
If auth_type is set in the keystone_authtoken section, then one can use the the keystoneauth1 library to load the authentication plugin. This makes muranoclient fully workable, with Keystone v3 in case domain name is not 'Default'. Related-Bug: 1580611 Change-Id: I0d71032fb5296752ee25482b75993072884731e7
112 lines
4.1 KiB
Python
112 lines
4.1 KiB
Python
# Copyright (c) 2015 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import base64
|
|
|
|
from keystoneauth1 import exceptions
|
|
from keystoneauth1.identity import v3
|
|
from keystoneauth1 import session as ks_session
|
|
from oslo_config import cfg
|
|
from oslo_log import log
|
|
from webob import exc
|
|
|
|
from murano.common.i18n import _, _LW
|
|
from murano.common import wsgi
|
|
|
|
CONF = cfg.CONF
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
class ExternalContextMiddleware(wsgi.Middleware):
|
|
def get_keystone_token(self, user, password):
|
|
# TODO(starodubcevna): picking up project_name and auth_url from
|
|
# section related to Cloud Foundry service broker is probably a duct
|
|
# tape and should be rewritten as soon as we get more non-OpenStack
|
|
# services as murano recipients. The same is right for project and user
|
|
# domain names.
|
|
|
|
auth_url = CONF.cfapi.auth_url
|
|
if not (auth_url.endswith('v2.0') or auth_url.endswith('v3')):
|
|
auth_url += '/v3'
|
|
elif auth_url.endswith('v2.0'):
|
|
auth_url = auth_url.replace('v2.0', 'v3')
|
|
elif auth_url.endswith('v3'):
|
|
pass
|
|
else:
|
|
LOG.warning(_LW('Wrong format for service broker auth url'))
|
|
|
|
kwargs = {'auth_url': auth_url,
|
|
'username': user,
|
|
'password': password,
|
|
'project_name': CONF.cfapi.tenant,
|
|
'user_domain_name': CONF.cfapi.user_domain_name,
|
|
'project_domain_name': CONF.cfapi.project_domain_name}
|
|
password_auth = v3.Password(**kwargs)
|
|
session = ks_session.Session(auth=password_auth)
|
|
|
|
self._query_endpoints(password_auth, session)
|
|
|
|
return session.get_token()
|
|
|
|
def _query_endpoints(self, auth, session):
|
|
if not hasattr(self, '_murano_endpoint'):
|
|
try:
|
|
self._murano_endpoint = auth.get_endpoint(
|
|
session, 'application-catalog')
|
|
except exceptions.EndpointNotFound:
|
|
pass
|
|
if not hasattr(self, '_glare_endpoint'):
|
|
try:
|
|
self._glare_endpoint = auth.get_endpoint(
|
|
session, 'artifact')
|
|
except exceptions.EndpointNotFound:
|
|
pass
|
|
|
|
def get_endpoints(self):
|
|
return {
|
|
'murano': getattr(self, '_murano_endpoint', None),
|
|
'glare': getattr(self, '_glare_endpoint', None),
|
|
}
|
|
|
|
def process_request(self, req):
|
|
|
|
"""Get keystone token for external request
|
|
|
|
This middleware is used for external requests. It get credentials from
|
|
request and try to get keystone token for further authorization.
|
|
|
|
:param req: wsgi request object that will be given the context object
|
|
"""
|
|
try:
|
|
credentials = base64.b64decode(
|
|
req.headers['Authorization'].split(' ')[1])
|
|
user, password = credentials.split(':', 2)
|
|
req.headers['X-Auth-Token'] = self.get_keystone_token(user,
|
|
password)
|
|
req.endpoints = self.get_endpoints()
|
|
except KeyError:
|
|
msg = _("Authorization required")
|
|
LOG.warning(msg)
|
|
raise exc.HTTPUnauthorized(explanation=msg)
|
|
except exceptions.Unauthorized:
|
|
msg = _("Your credentials are wrong. Please try again")
|
|
LOG.warning(msg)
|
|
raise exc.HTTPUnauthorized(explanation=msg)
|
|
|
|
@classmethod
|
|
def factory(cls, global_conf, **local_conf):
|
|
def filter(app):
|
|
return cls(app)
|
|
return filter
|