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)  

tokenless_auth.py
Go to the documentation of this file.
1 # Copyright 2015 Hewlett-Packard
2 # All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15 
16 import hashlib
17 
18 from oslo_log import log
19 
20 from keystone.auth import core
21 from keystone.common import provider_api
22 import keystone.conf
23 from keystone import exception
24 from keystone.federation import constants as federation_constants
25 from keystone.federation import utils
26 from keystone.i18n import _
27 
28 
29 CONF = keystone.conf.CONF
30 LOG = log.getLogger(__name__)
31 
32 
34  def __init__(self, env):
35  """A init class for TokenlessAuthHelper.
36 
37  :param env: The HTTP request environment that should contain
38  client certificate attributes. These attributes should match
39  with what the mapping defines. Or a user cannot be mapped and
40  results un-authenticated. The following examples are for the
41  attributes that reference to the client certificate's Subject's
42  Common Name and Organization:
43  SSL_CLIENT_S_DN_CN, SSL_CLIENT_S_DN_O
44  :type env: dict
45  """
46  self.env = env
47 
48  def _build_scope_info(self):
49  """Build the token request scope based on the headers.
50 
51  :returns: scope data
52  :rtype: dict
53  """
54  project_id = self.env.get('HTTP_X_PROJECT_ID')
55  project_name = self.env.get('HTTP_X_PROJECT_NAME')
56  project_domain_id = self.env.get('HTTP_X_PROJECT_DOMAIN_ID')
57  project_domain_name = self.env.get('HTTP_X_PROJECT_DOMAIN_NAME')
58  domain_id = self.env.get('HTTP_X_DOMAIN_ID')
59  domain_name = self.env.get('HTTP_X_DOMAIN_NAME')
60 
61  scope = {}
62  if project_id:
63  scope['project'] = {'id': project_id}
64  elif project_name:
65  scope['project'] = {'name': project_name}
66  if project_domain_id:
67  scope['project']['domain'] = {'id': project_domain_id}
68  elif project_domain_name:
69  scope['project']['domain'] = {'name': project_domain_name}
70  else:
71  msg = _('Neither Project Domain ID nor Project Domain Name '
72  'was provided.')
73  raise exception.ValidationError(msg)
74  elif domain_id:
75  scope['domain'] = {'id': domain_id}
76  elif domain_name:
77  scope['domain'] = {'name': domain_name}
78  else:
80  attribute='project or domain',
81  target='scope')
82  return scope
83 
84  def get_scope(self):
85  auth = {}
86  # NOTE(chioleong): Auth methods here are insignificant because
87  # we only care about using auth.controllers.AuthInfo
88  # to validate the scope information. Therefore,
89  # we don't provide any identity.
90  auth['scope'] = self._build_scope_info()
91 
92  # NOTE(chioleong): We'll let AuthInfo validate the scope for us
93  auth_info = core.AuthInfo.create(auth, scope_only=True)
94  return auth_info.get_scope()
95 
96  def get_mapped_user(self, project_id=None, domain_id=None):
97  """Map client certificate to an existing user.
98 
99  If user is ephemeral, there is no validation on the user himself;
100  however it will be mapped to a corresponding group(s) and the scope
101  of this ephemeral user is the same as what is assigned to the group.
102 
103  :param project_id: Project scope of the mapped user.
104  :param domain_id: Domain scope of the mapped user.
105  :returns: A dictionary that contains the keys, such as
106  user_id, user_name, domain_id, domain_name
107  :rtype: dict
108  """
109  idp_id = self._build_idp_id()
110  LOG.debug('The IdP Id %s and protocol Id %s are used to look up '
111  'the mapping.', idp_id, CONF.tokenless_auth.protocol)
112 
113  mapped_properties, mapping_id = self.federation_api.evaluate(
114  idp_id, CONF.tokenless_auth.protocol, self.env)
115 
116  user = mapped_properties.get('user', {})
117  user_id = user.get('id')
118  user_name = user.get('name')
119  user_type = user.get('type')
120  if user.get('domain') is not None:
121  user_domain_id = user.get('domain').get('id')
122  user_domain_name = user.get('domain').get('name')
123  else:
124  user_domain_id = None
125  user_domain_name = None
126 
127  # if user is ephemeral type, we don't care if the user exists
128  # or not, but just care if the mapped group(s) is valid.
129  if user_type == utils.UserType.EPHEMERAL:
130  user_ref = {'type': utils.UserType.EPHEMERAL}
131  group_ids = mapped_properties['group_ids']
132  utils.validate_mapped_group_ids(group_ids,
133  mapping_id,
134  self.identity_api)
135  group_ids.extend(
136  utils.transform_to_group_ids(
137  mapped_properties['group_names'], mapping_id,
138  self.identity_api, self.resource_api))
139  roles = self.assignment_api.get_roles_for_groups(group_ids,
140  project_id,
141  domain_id)
142  if roles is not None:
143  role_names = [role['name'] for role in roles]
144  user_ref['roles'] = role_names
145  user_ref['group_ids'] = list(group_ids)
146  user_ref[federation_constants.IDENTITY_PROVIDER] = idp_id
147  user_ref[federation_constants.PROTOCOL] = (
148  CONF.tokenless_auth.protocol)
149  return user_ref
150 
151  if user_id:
152  user_ref = self.identity_api.get_user(user_id)
153  elif user_name and (user_domain_name or user_domain_id):
154  if user_domain_name:
155  user_domain = self.resource_api.get_domain_by_name(
156  user_domain_name)
157  self.resource_api.assert_domain_enabled(user_domain['id'],
158  user_domain)
159  user_domain_id = user_domain['id']
160  user_ref = self.identity_api.get_user_by_name(user_name,
161  user_domain_id)
162  else:
163  msg = _('User auth cannot be built due to missing either '
164  'user id, or user name with domain id, or user name '
165  'with domain name.')
166  raise exception.ValidationError(msg)
167  self.identity_api.assert_user_enabled(
168  user_id=user_ref['id'],
169  user=user_ref)
170  user_ref['type'] = utils.UserType.LOCAL
171  return user_ref
172 
173  def _build_idp_id(self):
174  """Build the IdP name from the given config option issuer_attribute.
175 
176  The default issuer attribute SSL_CLIENT_I_DN in the environment is
177  built with the following formula -
178 
179  base64_idp = sha1(env['SSL_CLIENT_I_DN'])
180 
181  :returns: base64_idp like the above example
182  :rtype: str
183  """
184  idp = self.env.get(CONF.tokenless_auth.issuer_attribute)
185  if idp is None:
187  issuer_attribute=CONF.tokenless_auth.issuer_attribute)
188 
189  hashed_idp = hashlib.sha256(idp.encode('utf-8'))
190  return hashed_idp.hexdigest()
keystone.common.tokenless_auth.TokenlessAuthHelper._build_scope_info
def _build_scope_info(self)
Definition: tokenless_auth.py:48
keystone.common.tokenless_auth.TokenlessAuthHelper._build_idp_id
def _build_idp_id(self)
Definition: tokenless_auth.py:173
keystone.common.tokenless_auth.TokenlessAuthHelper.env
env
Definition: tokenless_auth.py:46
keystone.common.tokenless_auth.TokenlessAuthHelper
Definition: tokenless_auth.py:33
keystone.auth
Definition: __init__.py:1
keystone.exception.ValidationError
Definition: exception.py:98
keystone.federation
Definition: __init__.py:1
keystone.common.tokenless_auth.TokenlessAuthHelper.__init__
def __init__(self, env)
Definition: tokenless_auth.py:34
keystone.common.tokenless_auth.TokenlessAuthHelper.get_scope
def get_scope(self)
Definition: tokenless_auth.py:84
keystone.conf
Definition: __init__.py:1
keystone.common.provider_api.ProviderAPIMixin
Definition: provider_api.py:104
keystone.i18n._
_
Definition: i18n.py:29
keystone.common
Definition: __init__.py:1
keystone.i18n
Definition: i18n.py:1
keystone.common.tokenless_auth.TokenlessAuthHelper.get_mapped_user
def get_mapped_user(self, project_id=None, domain_id=None)
Definition: tokenless_auth.py:96
keystone.exception.TokenlessAuthConfigError
Definition: exception.py:678