Pass X_IS_ADMIN_PROJECT header from auth_token
To do policy enforcement around admin projects we need for auth_token middleware to pass this information down to context objects. Closes-Bug: #1577996 Change-Id: Ic680e6eaa683926914cf4b2152ec3bb67c6601ff
This commit is contained in:
parent
627ec923b9
commit
0562670d4e
@ -118,6 +118,12 @@ HTTP_X_USER_DOMAIN_NAME, HTTP_X_SERVICE_USER_DOMAIN_NAME
|
||||
HTTP_X_ROLES, HTTP_X_SERVICE_ROLES
|
||||
Comma delimited list of case-sensitive role names.
|
||||
|
||||
HTTP_X_IS_ADMIN_PROJECT
|
||||
The string value 'True' or 'False' representing whether the user's token is
|
||||
scoped to the admin project. As historically there was no admin project
|
||||
this will default to True for tokens without this information to be
|
||||
backwards with existing policy files.
|
||||
|
||||
HTTP_X_SERVICE_CATALOG
|
||||
service catalog (optional, JSON string).
|
||||
|
||||
|
@ -54,6 +54,15 @@ def _v3_to_v2_catalog(catalog):
|
||||
return v2_services
|
||||
|
||||
|
||||
def _is_admin_project(auth_ref):
|
||||
"""Return an appropriate header value for X-Is-Admin-Project.
|
||||
|
||||
Headers must be strings so we can't simply pass a boolean value through so
|
||||
return a True or False string to signal the admin project.
|
||||
"""
|
||||
return 'True' if auth_ref.is_admin_project else 'False'
|
||||
|
||||
|
||||
# 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):
|
||||
@ -86,6 +95,8 @@ class _AuthTokenRequest(webob.Request):
|
||||
_USER_STATUS_HEADER = 'X-Identity-Status'
|
||||
_SERVICE_STATUS_HEADER = 'X-Service-Identity-Status'
|
||||
|
||||
_ADMIN_PROJECT_HEADER = 'X-Is-Admin-Project'
|
||||
|
||||
_SERVICE_CATALOG_HEADER = 'X-Service-Catalog'
|
||||
_TOKEN_AUTH = 'keystone.token_auth'
|
||||
_TOKEN_INFO = 'keystone.token_info'
|
||||
@ -155,6 +166,7 @@ class _AuthTokenRequest(webob.Request):
|
||||
doc info at start of __init__ file for details of headers to be defined
|
||||
"""
|
||||
self._set_auth_headers(auth_ref, self._USER_HEADER_PREFIX)
|
||||
self.headers[self._ADMIN_PROJECT_HEADER] = _is_admin_project(auth_ref)
|
||||
|
||||
for k, v in six.iteritems(self._DEPRECATED_HEADER_MAP):
|
||||
self.headers[k] = self.headers[v]
|
||||
@ -192,6 +204,7 @@ class _AuthTokenRequest(webob.Request):
|
||||
yield self._SERVICE_CATALOG_HEADER
|
||||
yield self._USER_STATUS_HEADER
|
||||
yield self._SERVICE_STATUS_HEADER
|
||||
yield self._ADMIN_PROJECT_HEADER
|
||||
|
||||
for header in self._DEPRECATED_HEADER_MAP:
|
||||
yield header
|
||||
|
@ -133,6 +133,14 @@ class _TokenData(object):
|
||||
"""
|
||||
return frozenset(self._stored_auth_ref.role_names or [])
|
||||
|
||||
@property
|
||||
def is_admin_project(self):
|
||||
"""Return true if the current project scope is the admin project.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return self._stored_auth_ref.is_admin_project
|
||||
|
||||
@property
|
||||
def _log_format(self):
|
||||
roles = ','.join(self.role_names)
|
||||
|
@ -56,6 +56,7 @@ EXPECTED_V2_DEFAULT_ENV_RESPONSE = {
|
||||
'HTTP_X_USER_ID': 'user_id1',
|
||||
'HTTP_X_USER_NAME': 'user_name1',
|
||||
'HTTP_X_ROLES': 'role1,role2',
|
||||
'HTTP_X_IS_ADMIN_PROJECT': 'True',
|
||||
'HTTP_X_USER': 'user_name1', # deprecated (diablo-compat)
|
||||
'HTTP_X_TENANT': 'tenant_name1', # deprecated (diablo-compat)
|
||||
'HTTP_X_ROLE': 'role1,role2', # deprecated (diablo-compat)
|
||||
@ -75,6 +76,7 @@ EXPECTED_V3_DEFAULT_ENV_ADDITIONS = {
|
||||
'HTTP_X_PROJECT_DOMAIN_NAME': 'domain_name1',
|
||||
'HTTP_X_USER_DOMAIN_ID': 'domain_id1',
|
||||
'HTTP_X_USER_DOMAIN_NAME': 'domain_name1',
|
||||
'HTTP_X_IS_ADMIN_PROJECT': 'True'
|
||||
}
|
||||
|
||||
EXPECTED_V3_DEFAULT_SERVICE_ENV_ADDITIONS = {
|
||||
@ -1848,6 +1850,13 @@ class v3AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest,
|
||||
new_data = self.middleware.fetch_token(token)
|
||||
self.assertEqual(data, new_data)
|
||||
|
||||
def test_not_is_admin_project(self):
|
||||
token = self.examples.v3_NOT_IS_ADMIN_PROJECT
|
||||
self.set_middleware(expected_env={'HTTP_X_IS_ADMIN_PROJECT': 'False'})
|
||||
req = self.assert_valid_request_200(token)
|
||||
self.assertIs(False,
|
||||
req.environ['keystone.token_auth'].user.is_admin_project)
|
||||
|
||||
|
||||
class DelayedAuthTests(BaseAuthTokenMiddlewareTest):
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import fixtures
|
||||
from keystoneauth1 import fixture
|
||||
@ -131,6 +132,7 @@ class Examples(fixtures.Fixture):
|
||||
self.UUID_SERVICE_TOKEN_BIND = '5e43439613d34a13a7e03b2762bd08ab'
|
||||
self.v3_UUID_SERVICE_TOKEN_DEFAULT = 'g431071bbc2f492748596c1b53cb229'
|
||||
self.v3_UUID_SERVICE_TOKEN_BIND = 'be705e4426d0449a89e35ae21c380a05'
|
||||
self.v3_NOT_IS_ADMIN_PROJECT = uuid.uuid4().hex
|
||||
|
||||
revoked_token = self.REVOKED_TOKEN
|
||||
if isinstance(revoked_token, six.text_type):
|
||||
@ -465,6 +467,21 @@ class Examples(fixtures.Fixture):
|
||||
svc.add_endpoint('public', self.SERVICE_URL)
|
||||
self.TOKEN_RESPONSES[self.v3_UUID_SERVICE_TOKEN_DEFAULT] = token
|
||||
|
||||
token = fixture.V3Token(user_id=USER_ID,
|
||||
user_name=USER_NAME,
|
||||
user_domain_id=DOMAIN_ID,
|
||||
user_domain_name=DOMAIN_NAME,
|
||||
project_id=PROJECT_ID,
|
||||
project_name=PROJECT_NAME,
|
||||
project_domain_id=DOMAIN_ID,
|
||||
project_domain_name=DOMAIN_NAME,
|
||||
is_admin_project=False)
|
||||
token.add_role(name=ROLE_NAME1)
|
||||
token.add_role(name=ROLE_NAME2)
|
||||
svc = token.add_service(self.SERVICE_TYPE)
|
||||
svc.add_endpoint('public', self.SERVICE_URL)
|
||||
self.TOKEN_RESPONSES[self.v3_NOT_IS_ADMIN_PROJECT] = token
|
||||
|
||||
# PKIZ tokens generally link to above tokens
|
||||
|
||||
self.TOKEN_RESPONSES[self.SIGNED_TOKEN_SCOPED_PKIZ_KEY] = (
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
prelude: >
|
||||
- Add the `X_IS_ADMIN_PROJECT` header.
|
||||
features:
|
||||
- Added the `X_IS_ADMIN_PROJECT` header to authenticated headers. This has
|
||||
the string value of 'True' or 'False' and can be used to enforce admin
|
||||
project policies.
|
Loading…
x
Reference in New Issue
Block a user