diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-03-28 00:49:30 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-03-28 00:49:30 +0000 |
commit | 2207dcca9014092a15f8e0377ea07c1df910097a (patch) | |
tree | 96a6f22e2b83e6945f8311af611f66f925af15ab | |
parent | aac9668a992c730eb7b0b21831d34214399c58f3 (diff) | |
parent | de3de047d1163775cebda55ef04603e0a93777b2 (diff) | |
download | ironic-2207dcca9014092a15f8e0377ea07c1df910097a.tar.gz |
Merge "Process public API list as regular expressions"
-rw-r--r-- | ironic/api/hooks.py | 5 | ||||
-rw-r--r-- | ironic/api/middleware/auth_token.py | 25 | ||||
-rw-r--r-- | ironic/common/exception.py | 4 | ||||
-rw-r--r-- | ironic/tests/api/test_acl.py | 13 |
4 files changed, 38 insertions, 9 deletions
diff --git a/ironic/api/hooks.py b/ironic/api/hooks.py index 29eec61cc..d706edf8d 100644 --- a/ironic/api/hooks.py +++ b/ironic/api/hooks.py @@ -21,7 +21,6 @@ from pecan import hooks from webob import exc from ironic.common import context -from ironic.common import utils from ironic.conductor import rpcapi from ironic.db import api as dbapi from ironic.openstack.common import policy @@ -75,11 +74,9 @@ class ContextHook(hooks.PecanHook): auth_token = state.request.headers.get('X-Auth-Token') creds = {'roles': state.request.headers.get('X-Roles', '').split(',')} + is_public_api = state.request.environ.get('is_public_api', False) is_admin = policy.check('admin', state.request.headers, creds) - path = utils.safe_rstrip(state.request.path, '/') - is_public_api = path in self.public_api_routes - state.request.context = context.RequestContext( auth_token=auth_token, user=user_id, diff --git a/ironic/api/middleware/auth_token.py b/ironic/api/middleware/auth_token.py index d9c32b111..9cad079b3 100644 --- a/ironic/api/middleware/auth_token.py +++ b/ironic/api/middleware/auth_token.py @@ -12,9 +12,15 @@ # License for the specific language governing permissions and limitations # under the License. +import re + from keystoneclient.middleware import auth_token +from ironic.common import exception from ironic.common import utils +from ironic.openstack.common import log + +LOG = log.getLogger(__name__) class AuthTokenMiddleware(auth_token.AuthProtocol): @@ -25,14 +31,29 @@ class AuthTokenMiddleware(auth_token.AuthProtocol): """ def __init__(self, app, conf, public_api_routes=[]): - self.public_api_routes = set(public_api_routes) + route_pattern_tpl = '%s(\.json|\.xml)?$' + + try: + self.public_api_routes = [re.compile(route_pattern_tpl % route_tpl) + for route_tpl in public_api_routes] + except re.error as e: + msg = _('Cannot compile public API routes: %s') % e + + LOG.error(msg) + raise exception.ConfigInvalid(error_msg=msg) super(AuthTokenMiddleware, self).__init__(app, conf) def __call__(self, env, start_response): path = utils.safe_rstrip(env.get('PATH_INFO'), '/') - if path in self.public_api_routes: + # The information whether the API call is being performed against the + # public API is required for some other components. Saving it to the + # WSGI environment is reasonable thereby. + env['is_public_api'] = any(map(lambda pattern: re.match(pattern, path), + self.public_api_routes)) + + if env['is_public_api']: return self.app(env, start_response) return super(AuthTokenMiddleware, self).__call__(env, start_response) diff --git a/ironic/common/exception.py b/ironic/common/exception.py index 220fde0b6..0af15ea42 100644 --- a/ironic/common/exception.py +++ b/ironic/common/exception.py @@ -353,3 +353,7 @@ class NoFreeConductorWorker(TemporaryFailure): class VendorPassthruException(IronicException): pass + + +class ConfigInvalid(IronicException): + message = _("Invalid configuration file. %(error_msg)s") diff --git a/ironic/tests/api/test_acl.py b/ironic/tests/api/test_acl.py index 57056fc4e..0dfb8a499 100644 --- a/ironic/tests/api/test_acl.py +++ b/ironic/tests/api/test_acl.py @@ -83,6 +83,13 @@ class TestACL(base.FunctionalTest): # expect_errors should be set to True: If expect_errors is set to False # the response gets converted to JSON and we cannot read the response # code so easy. - response = self.get_json('/', expect_errors=True) - - self.assertEqual(200, response.status_int) + for route in ('/', '/v1'): + response = self.get_json(route, + path_prefix='', expect_errors=True) + self.assertEqual(200, response.status_int) + + def test_public_api_with_path_extensions(self): + for route in ('/v1/', '/v1.json', '/v1.xml'): + response = self.get_json(route, + path_prefix='', expect_errors=True) + self.assertEqual(200, response.status_int) |