def get_auth_ref(self, session, **kwargs): headers = {'Accept': 'application/json'} url = self.auth_url.rstrip('/') + '/tokens' params = {'auth': self.get_auth_data(headers)} if self.tenant_id: params['auth']['tenantId'] = self.tenant_id elif self.tenant_name: params['auth']['tenantName'] = self.tenant_name if self.trust_id: params['auth']['trust_id'] = self.trust_id _logger.debug('Making authentication request to %s', url) resp = session.post(url, json=params, headers=headers, authenticated=False, log=False) try: resp_data = resp.json()['access'] except (KeyError, ValueError): raise exceptions.InvalidResponse(response=resp) return access.AccessInfoV2(**resp_data)
def get_auth_ref(self, session, **kwargs): headers = {'Accept': 'application/json'} body = {'auth': {'identity': {}}} ident = body['auth']['identity'] for method in self.auth_methods: name, auth_data = method.get_auth_data(session, self, headers) ident.setdefault('methods', []).append(name) ident[name] = auth_data if not ident: raise exceptions.AuthorizationFailure('Authentication method ' 'required (e.g. password)') mutual_exclusion = [ bool(self.domain_id or self.domain_name), bool(self.project_id or self.project_name), bool(self.trust_id) ] if sum(mutual_exclusion) > 1: raise exceptions.AuthorizationFailure('Authentication cannot be ' 'scoped to multiple ' 'targets. Pick one of: ' 'project, domain or trust') if self.domain_id: body['auth']['scope'] = {'domain': {'id': self.domain_id}} elif self.domain_name: body['auth']['scope'] = {'domain': {'name': self.domain_name}} elif self.project_id: body['auth']['scope'] = {'project': {'id': self.project_id}} elif self.project_name: scope = body['auth']['scope'] = {'project': {}} scope['project']['name'] = self.project_name if self.project_domain_id: scope['project']['domain'] = {'id': self.project_domain_id} elif self.project_domain_name: scope['project']['domain'] = {'name': self.project_domain_name} elif self.trust_id: body['auth']['scope'] = {'OS-TRUST:trust': {'id': self.trust_id}} resp = session.post(self.token_url, json=body, headers=headers, authenticated=False) try: resp_data = resp.json()['token'] except (KeyError, ValueError): raise exceptions.InvalidResponse(response=resp) return access.AccessInfoV3(resp.headers['X-Subject-Token'], **resp_data)
def _get_unscoped_token(self, session, *kwargs): """Retrieve unscoped token after authentcation with ADFS server. This is a multistep process:: * Prepare ADFS Request Securty Token - build a etree.XML object filling certain attributes with proper user credentials, created/expires dates (ticket is be valid for 120 seconds as currently we don't handle reusing ADFS issued security tokens) . Step handled by ``ADFSUnscopedToken._prepare_adfs_request()`` method. * Send ADFS Security token to the ADFS server. Step handled by ``ADFSUnscopedToken._get_adfs_security_token()`` method. * Receive and parse security token, extract actual SAML assertion and prepare a request addressed for the Service Provider endpoint. This also includes changing namespaces in the XML document. Step handled by ``ADFSUnscopedToken._prepare_sp_request()`` method. * Send prepared assertion to the Service Provider endpoint. Usually the server will respond with HTTP 301 code which should be ignored as the 'location' header doesn't contain protected area. The goal of this operation is fetching the session cookie which later allows for accessing protected URL endpoints. Step handed by ``ADFSUnscopedToken._send_assertion_to_service_provider()`` method. * Once the session cookie is issued, the protected endpoint can be accessed and an unscoped token can be retrieved. Step handled by ``ADFSUnscopedToken._access_service_provider()`` method. :param session : a session object to send out HTTP requests. :type session: keystoneclient.session.Session :returns: (Unscoped federated token, token JSON body) """ self._prepare_adfs_request() self._get_adfs_security_token(session) self._prepare_sp_request() self._send_assertion_to_service_provider(session) self._access_service_provider(session) try: return (self.authenticated_response.headers['X-Subject-Token'], self.authenticated_response.json()['token']) except (KeyError, ValueError): raise exceptions.InvalidResponse( response=self.authenticated_response)
def get_auth_ref(self, session, **kwargs): headers = {'Accept': 'application/json'} body = {'auth': {'identity': {}}} ident = body['auth']['identity'] rkwargs = {} for method in self.auth_methods: name, auth_data = method.get_auth_data(session, self, headers, request_kwargs=rkwargs) ident.setdefault('methods', []).append(name) ident[name] = auth_data if not ident: raise exceptions.AuthorizationFailure( _('Authentication method required (e.g. password)')) mutual_exclusion = [ bool(self.domain_id or self.domain_name), bool(self.project_id or self.project_name), bool(self.trust_id), bool(self.unscoped) ] if sum(mutual_exclusion) > 1: raise exceptions.AuthorizationFailure( _('Authentication cannot be scoped to multiple targets. Pick ' 'one of: project, domain, trust or unscoped')) if self.domain_id: body['auth']['scope'] = {'domain': {'id': self.domain_id}} elif self.domain_name: body['auth']['scope'] = {'domain': {'name': self.domain_name}} elif self.project_id: body['auth']['scope'] = {'project': {'id': self.project_id}} elif self.project_name: scope = body['auth']['scope'] = {'project': {}} scope['project']['name'] = self.project_name if self.project_domain_id: scope['project']['domain'] = {'id': self.project_domain_id} elif self.project_domain_name: scope['project']['domain'] = {'name': self.project_domain_name} elif self.trust_id: body['auth']['scope'] = {'OS-TRUST:trust': {'id': self.trust_id}} elif self.unscoped: body['auth']['scope'] = {'unscoped': {}} # NOTE(jamielennox): we add nocatalog here rather than in token_url # directly as some federation plugins require the base token_url token_url = self.token_url if not self.include_catalog: token_url += '?nocatalog' _logger.debug('Making authentication request to %s', token_url) resp = session.post(token_url, json=body, headers=headers, authenticated=False, log=False, **rkwargs) try: _logger.debug(json.dumps(resp.json())) resp_data = resp.json()['token'] except (KeyError, ValueError): raise exceptions.InvalidResponse(response=resp) return access.AccessInfoV3(resp.headers['X-Subject-Token'], **resp_data)
def _retrieve_data_from_keystone(redis_client, url, tenant, token, blacklist_ttl, max_cache_life): """Retrieve the authentication data from OpenStack Keystone :param redis_client: redis.Redis object connected to the redis cache :param url: Keystone Identity URL to authenticate against :param tenant: tenant id of user data to retrieve :param token: auth_token for the tenant_id :param blacklist_ttl: time in milliseconds for blacklisting failed tokens :param max_cache_life: time in seconds for the maximum time a cache entry should remain in the cache of valid data :returns: a keystoneclient.access.AccessInfo on success or None on error """ try: # Try to authenticate the user and get the user information using # only the data provided, no special administrative tokens required. # When using the alternative validation method, the service catalog # identity does not return a service catalog for valid tokens. if get_conf().alternate_validation is True: _url = url.rstrip('/') + '/tokens' validation_url = _url + '/{0}'.format(token) headers = { 'Accept': 'application/json', 'X-Auth-Token': token } resp = requests.get(validation_url, headers=headers) if resp.status_code >= 400: LOG.debug('Request returned failure status: {0}'.format( resp.status_code)) raise exceptions.from_response(resp, 'GET', _url) try: resp_data = resp.json()['access'] except (KeyError, ValueError): raise exceptions.InvalidResponse(response=resp) access_info = access.AccessInfoV2(**resp_data) else: keystone = keystonev2_client.Client(tenant_id=tenant, token=token, auth_url=url) access_info = keystone.get_raw_token_from_identity_service( auth_url=url, tenant_id=tenant, token=token) # cache the data so it is easier to access next time _send_data_to_cache(redis_client, url, access_info, max_cache_life) return access_info except (exceptions.AuthorizationFailure, exceptions.Unauthorized) as ex: # re-raise 413 here and later on respond with 503 if 'HTTP 413' in str(ex): raise exceptions.RequestEntityTooLarge( method='POST', url=url, http_status=413 ) # Provided data was invalid and authorization failed msg = 'Failed to authenticate against {0} - {1}'.format( url, str(ex) ) LOG.debug(msg) # Blacklist the token _blacklist_token(redis_client, token, blacklist_ttl) return None except exceptions.RequestEntityTooLarge: LOG.debug('Request entity too large error from authentication server.') raise except Exception as ex: # Provided data was invalid or something else went wrong msg = 'Failed to authenticate against {0} - {1}'.format( url, str(ex) ) LOG.debug(msg) return None