Пример #1
0
    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
Пример #2
0
    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()
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
 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)
Пример #7
0
 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)
Пример #8
0
    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
Пример #9
0
    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()
Пример #10
0
    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)
Пример #11
0
    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
Пример #12
0
    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)
Пример #13
0
    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()