diff options
Diffstat (limited to 'keystonemiddleware/auth_token/__init__.py')
-rw-r--r-- | keystonemiddleware/auth_token/__init__.py | 147 |
1 files changed, 6 insertions, 141 deletions
diff --git a/keystonemiddleware/auth_token/__init__.py b/keystonemiddleware/auth_token/__init__.py index 6041e9e..dcf166b 100644 --- a/keystonemiddleware/auth_token/__init__.py +++ b/keystonemiddleware/auth_token/__init__.py @@ -217,7 +217,6 @@ object is stored. """ -import binascii import copy from keystoneauth1 import access @@ -226,8 +225,6 @@ from keystoneauth1 import discover from keystoneauth1 import exceptions as ksa_exceptions from keystoneauth1 import loading from keystoneauth1.loading import session as session_loading -from keystoneclient.common import cms -from keystoneclient import exceptions as ksc_exceptions import oslo_cache from oslo_config import cfg from oslo_log import log as logging @@ -242,7 +239,6 @@ from keystonemiddleware.auth_token import _exceptions as ksm_exceptions from keystonemiddleware.auth_token import _identity from keystonemiddleware.auth_token import _opts from keystonemiddleware.auth_token import _request -from keystonemiddleware.auth_token import _signing_dir from keystonemiddleware.auth_token import _user_plugin from keystonemiddleware.i18n import _ @@ -289,16 +285,6 @@ class _BIND_MODE(object): KERBEROS = 'kerberos' -def _uncompress_pkiz(token): - # TypeError If the signed_text is not zlib compressed binascii.Error if - # signed_text has incorrect base64 padding (py34) - - try: - return cms.pkiz_uncompress(token) - except (TypeError, binascii.Error): - raise ksm_exceptions.InvalidToken(token) - - class BaseAuthProtocol(object): """A base class for AuthProtocol token checking implementations. @@ -534,9 +520,6 @@ class BaseAuthProtocol(object): class AuthProtocol(BaseAuthProtocol): """Middleware that handles authenticating client calls.""" - _SIGNING_CERT_FILE_NAME = 'signing_cert.pem' - _SIGNING_CA_FILE_NAME = 'cacert.pem' - def __init__(self, app, conf): log = logging.getLogger(conf.get('log_name', __name__)) log.info('Starting Keystone auth_token middleware') @@ -568,9 +551,7 @@ class AuthProtocol(BaseAuthProtocol): 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._interface = self._conf.get('interface') - self._auth = self._create_auth_plugin() self._session = self._create_session() self._identity_server = self._create_identity_server() @@ -590,9 +571,6 @@ class AuthProtocol(BaseAuthProtocol): self._www_authenticate_uri = \ self._identity_server.www_authenticate_uri - self._signing_directory = _signing_dir.SigningDirectory( - directory_name=self._conf.get('signing_dir'), log=self.log) - self._token_cache = self._token_cache_factory() def process_request(self, request): @@ -674,37 +652,6 @@ class AuthProtocol(BaseAuthProtocol): header_val = 'Keystone uri="%s"' % self._www_authenticate_uri return [('WWW-Authenticate', header_val)] - def _token_hashes(self, token): - """Generate a list of hashes that the current token may be cached as. - - The first element of this list is the preferred algorithm and is what - new cache values should be saved as. - - :param str token: The token being presented by a user. - - :returns: list of str token hashes. - """ - if cms.is_asn1_token(token) or cms.is_pkiz(token): - return list(cms.cms_hash_token(token, mode=algo) - for algo in self._hash_algorithms) - else: - return [token] - - def _cache_get_hashes(self, token_hashes): - """Check if the token is cached already. - - Functions takes a list of hashes that might be in the cache and matches - the first one that is present. If nothing is found in the cache it - returns None. - - :returns: token data if found else None. - """ - for token in token_hashes: - cached = self._token_cache.get(token) - - if cached: - return cached - def fetch_token(self, token, allow_expired=False): """Retrieve a token from either a PKI bundle or the identity server. @@ -713,11 +660,8 @@ class AuthProtocol(BaseAuthProtocol): :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) + cached = self._token_cache.get(token) if cached: if cached == _CACHE_INVALID_INDICATOR: @@ -733,13 +677,11 @@ class AuthProtocol(BaseAuthProtocol): data = cached else: - data = self._validate_offline(token, token_hashes) - if not data: - data = self._identity_server.verify_token( - token, - allow_expired=allow_expired) + data = self._identity_server.verify_token( + token, + allow_expired=allow_expired) - self._token_cache.set(token_hashes[0], data) + self._token_cache.set(token, data) except (ksa_exceptions.ConnectFailure, ksa_exceptions.DiscoveryFailure, @@ -755,9 +697,7 @@ class AuthProtocol(BaseAuthProtocol): 'The Keystone service is temporarily unavailable.') 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._token_cache.set(token, _CACHE_INVALID_INDICATOR) self.log.warning('Authorization failed for token') raise except ksa_exceptions.EndpointNotFound: @@ -767,34 +707,6 @@ class AuthProtocol(BaseAuthProtocol): return data - 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: - verified = self._cms_verify(token_data, inform) - except ksc_exceptions.CertificateConfigError: - self.log.warning('Fetch certificate config failed, ' - 'fallback to online validation.') - else: - self.log.warning('auth_token middleware received a PKI/Z token. ' - 'This form of token is deprecated and has been ' - 'removed from keystone server and will be ' - 'removed from auth_token middleware in the Rocky ' - 'release. Please contact your administrator ' - 'about upgrading keystone and the token format.') - - data = jsonutils.loads(verified) - - return data - def _validate_token(self, auth_ref, **kwargs): super(AuthProtocol, self)._validate_token(auth_ref, **kwargs) @@ -802,53 +714,6 @@ class AuthProtocol(BaseAuthProtocol): msg = _('Unable to determine service tenancy.') raise ksm_exceptions.InvalidToken(msg) - def _cms_verify(self, data, inform=cms.PKI_ASN1_FORM): - """Verify the signature of the provided data's IAW CMS syntax. - - If either of the certificate files might be missing, fetch them and - retry. - """ - 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 (ksc_exceptions.CMSError, - cms.subprocess.CalledProcessError) as err: - self.log.warning('Verify error: %s', err) - msg = _('Token authorization failed') - raise ksm_exceptions.InvalidToken(msg) - - try: - return verify() - except ksc_exceptions.CertificateConfigError: - # the certs might be missing; unconditionally fetch to avoid racing - self._fetch_signing_cert() - self._fetch_ca_cert() - - try: - # retry with certs in place - return verify() - except ksc_exceptions.CertificateConfigError as err: - # if this is still occurring, something else is wrong and we - # need err.output to identify the problem - self.log.error('CMS Verify output: %s', err.output) - raise - - def _fetch_signing_cert(self): - self._signing_directory.write_file( - self._SIGNING_CERT_FILE_NAME, - self._identity_server.fetch_signing_cert()) - - def _fetch_ca_cert(self): - self._signing_directory.write_file( - self._SIGNING_CA_FILE_NAME, - self._identity_server.fetch_ca_cert()) - def _create_auth_plugin(self): # NOTE(jamielennox): Ideally this would use load_from_conf_options # however that is not possible because we have to support the override |