keystone  18.0.0
About: OpenStack Keystone (Core Service: Identity) provides an authentication and authorization service for other OpenStack services. Provides a catalog of endpoints for all OpenStack services.
The "Victoria" series (maintained release).
  Fossies Dox: keystone-18.0.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

credentials.py
Go to the documentation of this file.
1 # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 # not use this file except in compliance with the License. You may obtain
3 # a copy of the License at
4 #
5 # http://www.apache.org/licenses/LICENSE-2.0
6 #
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 # License for the specific language governing permissions and limitations
11 # under the License.
12 
13 # This file handles all flask-restful resources for /v3/credentials
14 
15 import hashlib
16 
17 import flask
18 import http.client
19 from oslo_serialization import jsonutils
20 
21 from keystone.common import provider_api
22 from keystone.common import rbac_enforcer
23 from keystone.common import validation
24 import keystone.conf
25 from keystone.credential import schema
26 from keystone import exception
27 from keystone.i18n import _
28 from keystone.server import flask as ks_flask
29 
30 CONF = keystone.conf.CONF
31 PROVIDERS = provider_api.ProviderAPIs
32 ENFORCER = rbac_enforcer.RBACEnforcer
33 
34 
36  target = {}
37  try:
38  target['credential'] = PROVIDERS.credential_api.get_credential(
39  flask.request.view_args.get('credential_id')
40  )
41  except exception.NotFound: # nosec
42  # Defer existance in the event the credential doesn't exist, we'll
43  # check this later anyway.
44  pass
45 
46  return target
47 
48 
49 class CredentialResource(ks_flask.ResourceBase):
50  collection_key = 'credentials'
51  member_key = 'credential'
52 
53  @staticmethod
54  def _blob_to_json(ref):
55  # credentials stored via ec2tokens before the fix for #1259584
56  # need json_serailzing, as that's the documented API format
57  blob = ref.get('blob')
58  if isinstance(blob, dict):
59  ref = ref.copy()
60  ref['blob'] = jsonutils.dumps(blob)
61  return ref
62 
63  def _validate_blob_json(self, ref):
64  try:
65  blob = jsonutils.loads(ref.get('blob'))
66  except (ValueError, TabError):
68  message=_('Invalid blob in credential'))
69  if not blob or not isinstance(blob, dict):
70  raise exception.ValidationError(attribute='blob',
71  target='credential')
72  if blob.get('access') is None:
73  raise exception.ValidationError(attribute='access',
74  target='credential')
75  return blob
76 
78  self, ref, trust_id=None, app_cred_id=None, access_token_id=None):
79  # Generates an assigns a unique identifier to a credential reference.
80  if ref.get('type', '').lower() == 'ec2':
81  blob = self._validate_blob_json(ref)
82  ref = ref.copy()
83  ref['id'] = hashlib.sha256(
84  blob['access'].encode('utf8')).hexdigest()
85  # update the blob with the trust_id or app_cred_id, so credentials
86  # created with a trust- or app cred-scoped token will result in
87  # trust- or app cred-scoped tokens when authentication via
88  # ec2tokens happens
89  if trust_id is not None:
90  blob['trust_id'] = trust_id
91  ref['blob'] = jsonutils.dumps(blob)
92  if app_cred_id is not None:
93  blob['app_cred_id'] = app_cred_id
94  ref['blob'] = jsonutils.dumps(blob)
95  if access_token_id is not None:
96  blob['access_token_id'] = access_token_id
97  ref['blob'] = jsonutils.dumps(blob)
98  return ref
99  else:
100  return super(CredentialResource, self)._assign_unique_id(ref)
101 
102  def _list_credentials(self):
103  filters = ['user_id', 'type']
104  if not self.oslo_context.system_scope:
105  target = {'credential': {'user_id': self.oslo_context.user_id}}
106  else:
107  target = None
108  ENFORCER.enforce_call(action='identity:list_credentials',
109  filters=filters, target_attr=target)
110  hints = self.build_driver_hints(filters)
111  refs = PROVIDERS.credential_api.list_credentials(hints)
112  # If the request was filtered, make sure to return only the
113  # credentials specific to that user. This makes it so that users with
114  # roles on projects can't see credentials that aren't theirs.
115  filtered_refs = []
116  for ref in refs:
117  # Check each credential again to make sure the user has access to
118  # it, either by owning it, being a project admin with
119  # enforce_scope=false, being a system user, or having some other
120  # custom policy that allows access.
121  try:
122  cred = PROVIDERS.credential_api.get_credential(ref['id'])
123  ENFORCER.enforce_call(
124  action='identity:get_credential',
125  target_attr={'credential': cred}
126  )
127  filtered_refs.append(ref)
128  except exception.Forbidden:
129  pass
130  refs = filtered_refs
131  refs = [self._blob_to_json(r) for r in refs]
132  return self.wrap_collection(refs, hints=hints)
133 
134  def _get_credential(self, credential_id):
135  ENFORCER.enforce_call(
136  action='identity:get_credential',
137  build_target=_build_target_enforcement
138  )
139  credential = PROVIDERS.credential_api.get_credential(credential_id)
140  return self.wrap_member(self._blob_to_json(credential))
141 
142  def get(self, credential_id=None):
143  # Get Credential or List of credentials.
144  if credential_id is None:
145  # No Parameter passed means that we're doing a LIST action.
146  return self._list_credentials()
147  else:
148  return self._get_credential(credential_id)
149 
150  def post(self):
151  # Create a new credential
152  credential = self.request_body_json.get('credential', {})
153  target = {}
154  target['credential'] = credential
155  ENFORCER.enforce_call(
156  action='identity:create_credential', target_attr=target
157  )
158  validation.lazy_validate(schema.credential_create, credential)
159  trust_id = getattr(self.oslo_context, 'trust_id', None)
160  app_cred_id = getattr(
161  self.auth_context['token'], 'application_credential_id', None)
162  access_token_id = getattr(
163  self.auth_context['token'], 'access_token_id', None)
164  ref = self._assign_unique_id(
165  self._normalize_dict(credential),
166  trust_id=trust_id, app_cred_id=app_cred_id,
167  access_token_id=access_token_id)
168  ref = PROVIDERS.credential_api.create_credential(
169  ref['id'], ref, initiator=self.audit_initiator)
170  return self.wrap_member(ref), http.client.CREATED
171 
172  def _validate_blob_update_keys(self, credential, ref):
173  if credential.get('type', '').lower() == 'ec2':
174  new_blob = self._validate_blob_json(ref)
175  old_blob = credential.get('blob')
176  if isinstance(old_blob, str):
177  old_blob = jsonutils.loads(old_blob)
178  # if there was a scope set, prevent changing it or unsetting it
179  for key in ['trust_id', 'app_cred_id', 'access_token_id',
180  'access_id']:
181  if old_blob.get(key) != new_blob.get(key):
182  message = _('%s can not be updated for credential') % key
183  raise exception.ValidationError(message=message)
184 
185  def patch(self, credential_id):
186  # Update Credential
187  ENFORCER.enforce_call(
188  action='identity:update_credential',
189  build_target=_build_target_enforcement
190  )
191  current = PROVIDERS.credential_api.get_credential(credential_id)
192 
193  credential = self.request_body_json.get('credential', {})
194  validation.lazy_validate(schema.credential_update, credential)
195  self._validate_blob_update_keys(current.copy(), credential.copy())
196  self._require_matching_id(credential)
197  # Check that the user hasn't illegally modified the owner or scope
198  target = {'credential': dict(current, **credential)}
199  ENFORCER.enforce_call(
200  action='identity:update_credential', target_attr=target
201  )
202  ref = PROVIDERS.credential_api.update_credential(
203  credential_id, credential)
204  return self.wrap_member(ref)
205 
206  def delete(self, credential_id):
207  # Delete credentials
208  ENFORCER.enforce_call(
209  action='identity:delete_credential',
210  build_target=_build_target_enforcement
211  )
212 
213  return (PROVIDERS.credential_api.delete_credential(
214  credential_id, initiator=self.audit_initiator),
215  http.client.NO_CONTENT)
216 
217 
218 class CredentialAPI(ks_flask.APIBase):
219 
220  _name = 'credentials'
221  _import_name = __name__
222  resource_mapping = []
223  resources = [CredentialResource]
224 
225 
226 APIs = (CredentialAPI,)
keystone.api.credentials.CredentialResource.delete
def delete(self, credential_id)
Definition: credentials.py:206
keystone.api.credentials.CredentialResource._get_credential
def _get_credential(self, credential_id)
Definition: credentials.py:134
keystone.api.credentials.CredentialResource._blob_to_json
def _blob_to_json(ref)
Definition: credentials.py:54
keystone.exception.NotFound
Definition: exception.py:395
keystone.credential
Definition: __init__.py:1
keystone.exception.ValidationError
Definition: exception.py:98
keystone.api.credentials.CredentialResource._validate_blob_json
def _validate_blob_json(self, ref)
Definition: credentials.py:63
keystone.api.credentials.CredentialResource
Definition: credentials.py:49
keystone.api.credentials.CredentialResource._list_credentials
def _list_credentials(self)
Definition: credentials.py:102
keystone.api.credentials._build_target_enforcement
def _build_target_enforcement()
Definition: credentials.py:35
keystone.api.credentials.CredentialResource._assign_unique_id
def _assign_unique_id(self, ref, trust_id=None, app_cred_id=None, access_token_id=None)
Definition: credentials.py:78
keystone.api.credentials.CredentialResource._validate_blob_update_keys
def _validate_blob_update_keys(self, credential, ref)
Definition: credentials.py:172
keystone.server
Definition: __init__.py:1
keystone.exception.Forbidden
Definition: exception.py:352
keystone.conf
Definition: __init__.py:1
keystone.i18n._
_
Definition: i18n.py:29
keystone.api.credentials.CredentialResource.get
def get(self, credential_id=None)
Definition: credentials.py:142
keystone.common
Definition: __init__.py:1
keystone.i18n
Definition: i18n.py:1
keystone.api.credentials.CredentialResource.patch
def patch(self, credential_id)
Definition: credentials.py:185
keystone.api.credentials.CredentialAPI
Definition: credentials.py:218
keystone.api.credentials.CredentialResource.post
def post(self)
Definition: credentials.py:150