summaryrefslogtreecommitdiff
path: root/keystone/api/credentials.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone/api/credentials.py')
-rw-r--r--keystone/api/credentials.py76
1 files changed, 56 insertions, 20 deletions
diff --git a/keystone/api/credentials.py b/keystone/api/credentials.py
index 6985b92d1..4ff11ec7b 100644
--- a/keystone/api/credentials.py
+++ b/keystone/api/credentials.py
@@ -13,6 +13,7 @@
# This file handles all flask-restful resources for /v3/credentials
import hashlib
+import six
import flask
from oslo_serialization import jsonutils
@@ -60,30 +61,41 @@ class CredentialResource(ks_flask.ResourceBase):
ref['blob'] = jsonutils.dumps(blob)
return ref
- def _assign_unique_id(self, ref, trust_id=None):
+ def _validate_blob_json(self, ref):
+ try:
+ blob = jsonutils.loads(ref.get('blob'))
+ except (ValueError, TabError):
+ raise exception.ValidationError(
+ message=_('Invalid blob in credential'))
+ if not blob or not isinstance(blob, dict):
+ raise exception.ValidationError(attribute='blob',
+ target='credential')
+ if blob.get('access') is None:
+ raise exception.ValidationError(attribute='access',
+ target='credential')
+ return blob
+
+ def _assign_unique_id(
+ self, ref, trust_id=None, app_cred_id=None, access_token_id=None):
# Generates an assigns a unique identifier to a credential reference.
if ref.get('type', '').lower() == 'ec2':
- try:
- blob = jsonutils.loads(ref.get('blob'))
- except (ValueError, TabError):
- raise exception.ValidationError(
- message=_('Invalid blob in credential'))
- if not blob or not isinstance(blob, dict):
- raise exception.ValidationError(attribute='blob',
- target='credential')
- if blob.get('access') is None:
- raise exception.ValidationError(attribute='access',
- target='credential')
-
+ blob = self._validate_blob_json(ref)
ref = ref.copy()
ref['id'] = hashlib.sha256(
blob['access'].encode('utf8')).hexdigest()
- # update the blob with the trust_id, so credentials created with
- # a trust scoped token will result in trust scoped tokens when
- # authentication via ec2tokens happens
+ # update the blob with the trust_id or app_cred_id, so credentials
+ # created with a trust- or app cred-scoped token will result in
+ # trust- or app cred-scoped tokens when authentication via
+ # ec2tokens happens
if trust_id is not None:
blob['trust_id'] = trust_id
ref['blob'] = jsonutils.dumps(blob)
+ if app_cred_id is not None:
+ blob['app_cred_id'] = app_cred_id
+ ref['blob'] = jsonutils.dumps(blob)
+ if access_token_id is not None:
+ blob['access_token_id'] = access_token_id
+ ref['blob'] = jsonutils.dumps(blob)
return ref
else:
return super(CredentialResource, self)._assign_unique_id(ref)
@@ -146,23 +158,47 @@ class CredentialResource(ks_flask.ResourceBase):
)
validation.lazy_validate(schema.credential_create, credential)
trust_id = getattr(self.oslo_context, 'trust_id', None)
+ app_cred_id = getattr(
+ self.auth_context['token'], 'application_credential_id', None)
+ access_token_id = getattr(
+ self.auth_context['token'], 'access_token_id', None)
ref = self._assign_unique_id(
- self._normalize_dict(credential), trust_id=trust_id)
- ref = PROVIDERS.credential_api.create_credential(ref['id'], ref,
- initiator=self.audit_initiator)
+ self._normalize_dict(credential),
+ trust_id=trust_id, app_cred_id=app_cred_id,
+ access_token_id=access_token_id)
+ ref = PROVIDERS.credential_api.create_credential(
+ ref['id'], ref, initiator=self.audit_initiator)
return self.wrap_member(ref), http_client.CREATED
+ def _validate_blob_update_keys(self, credential, ref):
+ if credential.get('type', '').lower() == 'ec2':
+ new_blob = self._validate_blob_json(ref)
+ old_blob = credential.get('blob')
+ if isinstance(old_blob, six.string_types):
+ old_blob = jsonutils.loads(old_blob)
+ # if there was a scope set, prevent changing it or unsetting it
+ for key in ['trust_id', 'app_cred_id', 'access_token_id']:
+ if old_blob.get(key) != new_blob.get(key):
+ message = _('%s can not be updated for credential') % key
+ raise exception.ValidationError(message=message)
+
def patch(self, credential_id):
# Update Credential
ENFORCER.enforce_call(
action='identity:update_credential',
build_target=_build_target_enforcement
)
- PROVIDERS.credential_api.get_credential(credential_id)
+ current = PROVIDERS.credential_api.get_credential(credential_id)
credential = self.request_body_json.get('credential', {})
validation.lazy_validate(schema.credential_update, credential)
+ self._validate_blob_update_keys(current.copy(), credential.copy())
self._require_matching_id(credential)
+ # Check that the user hasn't illegally modified the owner or scope
+ target = {'credential': dict(current, **credential)}
+ ENFORCER.enforce_call(
+ action='identity:update_credential', target_attr=target
+ )
ref = PROVIDERS.credential_api.update_credential(
credential_id, credential)
return self.wrap_member(ref)