set is_admin
on tokens for admin project
Adds two new configuration value: admin_project_name admin_project_domain_name If both values are set, and tokens requested for projects (only, not domains) that match both will have an additional value in them; `is_admin_project=true` DocImpact -- Configuration changes need documentation APIImpact -- Adds optional return values in token validation calls SecurityImpact -- Should be helpful in making access control decisions Implements: blueprint is-admin-project Partial-Bug: #968696 Change-Id: Ic9cf9862739381a30130b4be87075f726736ff88
This commit is contained in:
parent
933e118eee
commit
e7023697a8
@ -386,6 +386,17 @@ FILE_OPTIONS = {
|
||||
group='assignment')],
|
||||
help='Maximum number of entities that will be returned '
|
||||
'in a resource collection.'),
|
||||
cfg.StrOpt('admin_project_domain_name',
|
||||
help='Name of the domain that contains the special '
|
||||
'project for performing administrative operations on '
|
||||
'remote services. Tokens scoped to this project will '
|
||||
'contain the key/value `is_admin_project=true`. Defaults '
|
||||
'to None.'),
|
||||
cfg.StrOpt('admin_project_name',
|
||||
help='Special project for performing administrative '
|
||||
'operations on remote services. Tokens scoped to '
|
||||
'this project will contain the key/value '
|
||||
'`is_admin_project=true`. Defaults to None.'),
|
||||
],
|
||||
'domain_config': [
|
||||
cfg.StrOpt('driver',
|
||||
|
@ -572,6 +572,7 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
|
||||
require_catalog = kwargs.pop('require_catalog', True)
|
||||
endpoint_filter = kwargs.pop('endpoint_filter', False)
|
||||
ep_filter_assoc = kwargs.pop('ep_filter_assoc', 0)
|
||||
is_admin_project = kwargs.pop('is_admin_project', False)
|
||||
token = self.assertValidTokenResponse(r, *args, **kwargs)
|
||||
|
||||
if require_catalog:
|
||||
@ -599,6 +600,11 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
|
||||
self.assertIn('id', role)
|
||||
self.assertIn('name', role)
|
||||
|
||||
if is_admin_project:
|
||||
self.assertIs(True, token['is_admin_project'])
|
||||
else:
|
||||
self.assertNotIn('is_admin_project', token)
|
||||
|
||||
return token
|
||||
|
||||
def assertValidProjectScopedTokenResponse(self, r, *args, **kwargs):
|
||||
|
@ -413,6 +413,76 @@ class TokenAPITests(object):
|
||||
headers={'X-Subject-Token': v3_token})
|
||||
self.assertValidProjectScopedTokenResponse(r, require_catalog=False)
|
||||
|
||||
def test_is_admin_token_by_ids(self):
|
||||
self.config_fixture.config(
|
||||
group='resource',
|
||||
admin_project_domain_name=self.domain['name'],
|
||||
admin_project_name=self.project['name'])
|
||||
r = self.v3_create_token(self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
project_id=self.project['id']))
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=True)
|
||||
v3_token = r.headers.get('X-Subject-Token')
|
||||
r = self.get('/auth/tokens', headers={'X-Subject-Token': v3_token})
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=True)
|
||||
|
||||
def test_is_admin_token_by_names(self):
|
||||
self.config_fixture.config(
|
||||
group='resource',
|
||||
admin_project_domain_name=self.domain['name'],
|
||||
admin_project_name=self.project['name'])
|
||||
r = self.v3_create_token(self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
project_domain_name=self.domain['name'],
|
||||
project_name=self.project['name']))
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=True)
|
||||
v3_token = r.headers.get('X-Subject-Token')
|
||||
r = self.get('/auth/tokens', headers={'X-Subject-Token': v3_token})
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=True)
|
||||
|
||||
def test_token_for_non_admin_project_is_not_admin(self):
|
||||
self.config_fixture.config(
|
||||
group='resource',
|
||||
admin_project_domain_name=self.domain['name'],
|
||||
admin_project_name=uuid.uuid4().hex)
|
||||
r = self.v3_create_token(self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
project_id=self.project['id']))
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=False)
|
||||
v3_token = r.headers.get('X-Subject-Token')
|
||||
r = self.get('/auth/tokens', headers={'X-Subject-Token': v3_token})
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=False)
|
||||
|
||||
def test_token_for_non_admin_domain_same_project_name_is_not_admin(self):
|
||||
self.config_fixture.config(
|
||||
group='resource',
|
||||
admin_project_domain_name=uuid.uuid4().hex,
|
||||
admin_project_name=self.project['name'])
|
||||
r = self.v3_create_token(self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
project_id=self.project['id']))
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=False)
|
||||
v3_token = r.headers.get('X-Subject-Token')
|
||||
r = self.get('/auth/tokens', headers={'X-Subject-Token': v3_token})
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=False)
|
||||
|
||||
def test_only_admin_project_set_acts_as_non_admin(self):
|
||||
self.config_fixture.config(
|
||||
group='resource',
|
||||
admin_project_name=self.project['name'])
|
||||
r = self.v3_create_token(self.build_authentication_request(
|
||||
user_id=self.user['id'],
|
||||
password=self.user['password'],
|
||||
project_id=self.project['id']))
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=False)
|
||||
v3_token = r.headers.get('X-Subject-Token')
|
||||
r = self.get('/auth/tokens', headers={'X-Subject-Token': v3_token})
|
||||
self.assertValidProjectScopedTokenResponse(r, is_admin_project=False)
|
||||
|
||||
|
||||
class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase):
|
||||
def config_overrides(self):
|
||||
|
@ -253,6 +253,16 @@ class V3TokenDataHelper(object):
|
||||
return filtered_project
|
||||
|
||||
def _populate_scope(self, token_data, domain_id, project_id):
|
||||
# TODO(ayoung): Support the ability for a project acting as a domain
|
||||
# to be the admin project once the rest of the code for domains
|
||||
# acting as projects is merged. Code will likely be:
|
||||
# (r.admin_project_name == None and project['is_domain'] == True
|
||||
# and project['name'] == r.admin_project_domain_name)
|
||||
def _is_admin_project(project):
|
||||
r = CONF.resource
|
||||
return (project['name'] == r.admin_project_name and
|
||||
project['domain']['name'] == r.admin_project_domain_name)
|
||||
|
||||
if 'domain' in token_data or 'project' in token_data:
|
||||
# scope already exist, no need to populate it again
|
||||
return
|
||||
@ -261,6 +271,8 @@ class V3TokenDataHelper(object):
|
||||
token_data['domain'] = self._get_filtered_domain(domain_id)
|
||||
if project_id:
|
||||
token_data['project'] = self._get_filtered_project(project_id)
|
||||
if _is_admin_project(token_data['project']):
|
||||
token_data['is_admin_project'] = True
|
||||
|
||||
def _get_roles_for_user(self, user_id, domain_id, project_id):
|
||||
roles = []
|
||||
|
14
releasenotes/notes/is-admin-24b34238c83b3a82.yaml
Normal file
14
releasenotes/notes/is-admin-24b34238c83b3a82.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
[`bug 96869 <https://bugs.launchpad.net/keystone/+bug/968696>`_]
|
||||
A pair of configuration options have been added to the ``[resource]``
|
||||
section to specify a special ``admin`` project:
|
||||
``admin_project_domain_name`` and ``admin_project_name``. If these are
|
||||
defined, any scoped token issued for that project will have an additional
|
||||
identifier ``is_admin_project`` added to the token. This identifier can then
|
||||
be checked by the policy rules in the policy files of the services when
|
||||
evaluating access control policy for an API. Keystone does not yet
|
||||
support the ability for a project acting as a domain to be the
|
||||
admin project. That will be added once the rest of the code for
|
||||
domains acting as projects is merged.
|
Loading…
Reference in New Issue
Block a user