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 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 _confirm_token_bind(self, auth_ref, req): if self._enforce_token_bind == _BIND_MODE.DISABLED: return try: if auth_ref.version == "v2.0": bind = auth_ref["token"]["bind"] elif auth_ref.version == "v3": bind = auth_ref["bind"] else: self._invalid_user_token() except KeyError: bind = {} # permissive and strict modes don't require there to be a bind permissive = self._enforce_token_bind in (_BIND_MODE.PERMISSIVE, _BIND_MODE.STRICT) if not bind: if permissive: # no bind provided and none required return else: self.log.info(_LI("No bind information present in token.")) self._invalid_user_token() # get the named mode if bind_mode is not one of the predefined if permissive or self._enforce_token_bind == _BIND_MODE.REQUIRED: name = None else: name = self._enforce_token_bind if name and name not in bind: self.log.info(_LI("Named bind mode %s not in bind information"), name) self._invalid_user_token() for bind_type, identifier in six.iteritems(bind): if bind_type == _BIND_MODE.KERBEROS: if req.auth_type != "negotiate": self.log.info(_LI("Kerberos credentials required and " "not present.")) self._invalid_user_token() if req.remote_user != identifier: self.log.info(_LI("Kerberos credentials do not match " "those in bind.")) self._invalid_user_token() self.log.debug("Kerberos bind authentication successful.") elif self._enforce_token_bind == _BIND_MODE.PERMISSIVE: self.log.debug( "Ignoring Unknown bind for permissive mode: " "%(bind_type)s: %(identifier)s.", {"bind_type": bind_type, "identifier": identifier}, ) else: self.log.info( _LI("Couldn`t verify unknown bind: %(bind_type)s: " "%(identifier)s."), {"bind_type": bind_type, "identifier": identifier}, ) self._invalid_user_token()
def _confirm_token_bind(self, auth_ref, req): if self._enforce_token_bind == _BIND_MODE.DISABLED: return # permissive and strict modes don't require there to be a bind permissive = self._enforce_token_bind in (_BIND_MODE.PERMISSIVE, _BIND_MODE.STRICT) if not auth_ref.bind: if permissive: # no bind provided and none required return else: self.log.info(_LI('No bind information present in token.')) self._invalid_user_token() # get the named mode if bind_mode is not one of the predefined if permissive or self._enforce_token_bind == _BIND_MODE.REQUIRED: name = None else: name = self._enforce_token_bind if name and name not in auth_ref.bind: self.log.info(_LI('Named bind mode %s not in bind information'), name) self._invalid_user_token() for bind_type, identifier in six.iteritems(auth_ref.bind): if bind_type == _BIND_MODE.KERBEROS: if req.auth_type != 'negotiate': self.log.info( _LI('Kerberos credentials required and ' 'not present.')) self._invalid_user_token() if req.remote_user != identifier: self.log.info( _LI('Kerberos credentials do not match ' 'those in bind.')) self._invalid_user_token() self.log.debug('Kerberos bind authentication successful.') elif self._enforce_token_bind == _BIND_MODE.PERMISSIVE: self.log.debug( 'Ignoring Unknown bind for permissive mode: ' '%(bind_type)s: %(identifier)s.', { 'bind_type': bind_type, 'identifier': identifier }) else: self.log.info( _LI('Couldn`t verify unknown bind: %(bind_type)s: ' '%(identifier)s.'), { 'bind_type': bind_type, 'identifier': identifier }) self._invalid_user_token()
def process_request(self, request): """Process request. Evaluate the headers in a request and attempt to authenticate the request. If authenticated then additional headers are added to the request for use by applications. If not authenticated the request will be rejected or marked unauthenticated depending on configuration. """ request.remove_auth_headers() self._token_cache.initialize(request.environ) resp = super(AuthProtocol, self).process_request(request) if resp: return resp if not request.user_token: # if no user token is present then that's an invalid request request.user_token_valid = False # NOTE(jamielennox): The service status is allowed to be missing if a # service token is not passed. If the service status is missing that's # a valid request. We should find a better way to expose this from the # request object. user_status = request.user_token and request.user_token_valid service_status = request.headers.get('X-Service-Identity-Status', 'Confirmed') if not (user_status and service_status == 'Confirmed'): if self._delay_auth_decision: self.log.info(_LI('Deferring reject downstream')) else: self.log.info(_LI('Rejecting request')) message = 'The request you have made requires authentication.' body = { 'error': { 'code': 401, 'title': 'Unauthorized', 'message': message, } } raise webob.exc.HTTPUnauthorized( body=jsonutils.dumps(body), headers=self._reject_auth_headers, content_type='application/json') if request.user_token_valid: request.set_user_headers(request.token_auth.user) if self._include_service_catalog: request.set_service_catalog_headers(request.token_auth.user) if request.service_token and request.service_token_valid: request.set_service_headers(request.token_auth.service) if self.log.isEnabledFor(logging.DEBUG): self.log.debug('Received request from %s', request.token_auth._log_format)
def process_request(self, request): """Process request. Evaluate the headers in a request and attempt to authenticate the request. If authenticated then additional headers are added to the request for use by applications. If not authenticated the request will be rejected or marked unauthenticated depending on configuration. """ request.remove_auth_headers() self._token_cache.initialize(request.environ) resp = super(AuthProtocol, self).process_request(request) if resp: return resp if not request.user_token: # if no user token is present then that's an invalid request request.user_token_valid = False # NOTE(jamielennox): The service status is allowed to be missing if a # service token is not passed. If the service status is missing that's # a valid request. We should find a better way to expose this from the # request object. user_status = request.user_token and request.user_token_valid service_status = request.headers.get('X-Service-Identity-Status', 'Confirmed') if not (user_status and service_status == 'Confirmed'): if self._delay_auth_decision: self.log.info(_LI('Deferring reject downstream')) else: self.log.info(_LI('Rejecting request')) message = 'The request you have made requires authentication.' body = {'error': { 'code': 401, 'title': 'Unauthorized', 'message': message, }} raise webob.exc.HTTPUnauthorized( body=jsonutils.dumps(body), headers=self._reject_auth_headers, content_type='application/json') if request.user_token_valid: user_auth_ref = request.token_auth._user_auth_ref request.set_user_headers(user_auth_ref) if self._include_service_catalog: request.set_service_catalog_headers(user_auth_ref) if request.service_token and request.service_token_valid: request.set_service_headers(request.token_auth._serv_auth_ref) if self.log.isEnabledFor(logging.DEBUG): self.log.debug('Received request from %s', request.token_auth._log_format)
def _confirm_token_bind(self, auth_ref, req): if self._enforce_token_bind == _BIND_MODE.DISABLED: return # permissive and strict modes don't require there to be a bind permissive = self._enforce_token_bind in (_BIND_MODE.PERMISSIVE, _BIND_MODE.STRICT) if not auth_ref.bind: if permissive: # no bind provided and none required return else: self.log.info(_LI('No bind information present in token.')) self._invalid_user_token() # get the named mode if bind_mode is not one of the predefined if permissive or self._enforce_token_bind == _BIND_MODE.REQUIRED: name = None else: name = self._enforce_token_bind if name and name not in auth_ref.bind: self.log.info(_LI('Named bind mode %s not in bind information'), name) self._invalid_user_token() for bind_type, identifier in six.iteritems(auth_ref.bind): if bind_type == _BIND_MODE.KERBEROS: if req.auth_type != 'negotiate': self.log.info(_LI('Kerberos credentials required and ' 'not present.')) self._invalid_user_token() if req.remote_user != identifier: self.log.info(_LI('Kerberos credentials do not match ' 'those in bind.')) self._invalid_user_token() self.log.debug('Kerberos bind authentication successful.') elif self._enforce_token_bind == _BIND_MODE.PERMISSIVE: self.log.debug('Ignoring Unknown bind for permissive mode: ' '%(bind_type)s: %(identifier)s.', {'bind_type': bind_type, 'identifier': identifier}) else: self.log.info( _LI('Couldn`t verify unknown bind: %(bind_type)s: ' '%(identifier)s.'), {'bind_type': bind_type, 'identifier': identifier}) self._invalid_user_token()
def process_request(self, request): """Process request. Evaluate the headers in a request and attempt to authenticate the request against the identity server. If authenticated then additional headers are added to the request for use by applications. If not authenticated the request will be rejected or marked unauthenticated depending on configuration. """ # pdb.set_trace() tomograph.start_http( "keystonemiddleware.auth_token.AuthProtocol[process_request]", "process_request", request) tomograph.add_trace_info_header(request.headers) self._token_cache.initialize(request.environ) resp = super(AuthProtocol, self).process_request(request) tomograph.stop("process_request") if resp: return resp if not request.user_token: # if no user token is present then that's an invalid request request.user_token_valid = False # NOTE(jamielennox): The service status is allowed to be missing if a # service token is not passed. If the service status is missing that's # a valid request. We should find a better way to expose this from the # request object. user_status = request.user_token and request.user_token_valid service_status = request.headers.get('X-Service-Identity-Status', 'Confirmed') if not (user_status and service_status == 'Confirmed'): if self._delay_auth_decision: self.log.info(_LI('Deferring reject downstream')) else: self.log.info(_LI('Rejecting request')) self._reject_request() if request.user_token_valid: request.set_user_headers(request.token_auth._user_auth_ref, self._include_service_catalog) if request.service_token and request.service_token_valid: request.set_service_headers(request.token_auth._serv_auth_ref) if self.log.isEnabledFor(logging.DEBUG): self.log.debug('Received request from %s', request.token_auth._log_format)
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 if request.user_token: self.log.debug('Authenticating user token') try: data, user_auth_ref = self._do_fetch_token(request.user_token) self.log.debug('XXX JD Fetched user token') self._validate_token(user_auth_ref) self.log.debug('XXX JD Validated user token') self._confirm_token_bind(user_auth_ref, request) self.log.debug('XXX JD Confirmed user token') 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 self.log.debug('XXX JD Authenticated user token') 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: request.service_token_valid = True request.token_auth = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref)
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 """ request.remove_auth_headers() user_auth_ref = None serv_auth_ref = None if request.user_token: self.log.debug('Authenticating user token') try: data, user_auth_ref = self._do_fetch_token(request.user_token) self._validate_token(user_auth_ref) self._confirm_token_bind(user_auth_ref, request) except exc.InvalidToken: self.log.info(_LI('Invalid user token')) request.user_token_valid = False else: request.user_token_valid = True request.environ['keystone.token_info'] = data 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 exc.InvalidToken: self.log.info(_LI('Invalid service token')) request.service_token_valid = False else: request.service_token_valid = True p = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref) request.environ['keystone.token_auth'] = p
def process_request(self, request): """Process request. Evaluate the headers in a request and attempt to authenticate the request against the identity server. If authenticated then additional headers are added to the request for use by applications. If not authenticated the request will be rejected or marked unauthenticated depending on configuration. """ # pdb.set_trace() tomograph.start_http("keystonemiddleware.auth_token.AuthProtocol[process_request]", "process_request", request) tomograph.add_trace_info_header(request.headers) self._token_cache.initialize(request.environ) resp = super(AuthProtocol, self).process_request(request) tomograph.stop("process_request") if resp: return resp if not request.user_token: # if no user token is present then that's an invalid request request.user_token_valid = False # NOTE(jamielennox): The service status is allowed to be missing if a # service token is not passed. If the service status is missing that's # a valid request. We should find a better way to expose this from the # request object. user_status = request.user_token and request.user_token_valid service_status = request.headers.get("X-Service-Identity-Status", "Confirmed") if not (user_status and service_status == "Confirmed"): if self._delay_auth_decision: self.log.info(_LI("Deferring reject downstream")) else: self.log.info(_LI("Rejecting request")) self._reject_request() if request.user_token_valid: request.set_user_headers(request.token_auth._user_auth_ref, self._include_service_catalog) if request.service_token and request.service_token_valid: request.set_service_headers(request.token_auth._serv_auth_ref) if self.log.isEnabledFor(logging.DEBUG): self.log.debug("Received request from %s", request.token_auth._log_format)
def _lazy_create_signing_dir(self): if self._directory_name is None: self._directory_name = tempfile.mkdtemp(prefix='keystone-signing-') self._log.info( _LI('Using %s as cache directory for signing certificate'), self._directory_name) self._verify_signing_dir()
def _get_authz_from_moon(self, tenant_id, subject_id, object_id, action_id): try: _url ='{}/v3/OS-MOON/authz/{}/{}/{}/{}'.format( self._request_uri, tenant_id, subject_id, object_id, action_id) self._LOG.info(_url) response = requests.get(_url,verify=self._verify) except requests.exceptions.RequestException as e: self._LOG.error(_LI('HTTP connection exception: %s'), e) resp = self._deny_request('InvalidURI') raise ServiceError(resp) if response.status_code < 200 or response.status_code >= 300: self._LOG.debug('Keystone reply error: status=%s reason=%s', response.status_code, response.reason) if response.status_code == 404: resp = self._deny_request('NotFound') elif response.status_code == 401: resp = self._deny_request('AccessDenied') else: resp = self._deny_request('Error') raise ServiceError(resp) return response
def __init__(self, app, conf): self._LOG = logging.getLogger(conf.get('log_name', __name__)) # FIXME: events are duplicated in log file authz_fh = logging.FileHandler(CONF.keystone_authz["logfile"]) self._LOG.setLevel(logging.DEBUG) self._LOG.addHandler(authz_fh) self._LOG.info(_LI('Starting Keystone authz middleware')) self._conf = conf self._app = app # MOON self.auth_host = conf.get('auth_host', "127.0.0.1") self.auth_port = int(conf.get('auth_port', 35357)) auth_protocol = conf.get('auth_protocol', 'http') self._request_uri = '%s://%s:%s' % (auth_protocol, self.auth_host, self.auth_port) # SSL insecure = 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 notify(self, context, event_type, payload): self._log.info( _LI('Event type: %(event_type)s, Context: %(context)s, ' 'Payload: %(payload)s'), { 'context': context, 'event_type': event_type, 'payload': payload })
def __init__(self, directory_name=None, log=None): self._log = log or _LOG self._directory_name = directory_name if self._directory_name: self._log.info( _LI('Using %s as cache directory for signing certificate'), self._directory_name) self._verify_signing_dir()
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. """ request.remove_auth_headers() user_auth_ref = None serv_auth_ref = None if request.user_token: self.log.debug("Authenticating user token") try: data, user_auth_ref = self._do_fetch_token(request.user_token) self._validate_token(user_auth_ref) self._confirm_token_bind(user_auth_ref, request) except exc.InvalidToken: self.log.info(_LI("Invalid user token")) request.user_token_valid = False else: request.user_token_valid = True request.environ["keystone.token_info"] = data 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 exc.InvalidToken: self.log.info(_LI("Invalid service token")) request.service_token_valid = False else: request.service_token_valid = True p = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref) request.environ["keystone.token_auth"] = p
def __init__(self, directory_name=None, log=None): self._log = log or _LOG if directory_name is None: directory_name = tempfile.mkdtemp(prefix='keystone-signing-') self._log.info( _LI('Using %s as cache directory for signing certificate'), directory_name) self._directory_name = directory_name self._verify_signing_dir()
def _emit_audit(self, context, event_type, payload): """Emit audit notification if oslo.messaging enabled, send notification. if not, log event. """ if messaging: self._notifier.info(context, event_type, payload) else: _LOG.info(_LI('Event type: %(event_type)s, Context: %(context)s, ' 'Payload: %(payload)s'), {'context': context, 'event_type': event_type, 'payload': payload})
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 __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 __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 treat_request(self, auth_token, agent_data): if not agent_data['resource_id']: agent_data['resource_id'] = "servers" headers = {'X-Auth-Token': auth_token} self._LOG.debug('X-Auth-Token={}'.format(auth_token)) try: _url = '{}/moon/authz/{}/{}/{}/{}'.format( self.conf["_request_uri"], agent_data['tenant_id'], agent_data['user_id'], agent_data['resource_id'], agent_data['action_id']) self._LOG.info(_url) response = requests.get(_url, headers=headers, verify=self.conf["_verify"]) except requests.exceptions.RequestException as e: self._LOG.error(_LI('HTTP connection exception: %s'), e) resp = self._deny_request('InvalidURI') raise ServiceError(resp) if response.status_code < 200 or response.status_code >= 300: self._LOG.debug('Keystone reply error: status=%s reason=%s', response.status_code, response.reason) if response.status_code == 404: resp = self._deny_request('NotFound') elif response.status_code == 401: resp = self._deny_request('AccessDenied') else: resp = self._deny_request('Error') raise ServiceError(resp) elif response.status_code == 200: answer = json.loads(response.content) self._LOG.debug("action_id={}/{}".format( agent_data['OS_component'], agent_data['action_id'])) self._LOG.debug(answer) if "authz" in answer and answer["authz"]: return response self._LOG.error("You are not authorized to do that! ({})".format( unicode(answer["comment"]))) raise exception.Unauthorized( message="You are not authorized to do that! ({})".format( unicode(answer["comment"]))) else: self._LOG.error("Unable to request Moon ({}: {})".format( response.status_code, response.reason)) return response
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 _json_request(self, creds_json): headers = {'Content-Type': 'application/json'} try: response = requests.post('%s/v2.0/s3tokens' % self._request_uri, headers=headers, data=creds_json, verify=self._verify) except requests.exceptions.RequestException as e: self._logger.info(_LI('HTTP connection exception: %s'), e) resp = self._deny_request('InvalidURI') raise ServiceError(resp) if response.status_code < 200 or response.status_code >= 300: self._logger.debug('Keystone reply error: status=%s reason=%s', response.status_code, response.reason) resp = self._deny_request('AccessDenied') raise ServiceError(resp) return response
def _get_strategy_class(self): if self._requested_auth_version: # A specific version was requested. if discover.version_match(_V3RequestStrategy.AUTH_VERSION, self._requested_auth_version): return _V3RequestStrategy # The version isn't v3 so we don't know what to do. Just assume V2. return _V2RequestStrategy # Specific version was not requested then we fall through to # discovering available versions from the server for klass in _REQUEST_STRATEGIES: if self._adapter.get_endpoint(version=klass.AUTH_VERSION): msg = _LI('Auth Token confirmed use of %s apis') self._LOG.info(msg, self._requested_auth_version) return klass versions = ['v%d.%d' % s.AUTH_VERSION for s in _REQUEST_STRATEGIES] self._LOG.error(_LE('No attempted versions [%s] supported by server'), ', '.join(versions)) msg = _('No compatible apis supported by server') raise exc.ServiceError(msg)
def __init__(self, app, conf): self.conf = conf self._LOG = logging.getLogger(conf.get('log_name', __name__)) # FIXME: events are duplicated in log file moon_agent_fh = logging.FileHandler(self.conf.get('logfile', "/tmp/keystonemiddleware.log")) self._LOG.setLevel(logging.DEBUG) self._LOG.addHandler(moon_agent_fh) self._LOG.info(_LI('Starting Moon KeystoneMiddleware Agent')) self._conf = conf self._app = app # Auth self.auth_host = conf.get('auth_host', "127.0.0.1") self.auth_port = int(conf.get('auth_port', 35357)) auth_protocol = conf.get('auth_protocol', 'http') self._conf["_request_uri"] = '%s://%s:%s' % (auth_protocol, self.auth_host, # TODO: ??? for auth or authz self.auth_port) # SSL insecure = conf.get('insecure', False) cert_file = conf.get('certfile') key_file = conf.get('keyfile') if insecure: self._conf["_verify"] = False elif cert_file and key_file: self._conf["_verify"] = (cert_file, key_file) elif cert_file: self._conf["_verify"] = cert_file else: self._conf["_verify"] = None # Moon registered mgrs self.local_registered_mgr_dict = dict() # TODO: load from the sql backend from keystonemiddleware.moon_mgrs.authz_mgr.authz_mgr import AuthzMgr self.local_registered_mgr_dict["authz_mgr"] = AuthzMgr(self._conf)
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 process_request(self, request): """Process request. Evaluate the headers in a request and attempt to authenticate the request against the identity server. If authenticated then additional headers are added to the request for use by applications. If not authenticated the request will be rejected or marked unauthenticated depending on configuration. """ self._token_cache.initialize(request.environ) request.remove_auth_headers() user_auth_ref = None serv_auth_ref = None self.log.debug('Authenticating user token') try: user_token = self._get_user_token_from_request(request) data, user_auth_ref = self._do_fetch_token(user_token) self._validate_token(user_auth_ref) self._confirm_token_bind(user_auth_ref, request) except exc.InvalidToken: if self._delay_auth_decision: self.log.info( _LI('Invalid user token - deferring reject ' 'downstream')) request.user_token_valid = False else: self.log.info( _LI('Invalid user token - rejecting request')) self._reject_request() else: request.environ['keystone.token_info'] = data request.set_user_headers(user_auth_ref, self._include_service_catalog) if request.service_token is not None: self.log.debug('Authenticating service token') try: _ignore, 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 exc.InvalidToken: if self._delay_auth_decision: self.log.info( _LI('Invalid service token - deferring reject ' 'downstream')) request.service_token_valid = False else: self.log.info( _LI('Invalid service token - rejecting request')) self._reject_request() else: request.set_service_headers(serv_auth_ref) request.token_auth = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref) if self.log.isEnabledFor(logging.DEBUG): self.log.debug('Received request from %s' % request.token_auth._log_format)
def _confirm_token_bind(self, data, env): bind_mode = self._conf_get('enforce_token_bind') if bind_mode == _BIND_MODE.DISABLED: return try: if _token_is_v2(data): bind = data['access']['token']['bind'] elif _token_is_v3(data): bind = data['token']['bind'] else: self._invalid_user_token() except KeyError: bind = {} # permissive and strict modes don't require there to be a bind permissive = bind_mode in (_BIND_MODE.PERMISSIVE, _BIND_MODE.STRICT) if not bind: if permissive: # no bind provided and none required return else: self._LOG.info(_LI('No bind information present in token.')) self._invalid_user_token() # get the named mode if bind_mode is not one of the predefined if permissive or bind_mode == _BIND_MODE.REQUIRED: name = None else: name = bind_mode if name and name not in bind: self._LOG.info(_LI('Named bind mode %s not in bind information'), name) self._invalid_user_token() for bind_type, identifier in six.iteritems(bind): if bind_type == _BIND_MODE.KERBEROS: if not env.get('AUTH_TYPE', '').lower() == 'negotiate': self._LOG.info(_LI('Kerberos credentials required and ' 'not present.')) self._invalid_user_token() if not env.get('REMOTE_USER') == identifier: self._LOG.info(_LI('Kerberos credentials do not match ' 'those in bind.')) self._invalid_user_token() self._LOG.debug('Kerberos bind authentication successful.') elif bind_mode == _BIND_MODE.PERMISSIVE: self._LOG.debug('Ignoring Unknown bind for permissive mode: ' '%(bind_type)s: %(identifier)s.', {'bind_type': bind_type, 'identifier': identifier}) else: self._LOG.info( _LI('Couldn`t verify unknown bind: %(bind_type)s: ' '%(identifier)s.'), {'bind_type': bind_type, 'identifier': identifier}) self._invalid_user_token()
def __call__(self, env, start_response): """Handle incoming request. Authenticate send downstream on success. Reject request if we can't authenticate. """ def _fmt_msg(env): msg = ('user: user_id %s, project_id %s, roles %s ' 'service: user_id %s, project_id %s, roles %s' % ( env.get('HTTP_X_USER_ID'), env.get('HTTP_X_PROJECT_ID'), env.get('HTTP_X_ROLES'), env.get('HTTP_X_SERVICE_USER_ID'), env.get('HTTP_X_SERVICE_PROJECT_ID'), env.get('HTTP_X_SERVICE_ROLES'))) return msg self._token_cache.initialize(env) self._remove_auth_headers(env) try: user_auth_ref = None serv_auth_ref = None try: self._LOG.debug('Authenticating user token') user_token = self._get_user_token_from_header(env) user_token_info = self._validate_token(user_token, env) user_auth_ref = access.AccessInfo.factory( body=user_token_info, auth_token=user_token) env['keystone.token_info'] = user_token_info user_headers = self._build_user_headers(user_auth_ref, user_token_info) self._add_headers(env, user_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid user token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid user token - rejecting request')) return self._reject_request(env, start_response) try: self._LOG.debug('Authenticating service token') serv_token = self._get_service_token_from_header(env) if serv_token is not None: serv_token_info = self._validate_token( serv_token, env) serv_auth_ref = access.AccessInfo.factory( body=serv_token_info, auth_token=serv_token) serv_headers = self._build_service_headers(serv_token_info) self._add_headers(env, serv_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid service token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Service-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid service token - rejecting request')) return self._reject_request(env, start_response) env['keystone.token_auth'] = _user_plugin.UserAuthPlugin( user_auth_ref, serv_auth_ref) except exc.ServiceError as e: self._LOG.critical(_LC('Unable to obtain admin token: %s'), e) return self._do_503_error(env, start_response) except exc._InternalServiceError: return self._do_500_error(env, start_response) self._LOG.debug("Received request from %s", _fmt_msg(env)) return self._call_app(env, start_response)
def __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 __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 __call__(self, env, start_response): """Handle incoming request. Authenticate send downstream on success. Reject request if we can't authenticate. """ def _fmt_msg(env): msg = ('user: user_id %s, project_id %s, roles %s ' 'service: user_id %s, project_id %s, roles %s' % ( env.get('HTTP_X_USER_ID'), env.get('HTTP_X_PROJECT_ID'), env.get('HTTP_X_ROLES'), env.get('HTTP_X_SERVICE_USER_ID'), env.get('HTTP_X_SERVICE_PROJECT_ID'), env.get('HTTP_X_SERVICE_ROLES'))) return msg self._token_cache.initialize(env) self._remove_auth_headers(env) try: user_auth_ref = None serv_auth_ref = None try: self._LOG.debug('Authenticating user token') user_token = self._get_user_token_from_header(env) user_token_info = self._validate_token(user_token, env) user_auth_ref = access.AccessInfo.factory( body=user_token_info, auth_token=user_token) env['keystone.token_info'] = user_token_info user_headers = self._build_user_headers(user_auth_ref, user_token_info) self._add_headers(env, user_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid user token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid user token - rejecting request')) return self._reject_request(env, start_response) try: self._LOG.debug('Authenticating service token') serv_token = self._get_service_token_from_header(env) if serv_token is not None: serv_token_info = self._validate_token( serv_token, env) serv_auth_ref = access.AccessInfo.factory( body=serv_token_info, auth_token=serv_token) serv_headers = self._build_service_headers(serv_token_info) self._add_headers(env, serv_headers) except exc.InvalidToken: if self._delay_auth_decision: self._LOG.info( _LI('Invalid service token - deferring reject ' 'downstream')) self._add_headers(env, {'X-Service-Identity-Status': 'Invalid'}) else: self._LOG.info( _LI('Invalid service token - rejecting request')) return self._reject_request(env, start_response) env['keystone.token_auth'] = _user_plugin.UserAuthPlugin( user_auth_ref, serv_auth_ref) except exc.ServiceError as e: self._LOG.critical(_LC('Unable to obtain admin token: %s'), e) return self._do_503_error(env, start_response) self._LOG.debug("Received request from %s", _fmt_msg(env)) return self._call_app(env, start_response)
def __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