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:
@@ -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
|
||||
|
@@ -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):
|
||||
|
Reference in New Issue
Block a user