def verify_token(self, user_token, retry=True): """Authenticate user token with identity server. :param user_token: user's token id :param retry: flag that forces the middleware to retry user authentication when an indeterminate response is received. Optional. :returns: access info received from identity server on success :rtype: :py:class:`keystoneauth1.access.AccessInfo` :raises exc.InvalidToken: if token is rejected :raises exc.ServiceError: if unable to authenticate token """ try: auth_ref = self._request_strategy.verify_token(user_token) except ksa_exceptions.NotFound as e: self._LOG.warning(_LW("Authorization failed for token")) self._LOG.warning(_LW("Identity response: %s"), e.response.text) raise ksm_exceptions.InvalidToken(_("Token authorization failed")) except ksa_exceptions.Unauthorized as e: self._LOG.info(_LI("Identity server rejected authorization")) self._LOG.warning(_LW("Identity response: %s"), e.response.text) if retry: self._LOG.info(_LI("Retrying validation")) return self.verify_token(user_token, False) msg = _("Identity server rejected authorization necessary to " "fetch token data") raise ksm_exceptions.ServiceError(msg) except ksa_exceptions.HttpError as e: self._LOG.error(_LE("Bad response code while validating token: %s"), e.http_status) self._LOG.warning(_LW("Identity response: %s"), e.response.text) msg = _("Failed to fetch token data from identity server") raise ksm_exceptions.ServiceError(msg) else: return auth_ref
def verify_token(self, user_token, retry=True): """Authenticate user token with identity server. :param user_token: user's token id :param retry: flag that forces the middleware to retry user authentication when an indeterminate response is received. Optional. :returns: token object received from identity server on success :raises exc.InvalidToken: if token is rejected :raises exc.ServiceError: if unable to authenticate token """ user_token = _utils.safe_quote(user_token) try: response, data = self._request_strategy.verify_token(user_token) except exceptions.NotFound as e: self._LOG.warn(_LW('Authorization failed for token')) self._LOG.warn(_LW('Identity response: %s'), e.response.text) except exceptions.Unauthorized as e: self._LOG.info(_LI('Identity server rejected authorization')) self._LOG.warn(_LW('Identity response: %s'), e.response.text) if retry: self._LOG.info(_LI('Retrying validation')) return self.verify_token(user_token, False) except exceptions.HttpError as e: self._LOG.error( _LE('Bad response code while validating token: %s'), e.http_status) self._LOG.warn(_LW('Identity response: %s'), e.response.text) else: if response.status_code == 200: return data raise exc.InvalidToken()
def _validate_offline(self, token, token_hashes): if cms.is_pkiz(token): token_data = _uncompress_pkiz(token) inform = cms.PKIZ_CMS_FORM elif cms.is_asn1_token(token): token_data = cms.token_to_cms(token) inform = cms.PKI_ASN1_FORM else: # Can't do offline validation for this type of token. return try: self._revocations.check(token_hashes) verified = self._cms_verify(token_data, inform) except ksc_exceptions.CertificateConfigError: self.log.warning(_LW('Fetch certificate config failed, ' 'fallback to online validation.')) except ksm_exceptions.RevocationListError: self.log.warning(_LW('Fetch revocation list failed, ' 'fallback to online validation.')) else: 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) return data
def _validate_offline(self, token, token_hashes): try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_hashes) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_hashes) else: # Can't do offline validation for this type of token. return except ksc_exceptions.CertificateConfigError: self.log.warning(_LW('Fetch certificate config failed, ' 'fallback to online validation.')) except ksm_exceptions.RevocationListError: self.log.warning(_LW('Fetch revocation list failed, ' 'fallback to online validation.')) else: 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) return data
def _validate_offline(self, token, token_hashes): try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_hashes) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_hashes) else: # Can't do offline validation for this type of token. return except exceptions.CertificateConfigError: self.log.warning( _LW('Fetch certificate config failed, ' 'fallback to online validation.')) except exc.RevocationListError: self.log.warning( _LW('Fetch revocation list failed, ' 'fallback to online validation.')) else: 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) return data
def __init__(self, auth_host, auth_port, auth_protocol, auth_admin_prefix, admin_user, admin_password, admin_tenant_name, admin_token, identity_uri, log): log.warning( _LW("Use of the auth_admin_prefix, auth_host, auth_port, " "auth_protocol, identity_uri, admin_token, admin_user, " "admin_password, and admin_tenant_name configuration options was " "deprecated in the Mitaka release in favor of an auth_plugin and " "its related options. This class may be removed in a future " "release.")) # NOTE(jamielennox): it does appear here that our default arguments # are backwards. We need to do it this way so that we can handle the # same deprecation strategy for CONF and the conf variable. if not identity_uri: log.warning( _LW('Configuring admin URI using auth fragments was ' 'deprecated in the Kilo release, and will be ' 'removed in the Newton release, ' 'use \'identity_uri\ instead.')) if ':' in auth_host: # Note(dzyu) it is an IPv6 address, so it needs to be wrapped # with '[]' to generate a valid IPv6 URL, based on # http://www.ietf.org/rfc/rfc2732.txt auth_host = '[%s]' % auth_host identity_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port) if auth_admin_prefix: identity_uri = '%s/%s' % (identity_uri, auth_admin_prefix.strip('/')) self._identity_uri = identity_uri.rstrip('/') # FIXME(jamielennox): Yes. This is wrong. We should be determining the # plugin to use based on a combination of discovery and inputs. Much # of this can be changed when we get keystoneclient 0.10. For now this # hardcoded path is EXACTLY the same as the original auth_token did. auth_url = '%s/v2.0' % self._identity_uri if admin_token: log.warning( _LW("The admin_token option in auth_token middleware was " "deprecated in the Kilo release, and will be removed in the " "Newton release, use admin_user and admin_password instead." )) self._plugin = token_endpoint.Token(auth_url, admin_token) else: self._plugin = v2.Password(auth_url, username=admin_user, password=admin_password, tenant_name=admin_tenant_name) self._LOG = log self._discover = None
def __init__(self, auth_host, auth_port, auth_protocol, auth_admin_prefix, admin_user, admin_password, admin_tenant_name, admin_token, identity_uri, log): log.warning(_LW( "Use of the auth_admin_prefix, auth_host, auth_port, " "auth_protocol, identity_uri, admin_token, admin_user, " "admin_password, and admin_tenant_name configuration options was " "deprecated in the Mitaka release in favor of an auth_plugin and " "its related options. This class may be removed in a future " "release.")) # NOTE(jamielennox): it does appear here that our default arguments # are backwards. We need to do it this way so that we can handle the # same deprecation strategy for CONF and the conf variable. if not identity_uri: log.warning(_LW('Configuring admin URI using auth fragments was ' 'deprecated in the Kilo release, and will be ' 'removed in the N release, use \'identity_uri\ ' 'instead.')) if ':' in auth_host: # Note(dzyu) it is an IPv6 address, so it needs to be wrapped # with '[]' to generate a valid IPv6 URL, based on # http://www.ietf.org/rfc/rfc2732.txt auth_host = '[%s]' % auth_host identity_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port) if auth_admin_prefix: identity_uri = '%s/%s' % (identity_uri, auth_admin_prefix.strip('/')) self._identity_uri = identity_uri.rstrip('/') # FIXME(jamielennox): Yes. This is wrong. We should be determining the # plugin to use based on a combination of discovery and inputs. Much # of this can be changed when we get keystoneclient 0.10. For now this # hardcoded path is EXACTLY the same as the original auth_token did. auth_url = '%s/v2.0' % self._identity_uri if admin_token: log.warning(_LW( "The admin_token option in auth_token middleware was " "deprecated in the Kilo release, and will be removed in the N " "release, use admin_user and admin_password instead.")) self._plugin = token_endpoint.Token(auth_url, admin_token) else: self._plugin = v2.Password(auth_url, username=admin_user, password=admin_password, tenant_name=admin_tenant_name) self._LOG = log self._discover = None
def __init__(self, app, conf): """Common initialization code.""" self._app = app self._logger = logging.getLogger(conf.get('log_name', __name__)) self._logger.debug('Starting the %s component', PROTOCOL_NAME) self._reseller_prefix = conf.get('reseller_prefix', 'AUTH_') # where to find the auth service (we use this to validate tokens) self._request_uri = conf.get('auth_uri') if not self._request_uri: self._logger.warning( _LW("Use of the auth_host, auth_port, and auth_protocol " "configuration options was deprecated in the Newton release " "in favor of auth_uri. These options may be removed in a " "future release.")) auth_host = conf.get('auth_host') auth_port = int(conf.get('auth_port', 35357)) auth_protocol = conf.get('auth_protocol', 'https') self._request_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port) # SSL insecure = strutils.bool_from_string(conf.get('insecure', False)) cert_file = conf.get('certfile') key_file = conf.get('keyfile') if insecure: self._verify = False elif cert_file and key_file: self._verify = (cert_file, key_file) elif cert_file: self._verify = cert_file else: self._verify = None
def __init__(self, app, conf): """Common initialization code.""" self._app = app self._logger = logging.getLogger(conf.get('log_name', __name__)) self._logger.debug('Starting the %s component', PROTOCOL_NAME) self._reseller_prefix = conf.get('reseller_prefix', 'AUTH_') # where to find the auth service (we use this to validate tokens) self._request_uri = conf.get('auth_uri') if not self._request_uri: self._logger.warning(_LW( "Use of the auth_host, auth_port, and auth_protocol " "configuration options was deprecated in the Newton release " "in favor of auth_uri. These options may be removed in a " "future release.")) auth_host = conf.get('auth_host') auth_port = int(conf.get('auth_port', 35357)) auth_protocol = conf.get('auth_protocol', 'https') self._request_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port) # SSL insecure = strutils.bool_from_string(conf.get('insecure', False)) cert_file = conf.get('certfile') key_file = conf.get('keyfile') if insecure: self._verify = False elif cert_file and key_file: self._verify = (cert_file, key_file) elif cert_file: self._verify = cert_file else: self._verify = None
def _verify_signing_dir(self): if os.path.isdir(self._directory_name): if not os.access(self._directory_name, os.W_OK): raise exc.ConfigurationError( _('unable to access signing_dir %s') % self._directory_name) uid = os.getuid() if os.stat(self._directory_name).st_uid != uid: self._log.warning(_LW('signing_dir is not owned by %s'), uid) current_mode = stat.S_IMODE(os.stat(self._directory_name).st_mode) if current_mode != stat.S_IRWXU: self._log.warning( _LW('signing_dir mode is %(mode)s instead of %(need)s'), {'mode': oct(current_mode), 'need': oct(stat.S_IRWXU)}) else: os.makedirs(self._directory_name, stat.S_IRWXU)
def _validate_offline(self, token, token_hashes): try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_hashes) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_hashes) else: # Can't do offline validation for this type of token. return except exceptions.CertificateConfigError: self.log.warning(_LW("Fetch certificate config failed, " "fallback to online validation.")) except exc.RevocationListError: self.log.warning(_LW("Fetch revocation list failed, " "fallback to online validation.")) else: data = jsonutils.loads(verified) return data
def verify(): try: signing_cert_path = self._signing_directory.calc_path(self._SIGNING_CERT_FILE_NAME) signing_ca_path = self._signing_directory.calc_path(self._SIGNING_CA_FILE_NAME) return cms.cms_verify(data, signing_cert_path, signing_ca_path, inform=inform).decode("utf-8") except cms.subprocess.CalledProcessError as err: self.log.warning(_LW("Verify error: %s"), err) raise
def _do_fetch_token(self, token): """Helper method to fetch a token and convert it into an AccessInfo""" data = self._fetch_token(token) try: return data, access.AccessInfo.factory(body=data, auth_token=token) except Exception: self.log.warning(_LW("Invalid token contents."), exc_info=True) raise exc.InvalidToken(_("Token authorization failed"))
def _do_fetch_token(self, token): """Helper method to fetch a token and convert it into an AccessInfo""" data = self.fetch_token(token) try: return data, access.create(body=data, auth_token=token) except Exception: self.log.warning(_LW('Invalid token contents.'), exc_info=True) raise ksm_exceptions.InvalidToken(_('Token authorization failed'))
def _do_fetch_token(self, token): """Helper method to fetch a token and convert it into an AccessInfo""" data = self._fetch_token(token) try: return data, access.AccessInfo.factory(body=data, auth_token=token) except Exception: self.log.warning(_LW('Invalid token contents.'), exc_info=True) raise exc.InvalidToken(_('Token authorization failed'))
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 _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 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 _validate_offline(self, token, token_hashes): try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_hashes) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_hashes) else: # Can't do offline validation for this type of token. return except exceptions.CertificateConfigError: self.log.warning( _LW('Fetch certificate config failed, ' 'fallback to online validation.')) except exc.RevocationListError: self.log.warning( _LW('Fetch revocation list failed, ' 'fallback to online validation.')) else: data = jsonutils.loads(verified) 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 __init__(self, memcached_servers, log): self._memcached_servers = memcached_servers if not self._memcached_servers: log.warning(_LW( "Using the in-process token cache is deprecated as of the " "4.2.0 release and may be removed in the 5.0.0 release or " "the 'O' development cycle. The in-process cache causes " "inconsistent results and high memory usage. When the feature " "is removed the auth_token middleware will not cache tokens " "by default which may result in performance issues. It is " "recommended to use memcache for the auth_token token cache " "by setting the memcached_servers option."))
def verify(): try: signing_cert_path = self._signing_directory.calc_path( self._SIGNING_CERT_FILE_NAME) signing_ca_path = self._signing_directory.calc_path( self._SIGNING_CA_FILE_NAME) return cms.cms_verify(data, signing_cert_path, signing_ca_path, inform=inform).decode('utf-8') except cms.subprocess.CalledProcessError as err: self._LOG.warning(_LW('Verify error: %s'), err) raise
def verify_token(self, user_token, retry=True, allow_expired=False): """Authenticate user token with identity server. :param user_token: user's token id :param retry: flag that forces the middleware to retry user authentication when an indeterminate response is received. Optional. :param allow_expired: Allow retrieving an expired token. :returns: access info received from identity server on success :rtype: :py:class:`keystoneauth1.access.AccessInfo` :raises exc.InvalidToken: if token is rejected :raises exc.ServiceError: if unable to authenticate token """ try: auth_ref = self._request_strategy.verify_token( user_token, allow_expired=allow_expired) except ksa_exceptions.NotFound as e: self._LOG.warning(_LW('Authorization failed for token')) self._LOG.warning(_LW('Identity response: %s'), e.response.text) raise ksm_exceptions.InvalidToken(_('Token authorization failed')) except ksa_exceptions.Unauthorized as e: self._LOG.info(_LI('Identity server rejected authorization')) self._LOG.warning(_LW('Identity response: %s'), e.response.text) if retry: self._LOG.info(_LI('Retrying validation')) return self.verify_token(user_token, False) msg = _('Identity server rejected authorization necessary to ' 'fetch token data') raise ksm_exceptions.ServiceError(msg) except ksa_exceptions.HttpError as e: self._LOG.error( _LE('Bad response code while validating token: %s'), e.http_status) self._LOG.warning(_LW('Identity response: %s'), e.response.text) msg = _('Failed to fetch token data from identity server') raise ksm_exceptions.ServiceError(msg) else: return auth_ref
def verify(): try: signing_cert_path = self._signing_directory.calc_path( self._SIGNING_CERT_FILE_NAME) signing_ca_path = self._signing_directory.calc_path( self._SIGNING_CA_FILE_NAME) return cms.cms_verify(data, signing_cert_path, signing_ca_path, inform=inform).decode('utf-8') except (exceptions.CMSError, cms.subprocess.CalledProcessError) as err: self._LOG.warning(_LW('Verify error: %s'), err) raise exc.InvalidToken(_('Token authorization failed'))
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 __init__(self, app, conf): log = logging.getLogger(conf.get('log_name', __name__)) log.info(_LI('Starting Keystone auth_token middleware')) self._conf = config.Config('auth_token', _base.AUTHTOKEN_GROUP, list_opts(), conf) super(AuthProtocol, self).__init__( app, log=log, enforce_token_bind=self._conf.get('enforce_token_bind')) # delay_auth_decision means we still allow unauthenticated requests # through and we let the downstream service make the final decision self._delay_auth_decision = self._conf.get('delay_auth_decision') self._include_service_catalog = self._conf.get( 'include_service_catalog') self._hash_algorithms = self._conf.get('hash_algorithms') self._auth = self._create_auth_plugin() self._session = self._create_session() self._identity_server = self._create_identity_server() self._auth_uri = self._conf.get('auth_uri') if not self._auth_uri: self.log.warning( _LW('Configuring auth_uri to point to the public identity ' 'endpoint is required; clients may not be able to ' 'authenticate against an admin endpoint')) # FIXME(dolph): drop support for this fallback behavior as # documented in bug 1207517. self._auth_uri = self._identity_server.auth_uri self._signing_directory = _signing_dir.SigningDirectory( directory_name=self._conf.get('signing_dir'), log=self.log) self._token_cache = self._token_cache_factory() revocation_cache_timeout = datetime.timedelta( seconds=self._conf.get('revocation_cache_time')) self._revocations = _revocations.Revocations(revocation_cache_timeout, self._signing_directory, self._identity_server, self._cms_verify, self.log) self._check_revocations_for_cached = self._conf.get( 'check_revocations_for_cached')
def verify(): try: signing_cert_path = self._signing_directory.calc_path( self._SIGNING_CERT_FILE_NAME) signing_ca_path = self._signing_directory.calc_path( self._SIGNING_CA_FILE_NAME) return cms.cms_verify(data, signing_cert_path, signing_ca_path, inform=inform).decode('utf-8') except (exceptions.CMSError, cms.subprocess.CalledProcessError) as err: self.log.warning(_LW('Verify error: %s'), err) raise exc.InvalidToken(_('Token authorization failed'))
def __init__(self, app, conf): log = logging.getLogger(conf.get('log_name', __name__)) log.info(_LI('Starting Keystone auth_token middleware')) # NOTE(wanghong): If options are set in paste file, all the option # values passed into conf are string type. So, we should convert the # conf value into correct type. self._conf = _conf_values_type_convert(conf) super(AuthProtocol, self).__init__( app, log=log, enforce_token_bind=self._conf_get('enforce_token_bind')) # delay_auth_decision means we still allow unauthenticated requests # through and we let the downstream service make the final decision self._delay_auth_decision = self._conf_get('delay_auth_decision') self._include_service_catalog = self._conf_get( 'include_service_catalog') self._hash_algorithms = self._conf_get('hash_algorithms') self._identity_server = self._create_identity_server() self._auth_uri = self._conf_get('auth_uri') if not self._auth_uri: self.log.warning( _LW('Configuring auth_uri to point to the public identity ' 'endpoint is required; clients may not be able to ' 'authenticate against an admin endpoint')) # FIXME(dolph): drop support for this fallback behavior as # documented in bug 1207517. self._auth_uri = self._identity_server.auth_uri self._signing_directory = _signing_dir.SigningDirectory( directory_name=self._conf_get('signing_dir'), log=self.log) self._token_cache = self._token_cache_factory() revocation_cache_timeout = datetime.timedelta( seconds=self._conf_get('revocation_cache_time')) self._revocations = _revocations.Revocations(revocation_cache_timeout, self._signing_directory, self._identity_server, self._cms_verify, self.log) self._check_revocations_for_cached = self._conf_get( 'check_revocations_for_cached')
def _validate_offline(self, token, token_hashes): if cms.is_pkiz(token): token_data = _uncompress_pkiz(token) inform = cms.PKIZ_CMS_FORM elif cms.is_asn1_token(token): token_data = cms.token_to_cms(token) inform = cms.PKI_ASN1_FORM else: # Can't do offline validation for this type of token. return try: self._revocations.check(token_hashes) verified = self._cms_verify(token_data, inform) except ksc_exceptions.CertificateConfigError: self.log.warning( _LW('Fetch certificate config failed, ' 'fallback to online validation.')) except ksm_exceptions.RevocationListError: self.log.warning( _LW('Fetch revocation list failed, ' 'fallback to online validation.')) else: 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) return data
def _do_fetch_token(self, token, **kwargs): """Helper method to fetch a token and convert it into an AccessInfo.""" if self.kwargs_to_fetch_token: data = self.fetch_token(token, **kwargs) else: m = _('Implementations of auth_token must set ' 'kwargs_to_fetch_token this will be the required and ' 'assumed in Pike.') warnings.warn(m) data = self.fetch_token(token) try: return data, access.create(body=data, auth_token=token) except Exception: self.log.warning(_LW('Invalid token contents.'), exc_info=True) raise ksm_exceptions.InvalidToken(_('Token authorization failed'))
def get_target_resource(self, req): """Retrieve target information. If discovery is enabled, target will attempt to retrieve information from service catalog. If not, the information will be taken from given config file. """ service_info = Service(type=taxonomy.UNKNOWN, name=taxonomy.UNKNOWN, id=taxonomy.UNKNOWN, admin_endp=None, private_endp=None, public_endp=None) catalog = {} try: catalog = jsonutils.loads(req.environ['HTTP_X_SERVICE_CATALOG']) except KeyError: msg = _LW('Unable to discover target information because ' 'service catalog is missing. Either the incoming ' 'request does not contain an auth token or auth ' 'token does not contain a service catalog. For ' 'the latter, please make sure the ' '"include_service_catalog" property in ' 'auth_token middleware is set to "True"') self._log.warning(msg) default_endpoint = None for endp in catalog: endpoint_urls = endp['endpoints'][0] admin_urlparse = urlparse.urlparse( endpoint_urls.get('adminURL', '')) public_urlparse = urlparse.urlparse( endpoint_urls.get('publicURL', '')) req_url = urlparse.urlparse(req.host_url) if (req_url.netloc == admin_urlparse.netloc or req_url.netloc == public_urlparse.netloc): service_info = self._get_service_info(endp) break elif (self._MAP.default_target_endpoint_type and endp['type'] == self._MAP.default_target_endpoint_type): default_endpoint = endp else: if default_endpoint: service_info = self._get_service_info(default_endpoint) return self._build_target(req, service_info)
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 __init__(self, app, conf): self._LOG = logging.getLogger(conf.get('log_name', __name__)) self._LOG.info(_LI('Starting Keystone auth_token middleware')) # NOTE(wanghong): If options are set in paste file, all the option # values passed into conf are string type. So, we should convert the # conf value into correct type. self._conf = _conf_values_type_convert(conf) self._app = app # delay_auth_decision means we still allow unauthenticated requests # through and we let the downstream service make the final decision self._delay_auth_decision = self._conf_get('delay_auth_decision') self._include_service_catalog = self._conf_get( 'include_service_catalog') self._identity_server = self._create_identity_server() self._auth_uri = self._conf_get('auth_uri') if not self._auth_uri: self._LOG.warning( _LW('Configuring auth_uri to point to the public identity ' 'endpoint is required; clients may not be able to ' 'authenticate against an admin endpoint')) # FIXME(dolph): drop support for this fallback behavior as # documented in bug 1207517. self._auth_uri = self._identity_server.auth_uri self._signing_directory = _signing_dir.SigningDirectory( directory_name=self._conf_get('signing_dir'), log=self._LOG) self._token_cache = self._token_cache_factory() revocation_cache_timeout = datetime.timedelta( seconds=self._conf_get('revocation_cache_time')) self._revocations = _revocations.Revocations(revocation_cache_timeout, self._signing_directory, self._identity_server, self._cms_verify, self._LOG) self._check_revocations_for_cached = self._conf_get( 'check_revocations_for_cached') self._init_auth_headers()
def _get_user_token_from_header(self, env): """Get token id from request. :param env: wsgi request environment :returns: token id :raises exc.InvalidToken: if no token is provided in request """ token = self._get_header(env, 'X-Auth-Token', self._get_header(env, 'X-Storage-Token')) if token: return token else: if not self._delay_auth_decision: self._LOG.warn(_LW('Unable to find authentication token' ' in headers')) self._LOG.debug('Headers: %s', env) raise exc.InvalidToken(_('Unable to find token in headers'))
def __init__(self, app, conf): log = logging.getLogger(conf.get('log_name', __name__)) log.info(_LI('Starting Keystone auth_token middleware')) # NOTE(wanghong): If options are set in paste file, all the option # values passed into conf are string type. So, we should convert the # conf value into correct type. self._conf = _conf_values_type_convert(conf) # NOTE(sileht, cdent): If we don't want to use oslo.config global # object there are two options: set "oslo_config_project" in # paste.ini and the middleware will load the configuration with a # local oslo.config object or the caller which instantiates # AuthProtocol can pass in an existing oslo.config as the # value of the "oslo_config_config" key in conf. If both are # set "olso_config_config" is used. self._local_oslo_config = conf.get('oslo_config_config') if (not self._local_oslo_config) and ('oslo_config_project' in conf): if 'oslo_config_file' in conf: default_config_files = [conf['oslo_config_file']] else: default_config_files = None self._local_oslo_config = cfg.ConfigOpts() self._local_oslo_config( [], project=conf['oslo_config_project'], default_config_files=default_config_files, validate_default_values=True) if self._local_oslo_config: self._local_oslo_config.register_opts(_OPTS, group=_base.AUTHTOKEN_GROUP) self._local_oslo_config.register_opts(_auth.OPTS, group=_base.AUTHTOKEN_GROUP) loading.register_auth_conf_options(self._local_oslo_config, group=_base.AUTHTOKEN_GROUP) super(AuthProtocol, self).__init__( app, log=log, enforce_token_bind=self._conf_get('enforce_token_bind')) # delay_auth_decision means we still allow unauthenticated requests # through and we let the downstream service make the final decision self._delay_auth_decision = self._conf_get('delay_auth_decision') self._include_service_catalog = self._conf_get( 'include_service_catalog') self._hash_algorithms = self._conf_get('hash_algorithms') self._identity_server = self._create_identity_server() self._auth_uri = self._conf_get('auth_uri') if not self._auth_uri: self.log.warning( _LW('Configuring auth_uri to point to the public identity ' 'endpoint is required; clients may not be able to ' 'authenticate against an admin endpoint')) # FIXME(dolph): drop support for this fallback behavior as # documented in bug 1207517. self._auth_uri = self._identity_server.auth_uri self._signing_directory = _signing_dir.SigningDirectory( directory_name=self._conf_get('signing_dir'), log=self.log) self._token_cache = self._token_cache_factory() revocation_cache_timeout = datetime.timedelta( seconds=self._conf_get('revocation_cache_time')) self._revocations = _revocations.Revocations(revocation_cache_timeout, self._signing_directory, self._identity_server, self._cms_verify, self.log) self._check_revocations_for_cached = self._conf_get( 'check_revocations_for_cached')
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 _validate_token(self, token, env): """Authenticate user token :param token: token id :param env: wsgi environment :returns: uncrypted body of the token if the token is valid :raises exc.InvalidToken: if token is rejected """ 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: verified = None try: if cms.is_pkiz(token): verified = self._verify_pkiz_token(token, token_hashes) elif cms.is_asn1_token(token): verified = self._verify_signed_token(token, token_hashes) except exceptions.CertificateConfigError: self._LOG.warning(_LW('Fetch certificate config failed, ' 'fallback to online validation.')) except exc.RevocationListError: self._LOG.warning(_LW('Fetch revocation list failed, ' 'fallback to online validation.')) if verified is not None: data = jsonutils.loads(verified) else: data = self._identity_server.verify_token(token) auth_ref = access.AccessInfo.factory(body=data, auth_token=token) # 0 seconds of validity means is it valid right now. if auth_ref.will_expire_soon(stale_duration=0): raise exc.InvalidToken(_('Token authorization failed')) if _token_is_v2(data) and not auth_ref.project_id: msg = _('Unable to determine service tenancy.') raise exc.InvalidToken(msg) self._confirm_token_bind(data, env) if not cached: self._token_cache.store(token_hashes[0], data) return auth_ref, 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: raise 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'))
def __init__(self, app, conf): log = logging.getLogger(conf.get('log_name', __name__)) log.info(_LI('Starting Keystone auth_token middleware')) # NOTE(wanghong): If options are set in paste file, all the option # values passed into conf are string type. So, we should convert the # conf value into correct type. self._conf = _conf_values_type_convert(conf) # NOTE(sileht): If we don't want to use oslo.config global object # we can set the paste "oslo_config_project" and the middleware # will load the configuration with a local oslo.config object. self._local_oslo_config = None if 'oslo_config_project' in conf: if 'oslo_config_file' in conf: default_config_files = [conf['oslo_config_file']] else: default_config_files = None # For unit tests, support passing in a ConfigOpts in # oslo_config_config. self._local_oslo_config = conf.get('oslo_config_config', cfg.ConfigOpts()) self._local_oslo_config({}, project=conf['oslo_config_project'], default_config_files=default_config_files, validate_default_values=True) self._local_oslo_config.register_opts(_OPTS, group=_base.AUTHTOKEN_GROUP) auth.register_conf_options(self._local_oslo_config, group=_base.AUTHTOKEN_GROUP) super(AuthProtocol, self).__init__( app, log=log, enforce_token_bind=self._conf_get('enforce_token_bind')) # delay_auth_decision means we still allow unauthenticated requests # through and we let the downstream service make the final decision self._delay_auth_decision = self._conf_get('delay_auth_decision') self._include_service_catalog = self._conf_get( 'include_service_catalog') self._hash_algorithms = self._conf_get('hash_algorithms') self._identity_server = self._create_identity_server() self._auth_uri = self._conf_get('auth_uri') if not self._auth_uri: self.log.warning( _LW('Configuring auth_uri to point to the public identity ' 'endpoint is required; clients may not be able to ' 'authenticate against an admin endpoint')) # FIXME(dolph): drop support for this fallback behavior as # documented in bug 1207517. self._auth_uri = self._identity_server.auth_uri self._signing_directory = _signing_dir.SigningDirectory( directory_name=self._conf_get('signing_dir'), log=self.log) self._token_cache = self._token_cache_factory() revocation_cache_timeout = datetime.timedelta( seconds=self._conf_get('revocation_cache_time')) self._revocations = _revocations.Revocations(revocation_cache_timeout, self._signing_directory, self._identity_server, self._cms_verify, self.log) self._check_revocations_for_cached = self._conf_get( 'check_revocations_for_cached')
def __init__(self, app, conf): # tomograph.start("AuthProtocol", "init", "127.0.0.1", 0) log = logging.getLogger(conf.get("log_name", __name__)) log.info(_LI("Starting Keystone auth_token middleware")) # NOTE(wanghong): If options are set in paste file, all the option # values passed into conf are string type. So, we should convert the # conf value into correct type. self._conf = _conf_values_type_convert(conf) # NOTE(sileht): If we don't want to use oslo.config global object # we can set the paste "oslo_config_project" and the middleware # will load the configuration with a local oslo.config object. self._local_oslo_config = None if "oslo_config_project" in conf: if "oslo_config_file" in conf: default_config_files = [conf["oslo_config_file"]] else: default_config_files = None self._local_oslo_config = cfg.ConfigOpts() self._local_oslo_config( {}, project=conf["oslo_config_project"], default_config_files=default_config_files, validate_default_values=True, ) self._local_oslo_config.register_opts(_OPTS, group=_base.AUTHTOKEN_GROUP) auth.register_conf_options(self._local_oslo_config, group=_base.AUTHTOKEN_GROUP) # tomograph.annotate("call super", "AuthProtocol") super(AuthProtocol, self).__init__(app, log=log, enforce_token_bind=self._conf_get("enforce_token_bind")) # delay_auth_decision means we still allow unauthenticated requests # through and we let the downstream service make the final decision self._delay_auth_decision = self._conf_get("delay_auth_decision") self._include_service_catalog = self._conf_get("include_service_catalog") self._hash_algorithms = self._conf_get("hash_algorithms") # tomograph.annotate("create identity server", "AuthProtocol") self._identity_server = self._create_identity_server() self._auth_uri = self._conf_get("auth_uri") if not self._auth_uri: self.log.warning( _LW( "Configuring auth_uri to point to the public identity " "endpoint is required; clients may not be able to " "authenticate against an admin endpoint" ) ) # FIXME(dolph): drop support for this fallback behavior as # documented in bug 1207517. self._auth_uri = self._identity_server.auth_uri self._signing_directory = _signing_dir.SigningDirectory( directory_name=self._conf_get("signing_dir"), log=self.log ) self._token_cache = self._token_cache_factory() revocation_cache_timeout = datetime.timedelta(seconds=self._conf_get("revocation_cache_time")) self._revocations = _revocations.Revocations( revocation_cache_timeout, self._signing_directory, self._identity_server, self._cms_verify, self.log ) self._check_revocations_for_cached = self._conf_get("check_revocations_for_cached")
def process_request(self, request): """Process request. If this method returns a value then that value will be used as the response. The next application down the stack will not be executed and process_response will not be called. Otherwise, the next application down the stack will be executed and process_response will be called with the generated response. By default this method does not return a value. :param request: Incoming request :type request: _request.AuthTokenRequest """ user_auth_ref = None serv_auth_ref = None allow_expired = False if request.service_token: self.log.debug('Authenticating service token') try: _, serv_auth_ref = self._do_fetch_token(request.service_token) self._validate_token(serv_auth_ref) self._confirm_token_bind(serv_auth_ref, request) except ksm_exceptions.InvalidToken: self.log.info(_LI('Invalid service token')) request.service_token_valid = False else: # FIXME(jamielennox): The new behaviour for service tokens is # that they have to pass the policy check to be allowed. # Previously any token was accepted here. For now we will # continue to mark service tokens as valid if they are valid # but we will only allow service role tokens to do # allow_expired. In future we should reject any token that # isn't a service token here. role_names = set(serv_auth_ref.role_names) check = self._service_token_roles.intersection(role_names) role_check_passed = bool(check) # if service_token_role_required then the service token is only # valid if the roles check out. Otherwise at this point it is # true because keystone has already validated it. if self._service_token_roles_required: request.service_token_valid = role_check_passed else: if not self._service_token_warning_emitted: self.log.warning( _LW('A valid token was submitted as ' 'a service token, but it was not ' 'a valid service token. This is ' 'incorrect but backwards ' 'compatible behaviour. This will ' 'be removed in future releases.')) # prevent log spam on every single request self._service_token_warning_emitted = True request.service_token_valid = True # allow_expired always requires passing the role check. allow_expired = role_check_passed if request.user_token: self.log.debug('Authenticating user token') try: data, user_auth_ref = self._do_fetch_token( request.user_token, allow_expired=allow_expired) self._validate_token(user_auth_ref, allow_expired=allow_expired) if not request.service_token: self._confirm_token_bind(user_auth_ref, request) except ksm_exceptions.InvalidToken: self.log.info(_LI('Invalid user token')) request.user_token_valid = False else: request.user_token_valid = True request.token_info = data request.token_auth = _user_plugin.UserAuthPlugin( user_auth_ref, serv_auth_ref)
def _validate_token(self, token, env): """Authenticate user token :param token: token id :param env: wsgi environment :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) expires = _get_token_expiration(data) _confirm_token_not_expired(expires) else: data = self._identity_server.verify_token(token) # 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): self._LOG.debug('Token validation failure.', exc_info=True) self._LOG.warn(_LW('Authorization failed for token')) raise exc.InvalidToken(_('Token authorization failed')) except exc.ServiceError: raise except Exception: self._LOG.debug('Token validation failure.', exc_info=True) if token_id: self._token_cache.store_invalid(token_id) self._LOG.warn(_LW('Authorization failed for token')) raise exc.InvalidToken(_('Token authorization failed'))