From 245c91f2e3d499498e5f0edd30c23504cda9d111 Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Tue, 24 Apr 2018 22:10:37 +0000 Subject: [PATCH] Introduce new header for system-scoped tokens Keystonemiddleware attempts to parse user/service tokens and populate request headers for other services to consume. This information is important for services looking to build oslo.context objects from request environments. Change-Id: I0717c2a5207a647999b4f9bcdf11f728984f0812 Closes-Bug: 1766731 --- keystonemiddleware/auth_token/__init__.py | 5 +++++ keystonemiddleware/auth_token/_request.py | 9 +++++++++ .../unit/auth_token/test_auth_token_middleware.py | 15 +++++++++++++++ keystonemiddleware/tests/unit/client_fixtures.py | 12 ++++++++++++ .../notes/bug-1766731-3b29192cfeb77964.yaml | 7 +++++++ 5 files changed, 48 insertions(+) create mode 100644 releasenotes/notes/bug-1766731-3b29192cfeb77964.yaml diff --git a/keystonemiddleware/auth_token/__init__.py b/keystonemiddleware/auth_token/__init__.py index f0d22098..f4917bde 100644 --- a/keystonemiddleware/auth_token/__init__.py +++ b/keystonemiddleware/auth_token/__init__.py @@ -72,6 +72,11 @@ HTTP_X_IDENTITY_STATUS, HTTP_X_SERVICE_IDENTITY_STATUS presented. This allows the underlying service to determine if a denial should use ``401 Unauthenticated`` or ``403 Forbidden``. +HTTP_OPENSTACK_SYSTEM_SCOPE + A string relaying system information about the token's scope. This + attribute is only present if the token is system-scoped. The string ``all`` + means the token is scoped to the entire deployment system. + HTTP_X_DOMAIN_ID, HTTP_X_SERVICE_DOMAIN_ID Identity service managed unique identifier, string. Only present if this is a domain-scoped token. diff --git a/keystonemiddleware/auth_token/_request.py b/keystonemiddleware/auth_token/_request.py index 26037a2a..33df7a9f 100644 --- a/keystonemiddleware/auth_token/_request.py +++ b/keystonemiddleware/auth_token/_request.py @@ -62,6 +62,13 @@ def _is_admin_project(auth_ref): return 'True' if auth_ref.is_admin_project else 'False' +def _get_system_scope(auth_ref): + """Return the scope information of a system scoped token.""" + if auth_ref.system_scoped: + if auth_ref.system.get('all'): + return 'all' + + # NOTE(jamielennox): this should probably be moved into its own file, but at # the moment there's no real logic here so just keep it locally. class _AuthTokenResponse(webob.Response): @@ -95,6 +102,7 @@ class _AuthTokenRequest(webob.Request): _SERVICE_STATUS_HEADER = 'X-Service-Identity-Status' _ADMIN_PROJECT_HEADER = 'X-Is-Admin-Project' + _SYSTEM_SCOPE_HEADER = 'OpenStack-System-Scope' _SERVICE_CATALOG_HEADER = 'X-Service-Catalog' _TOKEN_AUTH = 'keystone.token_auth' @@ -154,6 +162,7 @@ class _AuthTokenRequest(webob.Request): def _set_auth_headers(self, auth_ref, prefix): names = ','.join(auth_ref.role_names) self.headers[self._ROLES_TEMPLATE % prefix] = names + self.headers[self._SYSTEM_SCOPE_HEADER] = _get_system_scope(auth_ref) for header_tmplt, attr in self._HEADER_TEMPLATE.items(): self.headers[header_tmplt % prefix] = getattr(auth_ref, attr) diff --git a/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py b/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py index 2c30f4ad..4d36be14 100644 --- a/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py +++ b/keystonemiddleware/tests/unit/auth_token/test_auth_token_middleware.py @@ -1871,6 +1871,21 @@ class v3AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, with_catalog=False) self.assertLastPath('/v3/auth/tokens') + def test_valid_system_scoped_token_request(self): + delta_expected_env = { + 'HTTP_OPENSTACK_SYSTEM_SCOPE': 'all', + 'HTTP_X_PROJECT_ID': None, + 'HTTP_X_PROJECT_NAME': None, + 'HTTP_X_PROJECT_DOMAIN_ID': None, + 'HTTP_X_PROJECT_DOMAIN_NAME': None, + 'HTTP_X_TENANT_ID': None, + 'HTTP_X_TENANT_NAME': None, + 'HTTP_X_TENANT': None + } + self.set_middleware(expected_env=delta_expected_env) + self.assert_valid_request_200(self.examples.v3_SYSTEM_SCOPED_TOKEN) + self.assertLastPath('/v3/auth/tokens') + def test_domain_scoped_uuid_request(self): # Modify items compared to default token for a domain scope delta_expected_env = { diff --git a/keystonemiddleware/tests/unit/client_fixtures.py b/keystonemiddleware/tests/unit/client_fixtures.py index fe199fca..9f5a9173 100644 --- a/keystonemiddleware/tests/unit/client_fixtures.py +++ b/keystonemiddleware/tests/unit/client_fixtures.py @@ -127,6 +127,7 @@ class Examples(fixtures.Fixture): self.v3_UUID_TOKEN_DOMAIN_SCOPED = 'e8a7b63aaa4449f38f0c5c05c3581792' self.v3_UUID_TOKEN_BIND = '2f61f73e1c854cbb9534c487f9bd63c2' self.v3_UUID_TOKEN_UNKNOWN_BIND = '7ed9781b62cd4880b8d8c6788ab1d1e2' + self.v3_SYSTEM_SCOPED_TOKEN = '9ca6e88364b6418a88ffc02e6a24afd8' self.UUID_SERVICE_TOKEN_DEFAULT = 'fe4c0710ec2f492748596c1b53ab124' self.UUID_SERVICE_TOKEN_BIND = '5e43439613d34a13a7e03b2762bd08ab' @@ -380,6 +381,17 @@ class Examples(fixtures.Fixture): user_domain_name=DOMAIN_NAME) self.TOKEN_RESPONSES[self.v3_UUID_TOKEN_UNSCOPED] = token + token = fixture.V3Token(user_id=USER_ID, + user_name=USER_NAME, + user_domain_id=DOMAIN_ID, + user_domain_name=DOMAIN_NAME) + token.system = {'all': True} + token.add_role(id=ROLE_NAME1, name=ROLE_NAME1) + token.add_role(id=ROLE_NAME2, name=ROLE_NAME2) + svc = token.add_service(self.SERVICE_TYPE) + svc.add_endpoint('public', self.SERVICE_URL) + self.TOKEN_RESPONSES[self.v3_SYSTEM_SCOPED_TOKEN] = token + token = fixture.V3Token(user_id=USER_ID, user_name=USER_NAME, user_domain_id=DOMAIN_ID, diff --git a/releasenotes/notes/bug-1766731-3b29192cfeb77964.yaml b/releasenotes/notes/bug-1766731-3b29192cfeb77964.yaml new file mode 100644 index 00000000..fe88b153 --- /dev/null +++ b/releasenotes/notes/bug-1766731-3b29192cfeb77964.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + [`bug 1766731 `_] + Keystonemiddleware now supports system scoped tokens. When a system-scoped + token is parsed by auth_token middleware, it will set the + ``OpenStack-System-Scope`` header accordingly.