Merge "Base use webob"
This commit is contained in:
commit
6f10b9c8e1
@ -212,6 +212,7 @@ from keystoneclient import session
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import six
|
import six
|
||||||
|
import webob.dec
|
||||||
|
|
||||||
from keystonemiddleware.auth_token import _auth
|
from keystonemiddleware.auth_token import _auth
|
||||||
from keystonemiddleware.auth_token import _base
|
from keystonemiddleware.auth_token import _base
|
||||||
@ -221,7 +222,6 @@ from keystonemiddleware.auth_token import _identity
|
|||||||
from keystonemiddleware.auth_token import _revocations
|
from keystonemiddleware.auth_token import _revocations
|
||||||
from keystonemiddleware.auth_token import _signing_dir
|
from keystonemiddleware.auth_token import _signing_dir
|
||||||
from keystonemiddleware.auth_token import _user_plugin
|
from keystonemiddleware.auth_token import _user_plugin
|
||||||
from keystonemiddleware.auth_token import _utils
|
|
||||||
from keystonemiddleware.i18n import _, _LC, _LE, _LI, _LW
|
from keystonemiddleware.i18n import _, _LC, _LE, _LI, _LW
|
||||||
|
|
||||||
|
|
||||||
@ -527,19 +527,8 @@ class AuthProtocol(object):
|
|||||||
else:
|
else:
|
||||||
return CONF[group][name]
|
return CONF[group][name]
|
||||||
|
|
||||||
def _call_app(self, env, start_response):
|
@webob.dec.wsgify
|
||||||
# NOTE(jamielennox): We wrap the given start response so that if an
|
def __call__(self, request):
|
||||||
# application with a 'delay_auth_decision' setting fails, or otherwise
|
|
||||||
# raises Unauthorized that we include the Authentication URL headers.
|
|
||||||
def _fake_start_response(status, response_headers, exc_info=None):
|
|
||||||
if status.startswith('401'):
|
|
||||||
response_headers.extend(self._reject_auth_headers)
|
|
||||||
|
|
||||||
return start_response(status, response_headers, exc_info)
|
|
||||||
|
|
||||||
return self._app(env, _fake_start_response)
|
|
||||||
|
|
||||||
def __call__(self, env, start_response):
|
|
||||||
"""Handle incoming request.
|
"""Handle incoming request.
|
||||||
|
|
||||||
Authenticate send downstream on success. Reject request if
|
Authenticate send downstream on success. Reject request if
|
||||||
@ -556,8 +545,8 @@ class AuthProtocol(object):
|
|||||||
env.get('HTTP_X_SERVICE_ROLES')))
|
env.get('HTTP_X_SERVICE_ROLES')))
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
self._token_cache.initialize(env)
|
self._token_cache.initialize(request.environ)
|
||||||
self._remove_auth_headers(env)
|
self._remove_auth_headers(request.environ)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user_auth_ref = None
|
user_auth_ref = None
|
||||||
@ -565,58 +554,61 @@ class AuthProtocol(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self._LOG.debug('Authenticating user token')
|
self._LOG.debug('Authenticating user token')
|
||||||
user_token_info = self._get_user_token_from_header(env)
|
user_token_info = self._get_user_token_from_header(
|
||||||
|
request.environ)
|
||||||
user_auth_ref, user_token_info = self._validate_token(
|
user_auth_ref, user_token_info = self._validate_token(
|
||||||
user_token_info, env)
|
user_token_info, request.environ)
|
||||||
env['keystone.token_info'] = user_token_info
|
request.environ['keystone.token_info'] = user_token_info
|
||||||
user_headers = self._build_user_headers(user_auth_ref)
|
user_headers = self._build_user_headers(user_auth_ref)
|
||||||
self._add_headers(env, user_headers)
|
self._add_headers(request.environ, user_headers)
|
||||||
except exc.InvalidToken:
|
except exc.InvalidToken:
|
||||||
if self._delay_auth_decision:
|
if self._delay_auth_decision:
|
||||||
self._LOG.info(
|
self._LOG.info(
|
||||||
_LI('Invalid user token - deferring reject '
|
_LI('Invalid user token - deferring reject '
|
||||||
'downstream'))
|
'downstream'))
|
||||||
self._add_headers(env, {'X-Identity-Status': 'Invalid'})
|
self._add_headers(request.environ,
|
||||||
|
{'X-Identity-Status': 'Invalid'})
|
||||||
else:
|
else:
|
||||||
self._LOG.info(
|
self._LOG.info(
|
||||||
_LI('Invalid user token - rejecting request'))
|
_LI('Invalid user token - rejecting request'))
|
||||||
return self._reject_request(env, start_response)
|
self._reject_request()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._LOG.debug('Authenticating service token')
|
self._LOG.debug('Authenticating service token')
|
||||||
serv_token = self._get_service_token_from_header(env)
|
serv_token = self._get_service_token_from_header(
|
||||||
|
request.environ)
|
||||||
if serv_token is not None:
|
if serv_token is not None:
|
||||||
serv_auth_ref, serv_token_info = self._validate_token(
|
serv_auth_ref, serv_token_info = self._validate_token(
|
||||||
serv_token, env)
|
serv_token, request.environ)
|
||||||
serv_headers = self._build_service_headers(serv_auth_ref)
|
serv_headers = self._build_service_headers(serv_auth_ref)
|
||||||
self._add_headers(env, serv_headers)
|
self._add_headers(request.environ, serv_headers)
|
||||||
except exc.InvalidToken:
|
except exc.InvalidToken:
|
||||||
if self._delay_auth_decision:
|
if self._delay_auth_decision:
|
||||||
self._LOG.info(
|
self._LOG.info(
|
||||||
_LI('Invalid service token - deferring reject '
|
_LI('Invalid service token - deferring reject '
|
||||||
'downstream'))
|
'downstream'))
|
||||||
self._add_headers(env,
|
self._add_headers(request.environ,
|
||||||
{'X-Service-Identity-Status': 'Invalid'})
|
{'X-Service-Identity-Status': 'Invalid'})
|
||||||
else:
|
else:
|
||||||
self._LOG.info(
|
self._LOG.info(
|
||||||
_LI('Invalid service token - rejecting request'))
|
_LI('Invalid service token - rejecting request'))
|
||||||
return self._reject_request(env, start_response)
|
self._reject_request()
|
||||||
|
|
||||||
env['keystone.token_auth'] = _user_plugin.UserAuthPlugin(
|
p = _user_plugin.UserAuthPlugin(user_auth_ref, serv_auth_ref)
|
||||||
user_auth_ref, serv_auth_ref)
|
request.environ['keystone.token_auth'] = p
|
||||||
|
|
||||||
except exc.ServiceError as e:
|
except exc.ServiceError as e:
|
||||||
self._LOG.critical(_LC('Unable to obtain admin token: %s'), e)
|
self._LOG.critical(_LC('Unable to obtain admin token: %s'), e)
|
||||||
return self._do_503_error(env, start_response)
|
raise webob.exc.HTTPServiceUnavailable()
|
||||||
|
|
||||||
self._LOG.debug("Received request from %s", _fmt_msg(env))
|
self._LOG.debug("Received request from %s", _fmt_msg(request.environ))
|
||||||
|
|
||||||
return self._call_app(env, start_response)
|
response = request.get_response(self._app)
|
||||||
|
|
||||||
def _do_503_error(self, env, start_response):
|
if response.status_int == 401:
|
||||||
resp = _utils.MiniResp('Service unavailable', env)
|
response.headers.extend(self._reject_auth_headers)
|
||||||
start_response('503 Service Unavailable', resp.headers)
|
|
||||||
return resp.body
|
return response
|
||||||
|
|
||||||
def _init_auth_headers(self):
|
def _init_auth_headers(self):
|
||||||
"""Initialize auth header list.
|
"""Initialize auth header list.
|
||||||
@ -683,7 +675,7 @@ class AuthProtocol(object):
|
|||||||
header_val = 'Keystone uri=\'%s\'' % self._auth_uri
|
header_val = 'Keystone uri=\'%s\'' % self._auth_uri
|
||||||
return [('WWW-Authenticate', header_val)]
|
return [('WWW-Authenticate', header_val)]
|
||||||
|
|
||||||
def _reject_request(self, env, start_response):
|
def _reject_request(self):
|
||||||
"""Redirect client to auth server.
|
"""Redirect client to auth server.
|
||||||
|
|
||||||
:param env: wsgi request environment
|
:param env: wsgi request environment
|
||||||
@ -691,10 +683,8 @@ class AuthProtocol(object):
|
|||||||
:returns: HTTPUnauthorized http response
|
:returns: HTTPUnauthorized http response
|
||||||
|
|
||||||
"""
|
"""
|
||||||
resp = _utils.MiniResp('Authentication required',
|
raise webob.exc.HTTPUnauthorized(body='Authentication required',
|
||||||
env, self._reject_auth_headers)
|
headers=self._reject_auth_headers)
|
||||||
start_response('401 Unauthorized', resp.headers)
|
|
||||||
return resp.body
|
|
||||||
|
|
||||||
def _token_hashes(self, token):
|
def _token_hashes(self, token):
|
||||||
"""Generate a list of hashes that the current token may be cached as.
|
"""Generate a list of hashes that the current token may be cached as.
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
|
|
||||||
class MiniResp(object):
|
|
||||||
|
|
||||||
def __init__(self, error_message, env, headers=[]):
|
|
||||||
# The HEAD method is unique: it must never return a body, even if
|
|
||||||
# it reports an error (RFC-2616 clause 9.4). We relieve callers
|
|
||||||
# from varying the error responses depending on the method.
|
|
||||||
if env['REQUEST_METHOD'] == 'HEAD':
|
|
||||||
self.body = ['']
|
|
||||||
else:
|
|
||||||
self.body = [error_message.encode()]
|
|
||||||
self.headers = list(headers)
|
|
||||||
self.headers.append(('Content-type', 'text/plain'))
|
|
@ -985,7 +985,6 @@ class CommonAuthTokenMiddlewareTest(object):
|
|||||||
self.assertEqual(401, resp.status_int)
|
self.assertEqual(401, resp.status_int)
|
||||||
self.assertEqual("Keystone uri='https://keystone.example.com:1234'",
|
self.assertEqual("Keystone uri='https://keystone.example.com:1234'",
|
||||||
resp.headers['WWW-Authenticate'])
|
resp.headers['WWW-Authenticate'])
|
||||||
self.assertEqual('', resp.body)
|
|
||||||
|
|
||||||
def test_request_blank_token(self):
|
def test_request_blank_token(self):
|
||||||
resp = self.call_middleware(headers={'X-Auth-Token': ''})
|
resp = self.call_middleware(headers={'X-Auth-Token': ''})
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import testtools
|
|
||||||
|
|
||||||
from keystonemiddleware.auth_token import _utils
|
|
||||||
|
|
||||||
|
|
||||||
class TokenEncodingTest(testtools.TestCase):
|
|
||||||
|
|
||||||
def test_messages_encoded_as_bytes(self):
|
|
||||||
"""Test that string are passed around as bytes for PY3."""
|
|
||||||
msg = "This is an error"
|
|
||||||
|
|
||||||
class FakeResp(_utils.MiniResp):
|
|
||||||
def __init__(self, error, env):
|
|
||||||
super(FakeResp, self).__init__(error, env)
|
|
||||||
|
|
||||||
fake_resp = FakeResp(msg, dict(REQUEST_METHOD='GET'))
|
|
||||||
# On Py2 .encode() don't do much but that's better than to
|
|
||||||
# have a ifdef with six.PY3
|
|
||||||
self.assertEqual(msg.encode(), fake_resp.body[0])
|
|
Loading…
x
Reference in New Issue
Block a user