Merge "Use requests library in S3 middleware"
This commit is contained in:
@@ -33,11 +33,12 @@ This WSGI component:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import httplib
|
|
||||||
import logging
|
import logging
|
||||||
import urllib
|
import urllib
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
from keystoneclient.openstack.common import jsonutils
|
from keystoneclient.openstack.common import jsonutils
|
||||||
|
|
||||||
|
|
||||||
@@ -105,16 +106,26 @@ class S3Token(object):
|
|||||||
self.logger.debug('Starting the %s component' % PROTOCOL_NAME)
|
self.logger.debug('Starting the %s component' % PROTOCOL_NAME)
|
||||||
self.reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
|
self.reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
|
||||||
# where to find the auth service (we use this to validate tokens)
|
# 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))
|
auth_host = conf.get('auth_host')
|
||||||
self.auth_protocol = conf.get('auth_protocol', 'https')
|
auth_port = int(conf.get('auth_port', 35357))
|
||||||
if self.auth_protocol == 'http':
|
auth_protocol = conf.get('auth_protocol', 'https')
|
||||||
self.http_client_class = httplib.HTTPConnection
|
|
||||||
else:
|
self.request_uri = '%s://%s:%s' % (auth_protocol, auth_host, auth_port)
|
||||||
self.http_client_class = httplib.HTTPSConnection
|
|
||||||
# SSL
|
# SSL
|
||||||
self.cert_file = conf.get('certfile')
|
insecure = conf.get('insecure', False)
|
||||||
self.key_file = conf.get('keyfile')
|
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):
|
def deny_request(self, code):
|
||||||
error_table = {
|
error_table = {
|
||||||
@@ -132,33 +143,22 @@ class S3Token(object):
|
|||||||
|
|
||||||
def _json_request(self, creds_json):
|
def _json_request(self, creds_json):
|
||||||
headers = {'Content-Type': 'application/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:
|
try:
|
||||||
conn.request('POST', '/v2.0/s3tokens',
|
response = requests.post('%s/v2.0/s3tokens' % self.request_uri,
|
||||||
body=creds_json,
|
headers=headers, data=creds_json,
|
||||||
headers=headers)
|
verify=self.verify)
|
||||||
response = conn.getresponse()
|
except requests.exceptions.RequestException as e:
|
||||||
output = response.read()
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.info('HTTP connection exception: %s' % e)
|
self.logger.info('HTTP connection exception: %s' % e)
|
||||||
resp = self.deny_request('InvalidURI')
|
resp = self.deny_request('InvalidURI')
|
||||||
raise ServiceError(resp)
|
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' %
|
self.logger.debug('Keystone reply error: status=%s reason=%s' %
|
||||||
(response.status, response.reason))
|
(response.status_code, response.reason))
|
||||||
resp = self.deny_request('AccessDenied')
|
resp = self.deny_request('AccessDenied')
|
||||||
raise ServiceError(resp)
|
raise ServiceError(resp)
|
||||||
|
|
||||||
return (response, output)
|
return response
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
"""Handle incoming request. authenticate and send downstream."""
|
"""Handle incoming request. authenticate and send downstream."""
|
||||||
@@ -225,23 +225,23 @@ class S3Token(object):
|
|||||||
# identified and not doing a second query and just
|
# identified and not doing a second query and just
|
||||||
# pass it through to swiftauth in this case.
|
# pass it through to swiftauth in this case.
|
||||||
try:
|
try:
|
||||||
resp, output = self._json_request(creds_json)
|
resp = self._json_request(creds_json)
|
||||||
except ServiceError as e:
|
except ServiceError as e:
|
||||||
resp = e.args[0]
|
resp = e.args[0]
|
||||||
msg = 'Received error, exiting middleware with error: %s'
|
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)
|
return resp(environ, start_response)
|
||||||
|
|
||||||
self.logger.debug('Keystone Reply: Status: %d, Output: %s' % (
|
self.logger.debug('Keystone Reply: Status: %d, Output: %s' % (
|
||||||
resp.status, output))
|
resp.status_code, resp.content))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
identity_info = jsonutils.loads(output)
|
identity_info = resp.json()
|
||||||
token_id = str(identity_info['access']['token']['id'])
|
token_id = str(identity_info['access']['token']['id'])
|
||||||
tenant = identity_info['access']['token']['tenant']
|
tenant = identity_info['access']['token']['tenant']
|
||||||
except (ValueError, KeyError):
|
except (ValueError, KeyError):
|
||||||
error = 'Error on keystone reply: %d %s'
|
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)
|
return self.deny_request('InvalidURI')(environ, start_response)
|
||||||
|
|
||||||
req.headers['X-Auth-Token'] = token_id
|
req.headers['X-Auth-Token'] = token_id
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import httpretty
|
import httpretty
|
||||||
import mock
|
import mock
|
||||||
|
import requests
|
||||||
import testtools
|
import testtools
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
@@ -120,6 +121,24 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
|
|||||||
path = req.environ['PATH_INFO']
|
path = req.environ['PATH_INFO']
|
||||||
self.assertTrue(path.startswith('/v1/AUTH_FORCED_TENANT_ID'))
|
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):
|
class S3TokenMiddlewareTestBad(S3TokenMiddlewareTestBase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Reference in New Issue
Block a user