From eb4aaa97bd1e1c7e541a0ad109fb23dfee0f9c9d Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 1 May 2012 15:41:06 -0700 Subject: [PATCH] Split noauth context middleware into new class Use UnauthenticatedContextMiddleware in the case that you want to deploy without an auth service. ContextMiddleware is now solely for authenticated requests. * Rewrite ownership tests for adding/updating images through the v1 API * Fixes bug 992859 Change-Id: I608671aac8300c9195769542708708afda991e04 --- .gitignore | 1 + doc/source/authentication.rst | 19 +-- etc/glance-api-paste.ini | 6 +- etc/glance-registry-paste.ini | 6 +- glance/common/context.py | 96 +++++++------- glance/tests/functional/__init__.py | 21 ++- glance/tests/functional/test_bin_glance.py | 141 ++------------------- glance/tests/functional/v1/test_api.py | 112 ++++++++++++++++ glance/tests/stubs.py | 9 +- glance/tests/unit/test_config.py | 4 +- glance/tests/unit/v1/test_api.py | 15 +-- glance/tests/utils.py | 6 +- 12 files changed, 228 insertions(+), 208 deletions(-) diff --git a/.gitignore b/.gitignore index 739f9ca783..df95d81adf 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ AUTHORS build dist +*.egg glance.egg-info glance/vcsversion.py tests.sqlite diff --git a/doc/source/authentication.rst b/doc/source/authentication.rst index 78f28ac9b8..0af8f9f560 100644 --- a/doc/source/authentication.rst +++ b/doc/source/authentication.rst @@ -40,12 +40,13 @@ Configuring the Glance servers to use Keystone Keystone is integrated with Glance through the use of middleware. The default configuration files for both the Glance API and the Glance -Registry use a single piece of middleware called ``context``, which -generates a request context containing all the necesary authorization +Registry use a single piece of middleware called ``unauthenticated-context``, +which generates a request context containing blank authentication information. In order to configure Glance to use Keystone, the -``authtoken`` middleware must also be deployed (which may be found in the -Keystone distribution). The ``authtoken`` middleware performs the Keystone -token validation, which is the heart of Keystone authentication. +``authtoken`` and ``context`` middlewares must be deployed in place of the +``unauthenticated-context`` middleware. The ``authtoken`` middleware performs +the authentication token validation and retrieves actual user authentication +information. It can be found in the Keystone distribution. Configuring Glance API to use Keystone -------------------------------------- @@ -80,11 +81,11 @@ Finally, to actually enable using Keystone authentication, the application pipeline must be modified. By default, it looks like:: [pipeline:glance-api] - pipeline = versionnegotiation context apiv1app + pipeline = versionnegotiation unauthenticated-context apiv1app -(Your particular pipeline may vary depending on other options, such as -the image cache.) This must be changed by inserting ``authtoken`` -before ``context``:: +Your particular pipeline may vary depending on other options, such as +the image cache. This must be changed by replacing ``unauthenticated-context`` +with ``authtoken`` and ``context``:: [pipeline:glance-api] pipeline = versionnegotiation authtoken context apiv1app diff --git a/etc/glance-api-paste.ini b/etc/glance-api-paste.ini index 097b5af2f0..ac0c7fc692 100644 --- a/etc/glance-api-paste.ini +++ b/etc/glance-api-paste.ini @@ -1,6 +1,6 @@ # Default minimal pipeline [pipeline:glance-api] -pipeline = versionnegotiation context rootapp +pipeline = versionnegotiation unauthenticated-context rootapp # Use the following pipeline for keystone auth # i.e. in glance-api.conf: @@ -62,6 +62,10 @@ glance.filter_factory = glance.api.middleware.cache_manage:CacheManageFilter paste.filter_factory = glance.common.wsgi:filter_factory glance.filter_factory = glance.common.context:ContextMiddleware +[filter:unauthenticated-context] +paste.filter_factory = glance.common.wsgi:filter_factory +glance.filter_factory = glance.common.context:UnauthenticatedContextMiddleware + [filter:authtoken] paste.filter_factory = keystone.middleware.auth_token:filter_factory auth_host = 127.0.0.1 diff --git a/etc/glance-registry-paste.ini b/etc/glance-registry-paste.ini index 9b529b3860..9ec01c699d 100644 --- a/etc/glance-registry-paste.ini +++ b/etc/glance-registry-paste.ini @@ -1,6 +1,6 @@ # Default minimal pipeline [pipeline:glance-registry] -pipeline = context registryapp +pipeline = unauthenticated-context registryapp # Use the following pipeline for keystone auth # i.e. in glance-registry.conf: @@ -18,6 +18,10 @@ glance.app_factory = glance.registry.api.v1:API paste.filter_factory = glance.common.wsgi:filter_factory glance.filter_factory = glance.common.context:ContextMiddleware +[filter:unauthenticated-context] +paste.filter_factory = glance.common.wsgi:filter_factory +glance.filter_factory = glance.common.context:UnauthenticatedContextMiddleware + [filter:authtoken] paste.filter_factory = keystone.middleware.auth_token:filter_factory auth_host = 127.0.0.1 diff --git a/glance/common/context.py b/glance/common/context.py index 6baaa0b7e3..2c9c459119 100644 --- a/glance/common/context.py +++ b/glance/common/context.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +import webob.exc + from glance.common import exception from glance.common import wsgi from glance.openstack.common import cfg @@ -130,60 +132,60 @@ class ContextMiddleware(wsgi.Middleware): opts = [ cfg.BoolOpt('owner_is_tenant', default=True), cfg.StrOpt('admin_role', default='admin'), - ] + ] def __init__(self, app, conf, **local_conf): self.conf = conf self.conf.register_opts(self.opts) super(ContextMiddleware, self).__init__(app) - def make_context(self, *args, **kwargs): - """ - Create a context with the given arguments. - """ - kwargs.setdefault('owner_is_tenant', self.conf.owner_is_tenant) + def process_request(self, req): + """Convert authentication informtion into a request context - return RequestContext(*args, **kwargs) + Generate a RequestContext object from the available + authentication headers and store on the 'context' attribute + of the req object. + + :param req: wsgi request object that will be given the context object + :raises webob.exc.HTTPUnauthorized: when value of the X-Identity-Status + header is not 'Confirmed' + """ + if req.headers.get('X-Identity-Status') != 'Confirmed': + raise webob.exc.HTTPUnauthorized() + + #NOTE(bcwaldon): X-Roles is a csv string, but we need to parse + # it into a list to be useful + roles_header = req.headers.get('X-Roles', '') + roles = [r.strip() for r in roles_header.split(',')] + + #NOTE(bcwaldon): This header is deprecated in favor of X-Auth-Token + deprecated_token = req.headers.get('X-Storage-Token') + + kwargs = { + 'user': req.headers.get('X-User-Id'), + 'tenant': req.headers.get('X-Tenant-Id'), + 'roles': roles, + 'is_admin': self.conf.admin_role in roles, + 'auth_tok': req.headers.get('X-Auth-Token', deprecated_token), + 'owner_is_tenant': self.conf.owner_is_tenant, + } + + req.context = RequestContext(**kwargs) + + +class UnauthenticatedContextMiddleware(wsgi.Middleware): + + def __init__(self, app, conf, **local_conf): + self.conf = conf + super(UnauthenticatedContextMiddleware, self).__init__(app) def process_request(self, req): - """ - Extract any authentication information in the request and - construct an appropriate context from it. + """Create a context without an authorized user.""" + kwargs = { + 'user': None, + 'tenant': None, + 'roles': [], + 'is_admin': True, + } - A few scenarios exist: - - 1. If X-Auth-Token is passed in, then consult TENANT and ROLE headers - to determine permissions. - - 2. An X-Auth-Token was passed in, but the Identity-Status is not - confirmed. For now, just raising a NotAuthenticated exception. - - 3. X-Auth-Token is omitted. If we were using Keystone, then the - tokenauth middleware would have rejected the request, so we must be - using NoAuth. In that case, assume that is_admin=True. - """ - auth_tok = req.headers.get('X-Auth-Token', - req.headers.get('X-Storage-Token')) - if auth_tok: - if req.headers.get('X-Identity-Status') == 'Confirmed': - # 1. Auth-token is passed, check other headers - user = req.headers.get('X-User-Id') - tenant = req.headers.get('X-Tenant-Id') - roles = [r.strip() - for r in req.headers.get('X-Roles', '').split(',')] - is_admin = self.conf.admin_role in roles - else: - # 2. Indentity-Status not confirmed - # FIXME(sirp): not sure what the correct behavior in this case - # is; just raising NotAuthenticated for now - raise exception.NotAuthenticated() - else: - # 3. Auth-token is ommited, assume NoAuth - user = None - tenant = None - roles = [] - is_admin = True - - req.context = self.make_context( - auth_tok=auth_tok, user=user, tenant=tenant, roles=roles, - is_admin=is_admin) + req.context = RequestContext(**kwargs) diff --git a/glance/tests/functional/__init__.py b/glance/tests/functional/__init__.py index 2ef3c6c116..fb6b63104e 100644 --- a/glance/tests/functional/__init__.py +++ b/glance/tests/functional/__init__.py @@ -252,13 +252,18 @@ policy_default_rule = %(policy_default_rule)s flavor = %(deployment_flavor)s """ self.paste_conf_base = """[pipeline:glance-api] -pipeline = versionnegotiation context rootapp +pipeline = versionnegotiation unauthenticated-context rootapp [pipeline:glance-api-caching] -pipeline = versionnegotiation context cache rootapp +pipeline = versionnegotiation unauthenticated-context cache rootapp [pipeline:glance-api-cachemanagement] -pipeline = versionnegotiation context cache cache_manage rootapp +pipeline = + versionnegotiation + unauthenticated-context + cache + cache_manage + rootapp [pipeline:glance-api-fakeauth] pipeline = versionnegotiation fakeauth context rootapp @@ -297,6 +302,10 @@ glance.filter_factory = glance.api.middleware.cache_manage:CacheManageFilter paste.filter_factory = glance.common.wsgi:filter_factory glance.filter_factory = glance.common.context:ContextMiddleware +[filter:unauthenticated-context] +paste.filter_factory = glance.common.wsgi:filter_factory +glance.filter_factory = glance.common.context:UnauthenticatedContextMiddleware + [filter:fakeauth] paste.filter_factory = glance.common.wsgi:filter_factory glance.filter_factory = glance.tests.utils:FakeAuthMiddleware @@ -337,7 +346,7 @@ owner_is_tenant = %(owner_is_tenant)s flavor = %(deployment_flavor)s """ self.paste_conf_base = """[pipeline:glance-registry] -pipeline = context registryapp +pipeline = unauthenticated-context registryapp [pipeline:glance-registry-fakeauth] pipeline = fakeauth context registryapp @@ -350,6 +359,10 @@ glance.app_factory = glance.registry.api.v1:API paste.filter_factory = glance.common.wsgi:filter_factory glance.filter_factory = glance.common.context:ContextMiddleware +[filter:unauthenticated-context] +paste.filter_factory = glance.common.wsgi:filter_factory +glance.filter_factory = glance.common.context:UnauthenticatedContextMiddleware + [filter:fakeauth] paste.filter_factory = glance.common.wsgi:filter_factory glance.filter_factory = glance.tests.utils:FakeAuthMiddleware diff --git a/glance/tests/functional/test_bin_glance.py b/glance/tests/functional/test_bin_glance.py index 4a4b1e82de..e65b58c21d 100644 --- a/glance/tests/functional/test_bin_glance.py +++ b/glance/tests/functional/test_bin_glance.py @@ -31,36 +31,6 @@ from glance.tests.functional.store_utils import (setup_http, get_http_uri) -class TestBinGlanceAuth(functional.FunctionalTest): - """Functional tests for bin/glance with some amount of auth""" - - def assertIn(self, key, bag): - msg = 'Expected to find substring "%s" in "%s"' % (key, bag) - self.assertTrue(key in bag, msg) - - def assertNotIn(self, key, bag): - msg = 'Expected not to find substring "%s" in "%s"' % (key, bag) - self.assertFalse(key in bag, msg) - - def test_index_with_https_auth(self): - self.cleanup() - self.start_servers(**self.__dict__.copy()) - - api_port = self.api_port - cmd = ("bin/glance --port=%d -N https://this.url.doesnt.matter/ " - "-A aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa index") % api_port - exitcode, out, err = execute(cmd, raise_error=False) - - #NOTE(markwash): we should expect the command to fail because the - # testing glance api server is not configured to authenticate, and the - # token we provide is invalid. However, it should fail due to - # NotAuthenticated, rather than because of an SSL error. - - self.assertNotEqual(0, exitcode) - self.assertNotIn('SSL23_GET_SERVER_HELLO', out) - self.assertIn('NotAuthenticated: You are not authenticated.', out) - - class TestBinGlance(functional.FunctionalTest): """Functional tests for the bin/glance CLI tool""" @@ -78,6 +48,20 @@ class TestBinGlance(functional.FunctionalTest): msg = 'expected "%s" to start with "%s"' % (str, prefix) self.assertTrue(str.startswith(prefix), msg) + def _assertNotIn(self, key, bag): + msg = 'Expected not to find substring "%s" in "%s"' % (key, bag) + self.assertFalse(key in bag, msg) + + def test_index_with_https(self): + self.cleanup() + self.start_servers(**self.__dict__.copy()) + + cmd = ("bin/glance -N https://auth/ --port=%d index") % self.api_port + exitcode, out, err = execute(cmd, raise_error=False) + + self.assertNotEqual(0, exitcode) + self._assertNotIn('SSL23_GET_SERVER_HELLO', out) + def test_add_with_location_and_id(self): self.cleanup() self.start_servers(**self.__dict__.copy()) @@ -176,103 +160,6 @@ class TestBinGlance(functional.FunctionalTest): self.assertEqual('0', size, "Expected image to be 0 bytes in size, " "but got %s. " % size) - def _verify_owner(self, owner, image_id): - cmd = "bin/glance --port=%d show %s" % (self.api_port, image_id) - exitcode, out, err = execute(cmd) - self.assertEqual(0, exitcode) - - # verify expected owner as first class attribute - self.assertTrue(('Owner: %s' % owner) in out) - # ensure owner does not appear as a custom property - self.assertFalse("Property 'owner':" in out) - - def _create_by_admin(self, owner): - # ownership set by admin user (defaults as such due to no-auth) - cmd = minimal_add_command(self.api_port, - 'MyImage', - '--silent-upload owner=%s' % owner) - exitcode, out, err = execute(cmd) - - self.assertEqual(0, exitcode) - self.assertTrue(out.strip().startswith('Added new image with ID:')) - - return out.strip().replace('Added new image with ID: ', '') - - def test_add_with_owner_admin(self): - """Test setting ownership of new image by admin user""" - self.cleanup() - self.start_servers(**self.__dict__.copy()) - - image_id = self._create_by_admin('42') - - self._verify_owner('42', image_id) - - def test_add_with_owner_non_admin(self): - """Test setting ownership of new image by non-admin user""" - self.cleanup() - self.api_server.deployment_flavor = 'fakeauth' - self.registry_server.deployment_flavor = 'fakeauth' - self.start_servers(**self.__dict__.copy()) - - # ownership set by non-admin user (setup as such by fakeauth pipeline) - headers = {'X-Image-Meta-Name': 'MyImage', - 'X-Image-Meta-disk_format': 'raw', - 'X-Image-Meta-container_format': 'ovf', - 'X-Image-Meta-Is-Public': 'True', - 'X-Image-Meta-Owner': '42', - 'X-Auth-Token': 'Confirmed:pattieblack:froggy:demo', - } - - path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) - http = httplib2.Http() - response, content = http.request(path, 'POST', headers=headers) - self.assertEqual(response.status, 201) - data = json.loads(content) - image_id = data['image']['id'] - - self._verify_owner('froggy', image_id) - - def test_update_with_owner_admin(self): - """Test updating ownership of existing image by admin user""" - self.cleanup() - self.start_servers(**self.__dict__.copy()) - - image_id = self._create_by_admin('user1') - - self._verify_owner('user1', image_id) - - # ownership updated by admin user (defaults as such due to no-auth) - cmd = "bin/glance update %s owner=user2 -p %d" % (image_id, - self.api_port) - exitcode, out, err = execute(cmd, raise_error=False) - - self.assertEqual(0, exitcode) - self.assertTrue(out.strip().endswith('Updated image %s' % image_id)) - - self._verify_owner('user2', image_id) - - def test_update_with_owner_non_admin(self): - """Test updating ownership of existing image by non-admin user""" - self.cleanup() - self.api_server.deployment_flavor = 'fakeauth' - self.registry_server.deployment_flavor = 'fakeauth' - self.start_servers(**self.__dict__.copy()) - - image_id = self._create_by_admin('user1') - - # ownership update attempted by non-admin user - # (setup as such by fakeauth pipeline) - headers = {'X-Image-Meta-Owner': 'user2', - 'X-Auth-Token': 'Confirmed:pattieblack:froggy:demo', - } - - path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", - self.api_port, - image_id) - http = httplib2.Http() - response, content = http.request(path, 'PUT', headers=headers) - self.assertEqual(response.status, 403) - def test_add_no_name(self): self.cleanup() self.start_servers(**self.__dict__.copy()) diff --git a/glance/tests/functional/v1/test_api.py b/glance/tests/functional/v1/test_api.py index 14693f041e..fba7539f15 100644 --- a/glance/tests/functional/v1/test_api.py +++ b/glance/tests/functional/v1/test_api.py @@ -1241,3 +1241,115 @@ class TestApi(functional.FunctionalTest): @skip_if_disabled def _do_test_put_image_content_missing_disk_format(self): self._do_test_put_image_content_missing_format('disk_format') + + @skip_if_disabled + def test_ownership(self): + self.cleanup() + self.api_server.deployment_flavor = 'fakeauth' + self.registry_server.deployment_flavor = 'fakeauth' + self.start_servers(**self.__dict__.copy()) + + # Add an image with admin privileges and ensure the owner + # can be set to something other than what was used to authenticate + auth_headers = { + 'X-Auth-Token': 'user1:tenant1:admin', + } + + create_headers = { + 'X-Image-Meta-Name': 'MyImage', + 'X-Image-Meta-disk_format': 'raw', + 'X-Image-Meta-container_format': 'ovf', + 'X-Image-Meta-Is-Public': 'True', + 'X-Image-Meta-Owner': 'tenant2', + } + create_headers.update(auth_headers) + + path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) + http = httplib2.Http() + response, content = http.request(path, 'POST', headers=create_headers) + self.assertEqual(response.status, 201) + data = json.loads(content) + image_id = data['image']['id'] + + path = ("http://%s:%d/v1/images/%s" % + ("0.0.0.0", self.api_port, image_id)) + http = httplib2.Http() + response, content = http.request(path, 'HEAD', headers=auth_headers) + self.assertEqual(response.status, 200) + self.assertEqual('tenant2', response['x-image-meta-owner']) + + # Now add an image without admin privileges and ensure the owner + # cannot be set to something other than what was used to authenticate + auth_headers = { + 'X-Auth-Token': 'user1:tenant1:role1', + } + create_headers.update(auth_headers) + + path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port) + http = httplib2.Http() + response, content = http.request(path, 'POST', headers=create_headers) + self.assertEqual(response.status, 201) + data = json.loads(content) + image_id = data['image']['id'] + + # We have to be admin to see the owner + auth_headers = { + 'X-Auth-Token': 'user1:tenant1:admin', + } + create_headers.update(auth_headers) + + path = ("http://%s:%d/v1/images/%s" % + ("0.0.0.0", self.api_port, image_id)) + http = httplib2.Http() + response, content = http.request(path, 'HEAD', headers=auth_headers) + self.assertEqual(response.status, 200) + self.assertEqual('tenant1', response['x-image-meta-owner']) + + # Make sure the non-privileged user can't update their owner either + update_headers = { + 'X-Image-Meta-Name': 'MyImage2', + 'X-Image-Meta-Owner': 'tenant2', + 'X-Auth-Token': 'user1:tenant1:role1', + } + + path = ("http://%s:%d/v1/images/%s" % + ("0.0.0.0", self.api_port, image_id)) + http = httplib2.Http() + response, content = http.request(path, 'PUT', headers=update_headers) + self.assertEqual(response.status, 200) + + # We have to be admin to see the owner + auth_headers = { + 'X-Auth-Token': 'user1:tenant1:admin', + } + + path = ("http://%s:%d/v1/images/%s" % + ("0.0.0.0", self.api_port, image_id)) + http = httplib2.Http() + response, content = http.request(path, 'HEAD', headers=auth_headers) + self.assertEqual(response.status, 200) + self.assertEqual('tenant1', response['x-image-meta-owner']) + + # An admin user should be able to update the owner + auth_headers = { + 'X-Auth-Token': 'user1:tenant3:admin', + } + + update_headers = { + 'X-Image-Meta-Name': 'MyImage2', + 'X-Image-Meta-Owner': 'tenant2', + } + update_headers.update(auth_headers) + + path = ("http://%s:%d/v1/images/%s" % + ("0.0.0.0", self.api_port, image_id)) + http = httplib2.Http() + response, content = http.request(path, 'PUT', headers=update_headers) + self.assertEqual(response.status, 200) + + path = ("http://%s:%d/v1/images/%s" % + ("0.0.0.0", self.api_port, image_id)) + http = httplib2.Http() + response, content = http.request(path, 'HEAD', headers=auth_headers) + self.assertEqual(response.status, 200) + self.assertEqual('tenant2', response['x-image-meta-owner']) diff --git a/glance/tests/stubs.py b/glance/tests/stubs.py index 9ae5fe93fd..03179e3ce3 100644 --- a/glance/tests/stubs.py +++ b/glance/tests/stubs.py @@ -72,7 +72,8 @@ def stub_out_registry_and_store_server(stubs, base_dir): 'verbose': VERBOSE, 'debug': DEBUG }) - api = context.ContextMiddleware(rserver.API(conf), conf) + api = context.UnauthenticatedContextMiddleware( + rserver.API(conf), conf) res = self.req.get_response(api) # httplib.Response has a read() method...fake it out @@ -160,7 +161,8 @@ def stub_out_registry_and_store_server(stubs, base_dir): 'filesystem_store_datadir': base_dir, 'policy_file': os.path.join(base_dir, 'policy.json'), }) - api = context.ContextMiddleware(router.API(conf), conf) + api = context.UnauthenticatedContextMiddleware( + router.API(conf), conf) res = self.req.get_response(api) # httplib.Response has a read() method...fake it out @@ -240,7 +242,8 @@ def stub_out_registry_server(stubs, **kwargs): 'verbose': VERBOSE, 'debug': DEBUG }) - api = context.ContextMiddleware(rserver.API(conf), conf) + api = context.UnauthenticatedContextMiddleware( + rserver.API(conf), conf) res = self.req.get_response(api) # httplib.Response has a read() method...fake it out diff --git a/glance/tests/unit/test_config.py b/glance/tests/unit/test_config.py index 73f00f92ce..c2e862fd5d 100644 --- a/glance/tests/unit/test_config.py +++ b/glance/tests/unit/test_config.py @@ -67,7 +67,7 @@ class TestPasteApp(unittest.TestCase): os.rmdir(os.path.dirname(conf.temp_file)) def test_load_paste_app(self): - expected_middleware = context.ContextMiddleware + expected_middleware = context.UnauthenticatedContextMiddleware self._do_test_load_paste_app(expected_middleware) def test_load_paste_app_with_paste_flavor(self): @@ -83,7 +83,7 @@ class TestPasteApp(unittest.TestCase): 'etc/glance-registry-paste.ini') paste_group = {'paste_deploy': {'config_file': paste_config_file}} - expected_middleware = context.ContextMiddleware + expected_middleware = context.UnauthenticatedContextMiddleware self._do_test_load_paste_app(expected_middleware, paste_group, paste_copy=False) diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py index f453c0ea89..ef51fed659 100644 --- a/glance/tests/unit/v1/test_api.py +++ b/glance/tests/unit/v1/test_api.py @@ -93,7 +93,8 @@ class TestRegistryAPI(base.IsolatedUnitTest): def setUp(self): """Establish a clean test environment""" super(TestRegistryAPI, self).setUp() - self.api = context.ContextMiddleware(rserver.API(self.conf), self.conf) + self.api = context.UnauthenticatedContextMiddleware( + rserver.API(self.conf), self.conf) self.FIXTURES = [ {'id': UUID1, 'name': 'fake image #1', @@ -1867,15 +1868,6 @@ class TestRegistryAPI(base.IsolatedUnitTest): self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code) - def test_delete_image_public_not_owned(self): - req = webob.Request.blank('/images/%s' % UUID2) - req.method = 'DELETE' - req.headers['x-auth-token'] = 'toke' - req.headers['x-identity-status'] = 'Confirmed' - - res = req.get_response(self.api) - self.assertEquals(res.status_int, 403) - def test_get_image_members(self): """ Tests members listing for existing images @@ -1955,7 +1947,8 @@ class TestGlanceAPI(base.IsolatedUnitTest): def setUp(self): """Establish a clean test environment""" super(TestGlanceAPI, self).setUp() - self.api = context.ContextMiddleware(router.API(self.conf), self.conf) + self.api = context.UnauthenticatedContextMiddleware( + router.API(self.conf), self.conf) self.FIXTURES = [ {'id': UUID1, 'name': 'fake image #1', diff --git a/glance/tests/utils.py b/glance/tests/utils.py index 90f9c3fc3b..7db686cfc4 100644 --- a/glance/tests/utils.py +++ b/glance/tests/utils.py @@ -384,8 +384,8 @@ class FakeAuthMiddleware(wsgi.Middleware): def process_request(self, req): auth_tok = req.headers.get('X-Auth-Token') if auth_tok: - status, user, tenant, role = auth_tok.split(':') - req.headers['X-Identity-Status'] = status + user, tenant, role = auth_tok.split(':') req.headers['X-User-Id'] = user req.headers['X-Tenant-Id'] = tenant - req.headers['X-Role'] = role + req.headers['X-Roles'] = role + req.headers['X-Identity-Status'] = 'Confirmed'