Browse Source

Add API changes for app cred access rules

bp whitelist-extension-for-app-creds

Change-Id: Ie022e379d03d0309ec320b6947b987758d87fe5d
changes/68/628168/28
Colleen Murphy 3 years ago
parent
commit
14c4b177ef
  1. 13
      keystone/api/users.py
  2. 25
      keystone/application_credential/schema.py
  3. 95
      keystone/tests/unit/test_v3_application_credential.py

13
keystone/api/users.py

@ -545,7 +545,8 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
# secret is only exposed after create, it is not stored
'secret',
'links',
'unrestricted'
'unrestricted',
'access_rules'
])
@staticmethod
@ -608,6 +609,16 @@ class UserAppCredListCreateResource(ks_flask.ResourceBase):
if app_cred_data.get('expires_at'):
app_cred_data['expires_at'] = utils.parse_expiration_date(
app_cred_data['expires_at'])
if app_cred_data.get('access_rules'):
for access_rule in app_cred_data['access_rules']:
# If user provides an access rule by ID, it will be looked up
# by ID. If user provides an access rule that is identical to
# an existing one, the ID generated here will be ignored and
# the pre-existing access rule will be used.
if 'id' not in access_rule:
# Generate directly, rather than using _assign_unique_id,
# so that there is no deep copy made
access_rule['id'] = uuid.uuid4().hex
app_cred_data = self._normalize_dict(app_cred_data)
app_cred_api = PROVIDERS.application_credential_api

25
keystone/application_credential/schema.py

@ -29,6 +29,28 @@ _role_properties = {
}
}
_access_rules_properties = {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'path': {
'type': 'string',
'minLength': 0,
'maxLength': 225,
'pattern': '^\/.*'
},
'method': {
'type': 'string',
'pattern': '^(POST|GET|HEAD|PATCH|PUT|DELETE)$'
},
'service': parameter_types.id_string,
'id': parameter_types.id_string,
},
'additionalProperties': False
}
}
_application_credential_properties = {
'name': parameter_types.name,
'description': validation.nullable(parameter_types.description),
@ -39,7 +61,8 @@ _application_credential_properties = {
'type': ['null', 'string']
},
'roles': _role_properties,
'unrestricted': parameter_types.boolean
'unrestricted': parameter_types.boolean,
'access_rules': _access_rules_properties
}
application_credential_create = {

95
keystone/tests/unit/test_v3_application_credential.py

@ -35,7 +35,8 @@ class ApplicationCredentialTestCase(test_v3.RestfulTestCase):
self.config_fixture.config(group='auth',
methods='password,application_credential')
def _app_cred_body(self, roles=None, name=None, expires=None, secret=None):
def _app_cred_body(self, roles=None, name=None, expires=None, secret=None,
access_rules=None):
name = name or uuid.uuid4().hex
description = 'Credential for backups'
app_cred_data = {
@ -48,6 +49,8 @@ class ApplicationCredentialTestCase(test_v3.RestfulTestCase):
app_cred_data['expires_at'] = expires
if secret:
app_cred_data['secret'] = secret
if access_rules is not None:
app_cred_data['access_rules'] = access_rules
return {'application_credential': app_cred_data}
def test_create_application_credential(self):
@ -187,6 +190,96 @@ class ApplicationCredentialTestCase(test_v3.RestfulTestCase):
expected_status_code=http_client.CREATED,
headers={'x-Auth-Token': token_data.headers['x-subject-token']})
def test_create_application_credential_with_access_rules(self):
roles = [{'id': self.role_id}]
access_rules = [
{
'path': '/v3/projects',
'method': 'POST',
'service': 'identity',
}
]
app_cred_body = self._app_cred_body(roles=roles,
access_rules=access_rules)
with self.test_client() as c:
token = self.get_scoped_token()
resp = c.post('/v3/users/%s/application_credentials' % self.user_id,
headers={'X-Auth-Token': token},
json=app_cred_body,
expected_status_code=http_client.CREATED)
resp_access_rules = resp.json['application_credential']['access_rules']
self.assertIn('id', resp_access_rules[0])
resp_access_rules[0].pop('id')
self.assertEqual(access_rules[0], resp_access_rules[0])
def test_create_application_credential_with_duplicate_access_rule(self):
roles = [{'id': self.role_id}]
access_rules = [
{
'path': '/v3/projects',
'method': 'POST',
'service': 'identity',
}
]
app_cred_body_1 = self._app_cred_body(roles=roles,
access_rules=access_rules)
with self.test_client() as c:
token = self.get_scoped_token()
resp = c.post('/v3/users/%s/application_credentials' % self.user_id,
headers={'X-Auth-Token': token},
json=app_cred_body_1,
expected_status_code=http_client.CREATED)
resp_access_rules = resp.json['application_credential']['access_rules']
self.assertIn('id', resp_access_rules[0])
access_rule_id = resp_access_rules[0].pop('id')
self.assertEqual(access_rules[0], resp_access_rules[0])
app_cred_body_2 = self._app_cred_body(roles=roles,
access_rules=access_rules)
with self.test_client() as c:
token = self.get_scoped_token()
resp = c.post('/v3/users/%s/application_credentials' % self.user_id,
headers={'X-Auth-Token': token},
json=app_cred_body_2,
expected_status_code=http_client.CREATED)
resp_access_rules = resp.json['application_credential']['access_rules']
self.assertEqual(access_rule_id, resp_access_rules[0]['id'])
def test_create_application_credential_with_access_rule_by_id(self):
roles = [{'id': self.role_id}]
access_rules = [
{
'path': '/v3/projects',
'method': 'POST',
'service': 'identity',
}
]
app_cred_body_1 = self._app_cred_body(roles=roles,
access_rules=access_rules)
with self.test_client() as c:
token = self.get_scoped_token()
resp = c.post('/v3/users/%s/application_credentials' % self.user_id,
headers={'X-Auth-Token': token},
json=app_cred_body_1,
expected_status_code=http_client.CREATED)
resp_access_rules = resp.json['application_credential']['access_rules']
access_rule_id = resp_access_rules
self.assertIn('id', resp_access_rules[0])
access_rule_id = resp_access_rules[0].pop('id')
self.assertEqual(access_rules[0], resp_access_rules[0])
access_rules = [{'id': access_rule_id}]
app_cred_body_2 = self._app_cred_body(roles=roles,
access_rules=access_rules)
with self.test_client() as c:
token = self.get_scoped_token()
resp = c.post('/v3/users/%s/application_credentials' % self.user_id,
headers={'X-Auth-Token': token},
json=app_cred_body_2,
expected_status_code=http_client.CREATED)
resp_access_rules = resp.json['application_credential']['access_rules']
self.assertEqual(access_rule_id, resp_access_rules[0]['id'])
def test_list_application_credentials(self):
with self.test_client() as c:
token = self.get_scoped_token()

Loading…
Cancel
Save