Add the service token details to context
In the case of communications that include service tokens we need to add that information to the context so that we can also enforce policy on it. Add this information and load this information in the from_environ method. Add these details to to_policy_values so that we can start to enforce policy based on these attributes. Change-Id: Id90f32795905112de804a18ddc8a69c038c829bb
This commit is contained in:
parent
c4621f04ff
commit
2eafb0eb6b
|
@ -40,22 +40,34 @@ _request_store = threading.local()
|
|||
|
||||
# These arguments will be passed to a new context from the first available
|
||||
# header to support backwards compatibility.
|
||||
_ENVIRON_HEADERS = {'auth_token': ['HTTP_X_AUTH_TOKEN',
|
||||
'HTTP_X_STORAGE_TOKEN'],
|
||||
'user': ['HTTP_X_USER_ID',
|
||||
'HTTP_X_USER'],
|
||||
'tenant': ['HTTP_X_PROJECT_ID',
|
||||
'HTTP_X_TENANT_ID',
|
||||
'HTTP_X_TENANT'],
|
||||
'user_domain': ['HTTP_X_USER_DOMAIN_ID'],
|
||||
'project_domain': ['HTTP_X_PROJECT_DOMAIN_ID'],
|
||||
'user_name': ['HTTP_X_USER_NAME'],
|
||||
'project_name': ['HTTP_X_PROJECT_NAME',
|
||||
'HTTP_X_TENANT_NAME'],
|
||||
'user_domain_name': ['HTTP_X_USER_DOMAIN_NAME'],
|
||||
'project_domain_name': ['HTTP_X_PROJECT_DOMAIN_NAME'],
|
||||
'request_id': ['openstack.request_id'],
|
||||
}
|
||||
_ENVIRON_HEADERS = {
|
||||
'auth_token': ['HTTP_X_AUTH_TOKEN',
|
||||
'HTTP_X_STORAGE_TOKEN'],
|
||||
'user': ['HTTP_X_USER_ID',
|
||||
'HTTP_X_USER'],
|
||||
'tenant': ['HTTP_X_PROJECT_ID',
|
||||
'HTTP_X_TENANT_ID',
|
||||
'HTTP_X_TENANT'],
|
||||
'user_domain': ['HTTP_X_USER_DOMAIN_ID'],
|
||||
'project_domain': ['HTTP_X_PROJECT_DOMAIN_ID'],
|
||||
'user_name': ['HTTP_X_USER_NAME'],
|
||||
'project_name': ['HTTP_X_PROJECT_NAME',
|
||||
'HTTP_X_TENANT_NAME'],
|
||||
'user_domain_name': ['HTTP_X_USER_DOMAIN_NAME'],
|
||||
'project_domain_name': ['HTTP_X_PROJECT_DOMAIN_NAME'],
|
||||
'request_id': ['openstack.request_id'],
|
||||
|
||||
|
||||
'service_token': ['HTTP_X_SERVICE_TOKEN'],
|
||||
'service_user_id': ['HTTP_X_SERVICE_USER_ID'],
|
||||
'service_user_name': ['HTTP_X_SERVICE_USER_NAME'],
|
||||
'service_user_domain_id': ['HTTP_X_SERVICE_USER_DOMAIN_ID'],
|
||||
'service_user_domain_name': ['HTTP_X_SERVICE_USER_DOMAIN_NAME'],
|
||||
'service_project_id': ['HTTP_X_SERVICE_PROJECT_ID'],
|
||||
'service_project_name': ['HTTP_X_SERVICE_PROJECT_NAME'],
|
||||
'service_project_domain_id': ['HTTP_X_SERVICE_PROJECT_DOMAIN_ID'],
|
||||
'service_project_domain_name': ['HTTP_X_SERVICE_PROJECT_DOMAIN_NAME'],
|
||||
}
|
||||
|
||||
|
||||
def generate_request_id():
|
||||
|
@ -181,7 +193,17 @@ class RequestContext(object):
|
|||
domain_name=None,
|
||||
user_domain_name=None,
|
||||
project_domain_name=None,
|
||||
is_admin_project=True):
|
||||
is_admin_project=True,
|
||||
service_token=None,
|
||||
service_user_id=None,
|
||||
service_user_name=None,
|
||||
service_user_domain_id=None,
|
||||
service_user_domain_name=None,
|
||||
service_project_id=None,
|
||||
service_project_name=None,
|
||||
service_project_domain_id=None,
|
||||
service_project_domain_name=None,
|
||||
service_roles=None):
|
||||
"""Initialize the RequestContext
|
||||
|
||||
:param overwrite: Set to False to ensure that the greenthread local
|
||||
|
@ -210,6 +232,18 @@ class RequestContext(object):
|
|||
self.show_deleted = show_deleted
|
||||
self.resource_uuid = resource_uuid
|
||||
self.roles = roles or []
|
||||
|
||||
self.service_token = service_token
|
||||
self.service_user_id = service_user_id
|
||||
self.service_user_name = service_user_name
|
||||
self.service_user_domain_id = service_user_domain_id
|
||||
self.service_user_domain_name = service_user_domain_name
|
||||
self.service_project_id = service_project_id
|
||||
self.service_project_name = service_project_name
|
||||
self.service_project_domain_id = service_project_domain_id
|
||||
self.service_project_domain_name = service_project_domain_name
|
||||
self.service_roles = service_roles or []
|
||||
|
||||
if not request_id:
|
||||
request_id = generate_request_id()
|
||||
self.request_id = request_id
|
||||
|
@ -261,7 +295,12 @@ class RequestContext(object):
|
|||
'project_id': self.project_id,
|
||||
'project_domain_id': self.project_domain_id,
|
||||
'roles': self.roles,
|
||||
'is_admin_project': self.is_admin_project})
|
||||
'is_admin_project': self.is_admin_project,
|
||||
'service_user_id': self.service_user_id,
|
||||
'service_user_domain_id': self.service_user_domain_id,
|
||||
'service_project_id': self.service_project_id,
|
||||
'service_project_domain_id': self.service_project_domain_id,
|
||||
'service_roles': self.service_roles})
|
||||
|
||||
def to_dict(self):
|
||||
"""Return a dictionary of context attributes."""
|
||||
|
@ -351,6 +390,11 @@ class RequestContext(object):
|
|||
roles = [r.strip() for r in roles.split(',')] if roles else []
|
||||
kwargs['roles'] = roles
|
||||
|
||||
if 'service_roles' not in kwargs:
|
||||
roles = environ.get('HTTP_X_SERVICE_ROLES')
|
||||
roles = [r.strip() for r in roles.split(',')] if roles else []
|
||||
kwargs['service_roles'] = roles
|
||||
|
||||
if 'is_admin_project' not in kwargs:
|
||||
# NOTE(jamielennox): we default is_admin_project to true because if
|
||||
# nothing is provided we have to assume it is the admin project to
|
||||
|
|
|
@ -200,18 +200,40 @@ class ContextTest(test_base.BaseTestCase):
|
|||
project_domain_id = generate_id(project_domain_name)
|
||||
roles = [uuid.uuid4().hex, uuid.uuid4().hex, uuid.uuid4().hex]
|
||||
request_id = uuid.uuid4().hex
|
||||
service_token = uuid.uuid4().hex
|
||||
service_user_id = uuid.uuid4().hex
|
||||
service_user_name = uuid.uuid4().hex
|
||||
service_user_domain_id = uuid.uuid4().hex
|
||||
service_user_domain_name = uuid.uuid4().hex
|
||||
service_project_id = uuid.uuid4().hex
|
||||
service_project_name = uuid.uuid4().hex
|
||||
service_project_domain_id = uuid.uuid4().hex
|
||||
service_project_domain_name = uuid.uuid4().hex
|
||||
service_roles = [uuid.uuid4().hex, uuid.uuid4().hex, uuid.uuid4().hex]
|
||||
|
||||
environ = {'HTTP_X_AUTH_TOKEN': auth_token,
|
||||
'HTTP_X_USER_ID': user_id,
|
||||
'HTTP_X_PROJECT_ID': project_id,
|
||||
'HTTP_X_USER_DOMAIN_ID': user_domain_id,
|
||||
'HTTP_X_PROJECT_DOMAIN_ID': project_domain_id,
|
||||
'HTTP_X_ROLES': ','.join(roles),
|
||||
'HTTP_X_USER_NAME': user_name,
|
||||
'HTTP_X_PROJECT_NAME': project_name,
|
||||
'HTTP_X_USER_DOMAIN_NAME': user_domain_name,
|
||||
'HTTP_X_PROJECT_DOMAIN_NAME': project_domain_name,
|
||||
'openstack.request_id': request_id}
|
||||
environ = {
|
||||
'HTTP_X_AUTH_TOKEN': auth_token,
|
||||
'HTTP_X_USER_ID': user_id,
|
||||
'HTTP_X_PROJECT_ID': project_id,
|
||||
'HTTP_X_USER_DOMAIN_ID': user_domain_id,
|
||||
'HTTP_X_PROJECT_DOMAIN_ID': project_domain_id,
|
||||
'HTTP_X_ROLES': ','.join(roles),
|
||||
'HTTP_X_USER_NAME': user_name,
|
||||
'HTTP_X_PROJECT_NAME': project_name,
|
||||
'HTTP_X_USER_DOMAIN_NAME': user_domain_name,
|
||||
'HTTP_X_PROJECT_DOMAIN_NAME': project_domain_name,
|
||||
'HTTP_X_SERVICE_TOKEN': service_token,
|
||||
'HTTP_X_SERVICE_USER_ID': service_user_id,
|
||||
'HTTP_X_SERVICE_USER_NAME': service_user_name,
|
||||
'HTTP_X_SERVICE_USER_DOMAIN_ID': service_user_domain_id,
|
||||
'HTTP_X_SERVICE_USER_DOMAIN_NAME': service_user_domain_name,
|
||||
'HTTP_X_SERVICE_PROJECT_ID': service_project_id,
|
||||
'HTTP_X_SERVICE_PROJECT_NAME': service_project_name,
|
||||
'HTTP_X_SERVICE_PROJECT_DOMAIN_ID': service_project_domain_id,
|
||||
'HTTP_X_SERVICE_PROJECT_DOMAIN_NAME': service_project_domain_name,
|
||||
'HTTP_X_SERVICE_ROLES': ','.join(service_roles),
|
||||
'openstack.request_id': request_id,
|
||||
}
|
||||
|
||||
ctx = context.RequestContext.from_environ(environ)
|
||||
|
||||
|
@ -226,6 +248,19 @@ class ContextTest(test_base.BaseTestCase):
|
|||
self.assertEqual(project_domain_name, ctx.project_domain_name)
|
||||
self.assertEqual(roles, ctx.roles)
|
||||
self.assertEqual(request_id, ctx.request_id)
|
||||
self.assertEqual(service_token, ctx.service_token)
|
||||
self.assertEqual(service_user_id, ctx.service_user_id)
|
||||
self.assertEqual(service_user_name, ctx.service_user_name)
|
||||
self.assertEqual(service_user_domain_id, ctx.service_user_domain_id)
|
||||
self.assertEqual(service_user_domain_name,
|
||||
ctx.service_user_domain_name)
|
||||
self.assertEqual(service_project_id, ctx.service_project_id)
|
||||
self.assertEqual(service_project_name, ctx.service_project_name)
|
||||
self.assertEqual(service_project_domain_id,
|
||||
ctx.service_project_domain_id)
|
||||
self.assertEqual(service_project_domain_name,
|
||||
ctx.service_project_domain_name)
|
||||
self.assertEqual(service_roles, ctx.service_roles)
|
||||
|
||||
def test_from_environ_no_roles(self):
|
||||
ctx = context.RequestContext.from_environ(environ={})
|
||||
|
@ -293,9 +328,11 @@ class ContextTest(test_base.BaseTestCase):
|
|||
self.assertEqual(new, ctx.project_name)
|
||||
|
||||
def test_from_environ_strip_roles(self):
|
||||
environ = {'HTTP_X_ROLES': ' abc\t,\ndef\n,ghi\n\n'}
|
||||
environ = {'HTTP_X_ROLES': ' abc\t,\ndef\n,ghi\n\n',
|
||||
'HTTP_X_SERVICE_ROLES': ' jkl\t,\nmno\n,pqr\n\n'}
|
||||
ctx = context.RequestContext.from_environ(environ=environ)
|
||||
self.assertEqual(['abc', 'def', 'ghi'], ctx.roles)
|
||||
self.assertEqual(['jkl', 'mno', 'pqr'], ctx.service_roles)
|
||||
|
||||
def test_environ_admin_project(self):
|
||||
environ = {}
|
||||
|
@ -461,20 +498,31 @@ class ContextTest(test_base.BaseTestCase):
|
|||
tenant = uuid.uuid4().hex
|
||||
project_domain = uuid.uuid4().hex
|
||||
roles = [uuid.uuid4().hex, uuid.uuid4().hex, uuid.uuid4().hex]
|
||||
service_user_id = uuid.uuid4().hex
|
||||
service_project_id = uuid.uuid4().hex
|
||||
service_roles = [uuid.uuid4().hex, uuid.uuid4().hex, uuid.uuid4().hex]
|
||||
|
||||
# default is_admin_project is True
|
||||
ctx = context.RequestContext(user=user,
|
||||
user_domain=user_domain,
|
||||
tenant=tenant,
|
||||
project_domain=project_domain,
|
||||
roles=roles)
|
||||
roles=roles,
|
||||
service_user_id=service_user_id,
|
||||
service_project_id=service_project_id,
|
||||
service_roles=service_roles)
|
||||
|
||||
self.assertEqual({'user_id': user,
|
||||
'user_domain_id': user_domain,
|
||||
'project_id': tenant,
|
||||
'project_domain_id': project_domain,
|
||||
'roles': roles,
|
||||
'is_admin_project': True},
|
||||
'is_admin_project': True,
|
||||
'service_user_id': service_user_id,
|
||||
'service_user_domain_id': None,
|
||||
'service_project_id': service_project_id,
|
||||
'service_project_domain_id': None,
|
||||
'service_roles': service_roles},
|
||||
ctx.to_policy_values())
|
||||
|
||||
ctx = context.RequestContext(user=user,
|
||||
|
@ -482,14 +530,22 @@ class ContextTest(test_base.BaseTestCase):
|
|||
tenant=tenant,
|
||||
project_domain=project_domain,
|
||||
roles=roles,
|
||||
is_admin_project=False)
|
||||
is_admin_project=False,
|
||||
service_user_id=service_user_id,
|
||||
service_project_id=service_project_id,
|
||||
service_roles=service_roles)
|
||||
|
||||
self.assertEqual({'user_id': user,
|
||||
'user_domain_id': user_domain,
|
||||
'project_id': tenant,
|
||||
'project_domain_id': project_domain,
|
||||
'roles': roles,
|
||||
'is_admin_project': False},
|
||||
'is_admin_project': False,
|
||||
'service_user_id': service_user_id,
|
||||
'service_user_domain_id': None,
|
||||
'service_project_id': service_project_id,
|
||||
'service_project_domain_id': None,
|
||||
'service_roles': service_roles},
|
||||
ctx.to_policy_values())
|
||||
|
||||
def test_positional_args(self):
|
||||
|
|
Loading…
Reference in New Issue