From b985627eaa9d926b7df29ec77b3a0c724fc9c498 Mon Sep 17 00:00:00 2001 From: Nikolay Starodubtsev Date: Tue, 3 Nov 2015 13:40:22 +0300 Subject: [PATCH] Add middleware for external requests New middleware will solve the problem with non-Openstack requests by adding some minimal required headers. Change-Id: I49986e73d0eb3da1ce13d22771c6bcb5a28ba846 Implements: bp external-request-middleware --- etc/murano/murano-paste.ini | 3 ++ murano/api/middleware/context.py | 2 +- murano/api/middleware/ext_context.py | 63 ++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 murano/api/middleware/ext_context.py diff --git a/etc/murano/murano-paste.ini b/etc/murano/murano-paste.ini index 2e8fca8f..514be5db 100644 --- a/etc/murano/murano-paste.ini +++ b/etc/murano/murano-paste.ini @@ -38,3 +38,6 @@ paste.filter_factory = oslo_middleware.request_id:RequestId.factory [filter:ssl] paste.filter_factory = murano.api.middleware.ssl:SSLMiddleware.factory + +[filter:ext_context] +paste.filter_factory = murano.api.middleware.ext_context:ExternalContextMiddleware.factory diff --git a/murano/api/middleware/context.py b/murano/api/middleware/context.py index ce3d3f6f..143f3c08 100644 --- a/murano/api/middleware/context.py +++ b/murano/api/middleware/context.py @@ -31,6 +31,7 @@ CONF = cfg.CONF class ContextMiddleware(wsgi.Middleware): def process_request(self, req): + """Convert authentication information into a request context Generate a murano.context.RequestContext object from the available @@ -39,7 +40,6 @@ class ContextMiddleware(wsgi.Middleware): :param req: wsgi request object that will be given the context object """ - roles = [r.strip() for r in req.headers.get('X-Roles').split(',')] kwargs = { 'user': req.headers.get('X-User-Id'), diff --git a/murano/api/middleware/ext_context.py b/murano/api/middleware/ext_context.py new file mode 100644 index 00000000..64378a14 --- /dev/null +++ b/murano/api/middleware/ext_context.py @@ -0,0 +1,63 @@ +# 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 keystoneclient import exceptions +from keystoneclient.v3 import client +from oslo_config import cfg +from oslo_log import log +from webob import exc + +from murano.common.i18n import _ +from murano.common import wsgi + +CONF = cfg.CONF +LOG = log.getLogger(__name__) + + +class ExternalContextMiddleware(wsgi.Middleware): + def get_keystone_token(self, user, password): + keystone = client.Client(username=user, + password=password, + auth_url=CONF.cfapi.auth_url.replace( + 'v2.0', 'v3')) + return keystone.auth_token + + 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 futher authorization. + + :param req: wsgi request object that will be given the context object + """ + + credentials = base64.b64decode( + req.headers['Authorization'].split(' ')[1]) + user, password = credentials.split(':', 2) + try: + req.headers['X-Auth-Token'] = self.get_keystone_token(user, + password) + 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