Use requests library in S3 middleware

Convert the S3 token middleware to use the requests library. It does not
validate certificates as part of this patch to keep new functionality
isolated.

Change-Id: I0f26c80a969b919de80410af0a80920bd8493191
Closes-Bug: #1275598
This commit is contained in:
Jamie Lennox
2014-02-03 13:14:53 +10:00
parent 7736825235
commit 9fda5add29
2 changed files with 52 additions and 33 deletions

View File

@@ -33,11 +33,12 @@ This WSGI component:
"""
import httplib
import logging
import urllib
import webob
import requests
from keystoneclient.openstack.common import jsonutils
@@ -105,16 +106,26 @@ class S3Token(object):
self.logger.debug('Starting the %s component' % PROTOCOL_NAME)
self.reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
# where to find the auth service (we use this to validate tokens)
self.auth_host = conf.get('auth_host')
self.auth_port = int(conf.get('auth_port', 35357))
self.auth_protocol = conf.get('auth_protocol', 'https')
if self.auth_protocol == 'http':
self.http_client_class = httplib.HTTPConnection
else:
self.http_client_class = httplib.HTTPSConnection
auth_host = conf.get('auth_host')
auth_port = int(conf.get('auth_port', 35357))
auth_protocol = conf.get('auth_protocol', 'https')
self.request_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port)
# SSL
self.cert_file = conf.get('certfile')
self.key_file = conf.get('keyfile')
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 deny_request(self, code):
error_table = {
@@ -132,33 +143,22 @@ class S3Token(object):
def _json_request(self, creds_json):
headers = {'Content-Type': 'application/json'}
if self.auth_protocol == 'http':
conn = self.http_client_class(self.auth_host, self.auth_port)
else:
conn = self.http_client_class(self.auth_host,
self.auth_port,
self.key_file,
self.cert_file)
try:
conn.request('POST', '/v2.0/s3tokens',
body=creds_json,
headers=headers)
response = conn.getresponse()
output = response.read()
except Exception as e:
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('HTTP connection exception: %s' % e)
resp = self.deny_request('InvalidURI')
raise ServiceError(resp)
finally:
conn.close()
if response.status < 200 or response.status >= 300:
if response.status_code < 200 or response.status_code >= 300:
self.logger.debug('Keystone reply error: status=%s reason=%s' %
(response.status, response.reason))
(response.status_code, response.reason))
resp = self.deny_request('AccessDenied')
raise ServiceError(resp)
return (response, output)
return response
def __call__(self, environ, start_response):
"""Handle incoming request. authenticate and send downstream."""
@@ -225,23 +225,23 @@ class S3Token(object):
# identified and not doing a second query and just
# pass it through to swiftauth in this case.
try:
resp, output = self._json_request(creds_json)
resp = self._json_request(creds_json)
except ServiceError as e:
resp = e.args[0]
msg = 'Received error, exiting middleware with error: %s'
self.logger.debug(msg % (resp.status))
self.logger.debug(msg % (resp.status_code))
return resp(environ, start_response)
self.logger.debug('Keystone Reply: Status: %d, Output: %s' % (
resp.status, output))
resp.status_code, resp.content))
try:
identity_info = jsonutils.loads(output)
identity_info = resp.json()
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, str(output)))
self.logger.debug(error % (resp.status_code, str(resp.content)))
return self.deny_request('InvalidURI')(environ, start_response)
req.headers['X-Auth-Token'] = token_id

View File

@@ -16,6 +16,7 @@
import httpretty
import mock
import requests
import testtools
import webob
@@ -120,6 +121,24 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
path = req.environ['PATH_INFO']
self.assertTrue(path.startswith('/v1/AUTH_FORCED_TENANT_ID'))
@mock.patch.object(requests, 'post')
def test_insecure(self, MOCK_REQUEST):
self.middleware = (
s3_token.filter_factory({'insecure': True})(FakeApp()))
MOCK_REQUEST.return_value = utils.TestResponse({
'status_code': 201,
'text': jsonutils.dumps(GOOD_RESPONSE)})
req = webob.Request.blank('/v1/AUTH_cfa/c/o')
req.headers['Authorization'] = 'access:signature'
req.headers['X-Storage-Token'] = 'token'
req.get_response(self.middleware)
self.assertTrue(MOCK_REQUEST.called)
mock_args, mock_kwargs = MOCK_REQUEST.call_args
self.assertIs(mock_kwargs['verify'], False)
class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase):
def setUp(self):