def _fetch_token(self, token): """Retrieve a token from either a PKI bundle or the identity server. :param str token: token id :raises exc.InvalidToken: if token is rejected """ data = None token_hashes = None try: token_hashes = self._token_hashes(token) self.log.debug('XXX JD Hashed token') cached = self._cache_get_hashes(token_hashes) self.log.debug('XXX JD Cache got token') if cached: self.log.debug('XXX JD Cached token!') data = cached if self._check_revocations_for_cached: # A token might have been revoked, regardless of initial # mechanism used to validate it, and needs to be checked. self.log.debug('XXX Checking revocation') self._revocations.check(token_hashes) else: self.log.debug('XXX Validating offline') data = self._validate_offline(token, token_hashes) if not data: self.log.debug('XXX Verify token on server') data = self._identity_server.verify_token(token) self.log.debug('XXX Storing in cache token') self._token_cache.store(token_hashes[0], data) self.log.debug('XXX Stored in cache token!') except (ksc_exceptions.ConnectionRefused, ksc_exceptions.RequestTimeout, ksm_exceptions.RevocationListError, ksm_exceptions.ServiceError) as e: self.log.critical(_LC('Unable to validate token: %s'), e) raise webob.exc.HTTPServiceUnavailable() except ksm_exceptions.InvalidToken: self.log.debug('Token validation failure.', exc_info=True) if token_hashes: self._token_cache.store_invalid(token_hashes[0]) self.log.warning(_LW('Authorization failed for token')) raise except Exception: self.log.critical(_LC('Unable to validate token'), exc_info=True) raise webob.exc.HTTPInternalServerError() return data
def fetch_token(self, token): """Retrieve a token from either a PKI bundle or the identity server. :param str token: token id :raises exc.InvalidToken: if token is rejected """ try: token_hashes = self._token_hashes(token) offline_data = self._validate_offline(token, token_hashes) if offline_data: # NOTE(jamielennox): If we've validated a PKI token we don't # need to cache it, and revocation check was already performed. return offline_data cached = self._token_cache.get_first(*token_hashes) if cached: if self._check_revocations_for_cached: # A token might have been revoked, regardless of initial # mechanism used to validate it, and needs to be checked. self._revocations.check(token_hashes) return cached data = self._identity_server.verify_token(token) self._token_cache.store(token_hashes[0], data) return data except (ksa_exceptions.ConnectFailure, ksa_exceptions.RequestTimeout, ksm_exceptions.RevocationListError, ksm_exceptions.ServiceError) as e: self.log.critical(_LC('Unable to validate token: %s'), e) raise webob.exc.HTTPServiceUnavailable() except ksm_exceptions.InvalidToken: self.log.debug('Token validation failure.', exc_info=True) if token_hashes: self._token_cache.store_invalid(token_hashes[0]) self.log.warning(_LW('Authorization failed for token')) raise except Exception: self.log.critical(_LC('Unable to validate token'), exc_info=True) raise webob.exc.HTTPInternalServerError()
def fetch_token(self, token): """Retrieve a token from either a PKI bundle or the identity server. :param str token: token id :raises exc.InvalidToken: if token is rejected """ data = None token_hashes = None try: token_hashes = self._token_hashes(token) cached = self._cache_get_hashes(token_hashes) if cached: data = cached if self._check_revocations_for_cached: # A token might have been revoked, regardless of initial # mechanism used to validate it, and needs to be checked. self._revocations.check(token_hashes) else: data = self._validate_offline(token, token_hashes) if not data: data = self._identity_server.verify_token(token) self._token_cache.store(token_hashes[0], data) except (ksa_exceptions.ConnectFailure, ksa_exceptions.RequestTimeout, ksm_exceptions.RevocationListError, ksm_exceptions.ServiceError) as e: self.log.critical(_LC('Unable to validate token: %s'), e) raise webob.exc.HTTPServiceUnavailable() except ksm_exceptions.InvalidToken: self.log.debug('Token validation failure.', exc_info=True) if token_hashes: self._token_cache.store_invalid(token_hashes[0]) self.log.warning(_LW('Authorization failed for token')) raise except Exception: self.log.critical(_LC('Unable to validate token'), exc_info=True) raise webob.exc.HTTPInternalServerError() return data
def fetch_token(self, token, allow_expired=False): """Retrieve a token from either a PKI bundle or the identity server. :param str token: token id :raises exc.InvalidToken: if token is rejected """ data = None token_hashes = None try: token_hashes = self._token_hashes(token) cached = self._cache_get_hashes(token_hashes) if cached: if cached == _CACHE_INVALID_INDICATOR: self.log.debug('Cached token is marked unauthorized') raise ksm_exceptions.InvalidToken() if self._check_revocations_for_cached: # A token might have been revoked, regardless of initial # mechanism used to validate it, and needs to be checked. self._revocations.check(token_hashes) # NOTE(jamielennox): Cached values used to be stored as a tuple # of data and expiry time. They no longer are but we have to # allow some time to transition the old format so if it's a # tuple just use the data. if len(cached) == 2: cached = cached[0] data = cached else: data = self._validate_offline(token, token_hashes) if not data: data = self._identity_server.verify_token( token, allow_expired=allow_expired) self._token_cache.set(token_hashes[0], data) except (ksa_exceptions.ConnectFailure, ksa_exceptions.RequestTimeout, ksm_exceptions.RevocationListError, ksm_exceptions.ServiceError) as e: self.log.critical(_LC('Unable to validate token: %s'), e) raise webob.exc.HTTPServiceUnavailable() except ksm_exceptions.InvalidToken: self.log.debug('Token validation failure.', exc_info=True) if token_hashes: self._token_cache.set(token_hashes[0], _CACHE_INVALID_INDICATOR) self.log.warning(_LW('Authorization failed for token')) raise return data
def fetch_token(self, token): """Retrieve a token from either a PKI bundle or the identity server. :param str token: token id :raises exc.InvalidToken: if token is rejected """ data = None token_hashes = None try: token_hashes = self._token_hashes(token) cached = self._cache_get_hashes(token_hashes) if cached: if cached == _CACHE_INVALID_INDICATOR: self._LOG.debug('Cached token is marked unauthorized') raise ksm_exceptions.InvalidToken() if self._check_revocations_for_cached: # A token might have been revoked, regardless of initial # mechanism used to validate it, and needs to be checked. self._revocations.check(token_hashes) # NOTE(jamielennox): Cached values used to be stored as a tuple # of data and expiry time. They no longer are but we have to # allow some time to transition the old format so if it's a # tuple just use the data. if len(cached) == 2: cached = cached[0] data = cached else: data = self._validate_offline(token, token_hashes) if not data: data = self._identity_server.verify_token(token) self._token_cache.set(token_hashes[0], data) except (ksa_exceptions.ConnectFailure, ksa_exceptions.RequestTimeout, ksm_exceptions.RevocationListError, ksm_exceptions.ServiceError) as e: self.log.critical(_LC('Unable to validate token: %s'), e) raise webob.exc.HTTPServiceUnavailable() except ksm_exceptions.InvalidToken: self.log.debug('Token validation failure.', exc_info=True) if token_hashes: self._token_cache.set(token_hashes[0], _CACHE_INVALID_INDICATOR) self.log.warning(_LW('Authorization failed for token')) raise return data
def acquire(self): try: conn = self.get(timeout=self._connection_get_timeout) except queue.Empty: self._LOG.critical(_LC('Unable to get a connection from pool id ' '%(id)s after %(seconds)s seconds.'), {'id': id(self), 'seconds': self._connection_get_timeout}) raise ConnectionGetTimeoutException() try: yield conn finally: self.put(conn)
def _fetch_token(self, token): """Retrieve a token from either a PKI bundle or the identity server. :param str token: token id :raises exc.InvalidToken: if token is rejected """ data = None token_hashes = None try: token_hashes = self._token_hashes(token) cached = self._cache_get_hashes(token_hashes) if cached: data = cached if self._check_revocations_for_cached: # A token stored in Memcached might have been revoked # regardless of initial mechanism used to validate it, # and needs to be checked. self._revocations.check(token_hashes) else: data = self._validate_offline(token, token_hashes) if not data: data = self._identity_server.verify_token(token) self._token_cache.store(token_hashes[0], data) except (exceptions.ConnectionRefused, exceptions.RequestTimeout): self.log.debug("Token validation failure.", exc_info=True) self.log.warning(_LW("Authorization failed for token")) raise exc.InvalidToken(_("Token authorization failed")) except exc.ServiceError as e: self.log.critical(_LC("Unable to obtain admin token: %s"), e) raise webob.exc.HTTPServiceUnavailable() except Exception: self.log.debug("Token validation failure.", exc_info=True) if token_hashes: self._token_cache.store_invalid(token_hashes[0]) self.log.warning(_LW("Authorization failed for token")) raise exc.InvalidToken(_("Token authorization failed")) return data
def _validate_token(self, token, env, retry=True): """Authenticate user token :param token: token id :param env: wsgi environment :param retry: Ignored, as it is not longer relevant :returns: uncrypted body of the token if the token is valid :raises exc.InvalidToken: if token is rejected """ token_id = None try: token_ids, cached = self._token_cache.get(token) token_id = token_ids[0] if cached: # Token was retrieved from the cache. In this case, there's no # need to check that the token is expired because the cache # fetch fails for an expired token. Also, there's no need to # put the token in the cache because it's already in the cache. data = cached if self._check_revocations_for_cached: # A token stored in Memcached might have been revoked # regardless of initial mechanism used to validate it, # and needs to be checked. self._revocations.check(token_ids) self._confirm_token_bind(data, env) else: verified = None # Token wasn't cached. In this case, the token needs to be # checked that it's not expired, and also put in the cache. try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_ids) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_ids) except exceptions.CertificateConfigError: self._LOG.warn(_LW('Fetch certificate config failed, ' 'fallback to online validation.')) except exc.RevocationListError: self._LOG.warn(_LW('Fetch revocation list failed, ' 'fallback to online validation.')) if verified is not None: data = jsonutils.loads(verified) audit_ids = None if 'access' in data: # It's a v2 token. audit_ids = data['access']['token'].get('audit_ids') else: # It's a v3 token audit_ids = data['token'].get('audit_ids') if audit_ids: self._revocations.check_by_audit_id(audit_ids) expires = _get_token_expiration(data) _confirm_token_not_expired(expires) else: data = self._identity_server.verify_token(token, retry) # No need to confirm token expiration here since # verify_token fails for expired tokens. expires = _get_token_expiration(data) self._confirm_token_bind(data, env) self._token_cache.store(token_id, data, expires) return data except (exceptions.ConnectionRefused, exceptions.RequestTimeout, exc.RevocationListError, exc.ServiceError) as e: self._LOG.critical(_LC('Unable to validate token: %s'), e) raise ServiceError() except exc.InvalidToken: self._LOG.debug('Token validation failure.', exc_info=True) if token_id: self._token_cache.store_invalid(token_id) self._LOG.warning(_LW('Authorization failed for token')) raise except Exception: self._LOG.critical(_LC('Unable to validate token'), exc_info=True) raise exc._InternalServiceError()
def __call__(self, env, start_response): """Handle incoming request. Authenticate send downstream on success. Reject request if we can't authenticate. """ def _fmt_msg(env): msg = ('user: user_id %s, project_id %s, roles %s ' 'service: user_id %s, project_id %s, roles %s' % ( env.get('HTTP_X_USER_ID'), env.get('HTTP_X_PROJECT_ID'), env.get('HTTP_X_ROLES'), env.get('HTTP_X_SERVICE_USER_ID'), env.get('HTTP_X_SERVICE_PROJECT_ID'), env.get('HTTP_X_SERVICE_ROLES'))) return msg self._token_cache.initialize(env) self._remove_auth_headers(env) try: user_auth_ref = None serv_auth_ref = None try: self._LOG.debug('Authenticating user token') user_token = self._get_user_token_from_header(env) user_token_info = self._validate_token(user_token, env) user_auth_ref = access.AccessInfo.factory( body=user_token_info, auth_token=user_token) env['keystone.token_info'] = user_token_info user_headers = self._build_user_headers(user_auth_ref, user_token_info) self._add_headers(env, user_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid user token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid user token - rejecting request')) return self._reject_request(env, start_response) try: self._LOG.debug('Authenticating service token') serv_token = self._get_service_token_from_header(env) if serv_token is not None: serv_token_info = self._validate_token( serv_token, env) serv_auth_ref = access.AccessInfo.factory( body=serv_token_info, auth_token=serv_token) serv_headers = self._build_service_headers(serv_token_info) self._add_headers(env, serv_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid service token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Service-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid service token - rejecting request')) return self._reject_request(env, start_response) env['keystone.token_auth'] = _user_plugin.UserAuthPlugin( user_auth_ref, serv_auth_ref) except exc.ServiceError as e: self._LOG.critical(_LC('Unable to obtain admin token: %s'), e) return self._do_503_error(env, start_response) except exc._InternalServiceError: return self._do_500_error(env, start_response) self._LOG.debug("Received request from %s", _fmt_msg(env)) return self._call_app(env, start_response)
def __call__(self, request): """Handle incoming request. Authenticate send downstream on success. Reject request if we can't authenticate. """ self._token_cache.initialize(request.environ) self._remove_auth_headers(request.environ) try: user_auth_ref = None serv_auth_ref = None try: self._LOG.debug('Authenticating user token') user_token_info = self._get_user_token_from_request(request) user_auth_ref, user_token_info = self._validate_token( user_token_info, request.environ) request.environ['keystone.token_info'] = user_token_info user_headers = self._build_user_headers(user_auth_ref) self._add_headers(request.environ, user_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid user token - deferring reject ' 'downstream')) self._add_headers(request.environ, {'X-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid user token - rejecting request')) self._reject_request() try: self._LOG.debug('Authenticating service token') serv_token = request.headers.get('X-Service-Token') if serv_token is not None: serv_auth_ref, serv_token_info = self._validate_token( serv_token, request.environ) serv_headers = self._build_service_headers(serv_auth_ref) self._add_headers(request.environ, serv_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid service token - deferring reject ' 'downstream')) self._add_headers(request.environ, {'X-Service-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid service token - rejecting request')) self._reject_request() p = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref) request.environ['keystone.token_auth'] = p except exc.ServiceError as e: self._LOG.critical(_LC('Unable to obtain admin token: %s'), e) raise webob.exc.HTTPServiceUnavailable() if self._LOG.isEnabledFor(logging.DEBUG): self._LOG.debug('Received request from %s' % p._log_format) response = request.get_response(self._app) if response.status_int == 401: response.headers.extend(self._reject_auth_headers) return response
def __call__(self, env, start_response): """Handle incoming request. Authenticate send downstream on success. Reject request if we can't authenticate. """ def _fmt_msg(env): msg = ('user: user_id %s, project_id %s, roles %s ' 'service: user_id %s, project_id %s, roles %s' % ( env.get('HTTP_X_USER_ID'), env.get('HTTP_X_PROJECT_ID'), env.get('HTTP_X_ROLES'), env.get('HTTP_X_SERVICE_USER_ID'), env.get('HTTP_X_SERVICE_PROJECT_ID'), env.get('HTTP_X_SERVICE_ROLES'))) return msg self._token_cache.initialize(env) self._remove_auth_headers(env) try: user_auth_ref = None serv_auth_ref = None try: self._LOG.debug('Authenticating user token') user_token = self._get_user_token_from_header(env) user_token_info = self._validate_token(user_token, env) user_auth_ref = access.AccessInfo.factory( body=user_token_info, auth_token=user_token) env['keystone.token_info'] = user_token_info user_headers = self._build_user_headers(user_auth_ref, user_token_info) self._add_headers(env, user_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid user token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid user token - rejecting request')) return self._reject_request(env, start_response) try: self._LOG.debug('Authenticating service token') serv_token = self._get_service_token_from_header(env) if serv_token is not None: serv_token_info = self._validate_token( serv_token, env) serv_auth_ref = access.AccessInfo.factory( body=serv_token_info, auth_token=serv_token) serv_headers = self._build_service_headers(serv_token_info) self._add_headers(env, serv_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid service token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Service-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid service token - rejecting request')) return self._reject_request(env, start_response) env['keystone.token_auth'] = _user_plugin.UserAuthPlugin( user_auth_ref, serv_auth_ref) except exc.ServiceError as e: self._LOG.critical(_LC('Unable to obtain admin token: %s'), e) return self._do_503_error(env, start_response) self._LOG.debug("Received request from %s", _fmt_msg(env)) return self._call_app(env, start_response)
def _validate_token(self, token, env, retry=True): """Authenticate user token :param token: token id :param env: wsgi environment :param retry: Ignored, as it is not longer relevant :returns: uncrypted body of the token if the token is valid :raises exc.InvalidToken: if token is rejected """ token_id = None try: token_ids, cached = self._token_cache.get(token) token_id = token_ids[0] if cached: # Token was retrieved from the cache. In this case, there's no # need to check that the token is expired because the cache # fetch fails for an expired token. Also, there's no need to # put the token in the cache because it's already in the cache. data = cached if self._check_revocations_for_cached: # A token stored in Memcached might have been revoked # regardless of initial mechanism used to validate it, # and needs to be checked. self._revocations.check(token_ids) self._confirm_token_bind(data, env) else: verified = None # Token wasn't cached. In this case, the token needs to be # checked that it's not expired, and also put in the cache. try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_ids) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_ids) except exceptions.CertificateConfigError: self._LOG.warn( _LW('Fetch certificate config failed, ' 'fallback to online validation.')) except exc.RevocationListError: self._LOG.warn( _LW('Fetch revocation list failed, ' 'fallback to online validation.')) if verified is not None: data = jsonutils.loads(verified) audit_ids = None if 'access' in data: # It's a v2 token. audit_ids = data['access']['token'].get('audit_ids') else: # It's a v3 token audit_ids = data['token'].get('audit_ids') if audit_ids: self._revocations.check_by_audit_id(audit_ids) expires = _get_token_expiration(data) _confirm_token_not_expired(expires) else: data = self._identity_server.verify_token(token, retry) # No need to confirm token expiration here since # verify_token fails for expired tokens. expires = _get_token_expiration(data) self._confirm_token_bind(data, env) self._token_cache.store(token_id, data, expires) return data except (exceptions.ConnectionRefused, exceptions.RequestTimeout, exc.RevocationListError, exc.ServiceError) as e: self._LOG.critical(_LC('Unable to validate token: %s'), e) raise ServiceError() except exc.InvalidToken: self._LOG.debug('Token validation failure.', exc_info=True) if token_id: self._token_cache.store_invalid(token_id) self._LOG.warning(_LW('Authorization failed for token')) raise except Exception: self._LOG.critical(_LC('Unable to validate token'), exc_info=True) raise exc._InternalServiceError()