|
| 1 | + |
| 2 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 3 | +# not use this file except in compliance with the License. You may obtain |
| 4 | +# a copy of the License at |
| 5 | +# |
| 6 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | +# |
| 8 | +# Unless required by applicable law or agreed to in writing, software |
| 9 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 10 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 11 | +# License for the specific language governing permissions and limitations |
| 12 | +# under the License. |
| 13 | + |
| 14 | +import re |
| 15 | + |
| 16 | +from keystonemiddleware import auth_token |
| 17 | +from oslo_log import log |
| 18 | + |
| 19 | +from bigbang.common import exception |
| 20 | +from bigbang.common.i18n import _ |
| 21 | +from bigbang.common import utils |
| 22 | + |
| 23 | +LOG = log.getLogger(__name__) |
| 24 | + |
| 25 | + |
| 26 | +class AuthTokenMiddleware(auth_token.AuthProtocol): |
| 27 | + """A wrapper on Keystone auth_token middleware. |
| 28 | +
|
| 29 | + Does not perform verification of authentication tokens |
| 30 | + for public routes in the API. |
| 31 | +
|
| 32 | + """ |
| 33 | + def __init__(self, app, conf, public_api_routes=None): |
| 34 | + if public_api_routes is None: |
| 35 | + public_api_routes = [] |
| 36 | + route_pattern_tpl = '%s(\.json)?$' |
| 37 | + |
| 38 | + try: |
| 39 | + self.public_api_routes = [re.compile(route_pattern_tpl % route_tpl) |
| 40 | + for route_tpl in public_api_routes] |
| 41 | + except re.error as e: |
| 42 | + msg = _('Cannot compile public API routes: %s') % e |
| 43 | + |
| 44 | + LOG.error(msg) |
| 45 | + raise exception.ConfigInvalid(error_msg=msg) |
| 46 | + |
| 47 | + super(AuthTokenMiddleware, self).__init__(app, conf) |
| 48 | + |
| 49 | + def __call__(self, env, start_response): |
| 50 | + path = utils.safe_rstrip(env.get('PATH_INFO'), '/') |
| 51 | + |
| 52 | + # The information whether the API call is being performed against the |
| 53 | + # public API is required for some other components. Saving it to the |
| 54 | + # WSGI environment is reasonable thereby. |
| 55 | + env['is_public_api'] = any(map(lambda pattern: re.match(pattern, path), |
| 56 | + self.public_api_routes)) |
| 57 | + |
| 58 | + if env['is_public_api']: |
| 59 | + return self._app(env, start_response) |
| 60 | + |
| 61 | + return super(AuthTokenMiddleware, self).__call__(env, start_response) |
| 62 | + |
| 63 | + @classmethod |
| 64 | + def factory(cls, global_config, **local_conf): |
| 65 | + public_routes = local_conf.get('acl_public_routes', '') |
| 66 | + public_api_routes = [path.strip() for path in public_routes.split(',')] |
| 67 | + |
| 68 | + def _factory(app): |
| 69 | + return cls(app, global_config, public_api_routes=public_api_routes) |
| 70 | + return _factory |
0 commit comments