Merge "Add delay_auth_decision config option"
This commit is contained in:
commit
aa90483ff0
@ -146,6 +146,11 @@ use = egg:swift3#s3token
|
||||
# Prefix that will be prepended to the tenant to form the account
|
||||
reseller_prefix = AUTH_
|
||||
|
||||
# By default, s3token will reject all invalid S3-style requests. Set this to
|
||||
# True to delegate that decision to downstream WSGI components. This may be
|
||||
# useful if there are multiple auth systems in the proxy pipeline.
|
||||
delay_auth_decision = False
|
||||
|
||||
# Keystone server details
|
||||
auth_uri = http://keystonehost:35357/
|
||||
|
||||
|
@ -63,8 +63,10 @@ class S3Token(object):
|
||||
if not (0 < self._timeout <= 60):
|
||||
raise ValueError('http_timeout must be between 0 and 60 seconds')
|
||||
self._reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
|
||||
# where to find the auth service (we use this to validate tokens)
|
||||
self._delay_auth_decision = config_true_value(
|
||||
conf.get('delay_auth_decision'))
|
||||
|
||||
# where to find the auth service (we use this to validate tokens)
|
||||
self._request_uri = conf.get('auth_uri')
|
||||
if not self._request_uri:
|
||||
self._logger.warning(
|
||||
@ -167,9 +169,15 @@ class S3Token(object):
|
||||
try:
|
||||
access, signature = auth_header.split(' ')[-1].rsplit(':', 1)
|
||||
except ValueError:
|
||||
msg = 'You have an invalid Authorization header: %s'
|
||||
self._logger.debug(msg, auth_header)
|
||||
return self._deny_request('InvalidURI')(environ, start_response)
|
||||
if self._delay_auth_decision:
|
||||
self._logger.debug('Invalid Authorization header: %s - '
|
||||
'deferring reject downstream', auth_header)
|
||||
return self._app(environ, start_response)
|
||||
else:
|
||||
self._logger.debug('Invalid Authorization header: %s - '
|
||||
'rejecting request', auth_header)
|
||||
return self._deny_request('InvalidURI')(
|
||||
environ, start_response)
|
||||
|
||||
# NOTE(chmou): This is to handle the special case with nova
|
||||
# when we have the option s3_affix_tenant. We will force it to
|
||||
@ -205,9 +213,14 @@ class S3Token(object):
|
||||
resp = self._json_request(creds_json)
|
||||
except ServiceError as e:
|
||||
resp = e.args[0] # NB: swob.Response, not requests.Response
|
||||
msg = 'Received error, exiting middleware with error: %s'
|
||||
self._logger.debug(msg, resp.status_int)
|
||||
return resp(environ, start_response)
|
||||
if self._delay_auth_decision:
|
||||
msg = 'Received error, deferring rejection based on error: %s'
|
||||
self._logger.debug(msg, resp.status)
|
||||
return self._app(environ, start_response)
|
||||
else:
|
||||
msg = 'Received error, rejecting request with error: %s'
|
||||
self._logger.debug(msg, resp.status)
|
||||
return resp(environ, start_response)
|
||||
|
||||
self._logger.debug('Keystone Reply: Status: %d, Output: %s',
|
||||
resp.status_code, resp.content)
|
||||
@ -217,9 +230,17 @@ class S3Token(object):
|
||||
token_id = str(identity_info['access']['token']['id'])
|
||||
tenant = identity_info['access']['token']['tenant']
|
||||
except (ValueError, KeyError):
|
||||
error = 'Error on keystone reply: %d %s'
|
||||
self._logger.debug(error, resp.status_code, resp.content)
|
||||
return self._deny_request('InvalidURI')(environ, start_response)
|
||||
if self._delay_auth_decision:
|
||||
error = ('Error on keystone reply: %d %s - '
|
||||
'deferring rejection downstream')
|
||||
self._logger.debug(error, resp.status_code, resp.content)
|
||||
return self._app(environ, start_response)
|
||||
else:
|
||||
error = ('Error on keystone reply: %d %s - '
|
||||
'rejecting request')
|
||||
self._logger.debug(error, resp.status_code, resp.content)
|
||||
return self._deny_request('InvalidURI')(
|
||||
environ, start_response)
|
||||
|
||||
req.headers['X-Auth-Token'] = token_id
|
||||
tenant_to_connect = force_tenant or tenant['id']
|
||||
|
@ -62,8 +62,10 @@ class TestResponse(requests.Response):
|
||||
|
||||
|
||||
class FakeApp(object):
|
||||
calls = 0
|
||||
"""This represents a WSGI app protected by the auth_token middleware."""
|
||||
def __call__(self, env, start_response):
|
||||
self.calls += 1
|
||||
resp = Response()
|
||||
resp.environ = env
|
||||
return resp(env, start_response)
|
||||
@ -149,6 +151,7 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
|
||||
req.get_response(self.middleware)
|
||||
self.assertTrue(req.path.startswith('/v1/AUTH_TENANT_ID'))
|
||||
self.assertEqual(req.headers['X-Auth-Token'], 'TOKEN_ID')
|
||||
self.assertEqual(1, self.middleware._app.calls)
|
||||
|
||||
def test_authorized_http(self):
|
||||
protocol = 'http'
|
||||
@ -326,6 +329,7 @@ class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase):
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
s3_denied_req.status_int) # pylint: disable-msg=E1101
|
||||
self.assertEqual(0, self.middleware._app.calls)
|
||||
|
||||
def test_bogus_authorization(self):
|
||||
req = Request.blank('/v1/AUTH_cfa/c/o')
|
||||
@ -338,6 +342,7 @@ class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase):
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
s3_invalid_req.status_int) # pylint: disable-msg=E1101
|
||||
self.assertEqual(0, self.middleware._app.calls)
|
||||
|
||||
def test_fail_to_connect_to_keystone(self):
|
||||
with mock.patch.object(self.middleware, '_json_request') as o:
|
||||
@ -352,6 +357,7 @@ class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase):
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
s3_invalid_req.status_int) # pylint: disable-msg=E1101
|
||||
self.assertEqual(0, self.middleware._app.calls)
|
||||
|
||||
def test_bad_reply(self):
|
||||
self.requests_mock.post(self.TEST_URL,
|
||||
@ -367,3 +373,68 @@ class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase):
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
s3_invalid_req.status_int) # pylint: disable-msg=E1101
|
||||
self.assertEqual(0, self.middleware._app.calls)
|
||||
|
||||
|
||||
class S3TokenMiddlewareTestDeferredAuth(S3TokenMiddlewareTestBase):
|
||||
def setUp(self):
|
||||
super(S3TokenMiddlewareTestDeferredAuth, self).setUp()
|
||||
self.conf['delay_auth_decision'] = 'yes'
|
||||
self.middleware = s3_token.S3Token(FakeApp(), self.conf)
|
||||
|
||||
def test_unauthorized_token(self):
|
||||
ret = {"error":
|
||||
{"message": "EC2 access key not found.",
|
||||
"code": 401,
|
||||
"title": "Unauthorized"}}
|
||||
self.requests_mock.post(self.TEST_URL, status_code=403, json=ret)
|
||||
req = Request.blank('/v1/AUTH_cfa/c/o')
|
||||
req.headers['Authorization'] = 'AWS access:signature'
|
||||
req.headers['X-Storage-Token'] = 'token'
|
||||
resp = req.get_response(self.middleware)
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
200)
|
||||
self.assertNotIn('X-Auth-Token', req.headers)
|
||||
self.assertEqual(1, self.middleware._app.calls)
|
||||
|
||||
def test_bogus_authorization(self):
|
||||
req = Request.blank('/v1/AUTH_cfa/c/o')
|
||||
req.headers['Authorization'] = 'AWS badboy'
|
||||
req.headers['X-Storage-Token'] = 'token'
|
||||
resp = req.get_response(self.middleware)
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
200)
|
||||
self.assertNotIn('X-Auth-Token', req.headers)
|
||||
self.assertEqual(1, self.middleware._app.calls)
|
||||
|
||||
def test_fail_to_connect_to_keystone(self):
|
||||
with mock.patch.object(self.middleware, '_json_request') as o:
|
||||
s3_invalid_req = self.middleware._deny_request('InvalidURI')
|
||||
o.side_effect = s3_token.ServiceError(s3_invalid_req)
|
||||
|
||||
req = Request.blank('/v1/AUTH_cfa/c/o')
|
||||
req.headers['Authorization'] = 'AWS access:signature'
|
||||
req.headers['X-Storage-Token'] = 'token'
|
||||
resp = req.get_response(self.middleware)
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
200)
|
||||
self.assertNotIn('X-Auth-Token', req.headers)
|
||||
self.assertEqual(1, self.middleware._app.calls)
|
||||
|
||||
def test_bad_reply(self):
|
||||
self.requests_mock.post(self.TEST_URL,
|
||||
status_code=201,
|
||||
text="<badreply>")
|
||||
|
||||
req = Request.blank('/v1/AUTH_cfa/c/o')
|
||||
req.headers['Authorization'] = 'AWS access:signature'
|
||||
req.headers['X-Storage-Token'] = 'token'
|
||||
resp = req.get_response(self.middleware)
|
||||
self.assertEqual(
|
||||
resp.status_int, # pylint: disable-msg=E1101
|
||||
200)
|
||||
self.assertNotIn('X-Auth-Token', req.headers)
|
||||
self.assertEqual(1, self.middleware._app.calls)
|
||||
|
Loading…
x
Reference in New Issue
Block a user