Skip to content
This repository was archived by the owner on Sep 26, 2019. It is now read-only.

Commit 2a48861

Browse files
tipabuKota Tsuyuzaki
authored andcommitted
Make s3token work in a Keystone-V3-only world
Previously, we hardcoded a v2.0 path to use when validating requests against Keystone. Now, the version to use may be specified in a new auth_version config option. In the future, we may want to implement some form of version discovery, but that will be complicated by: * trying to determine whether the S3 extension is actually enabled for a given version (particularly since the extensions endpoint [1] seems to have gone away in v3), and * needing to be able to perform this detection as part of the client-request cycle, in case Keystone is down when the proxy is coming up. [1] http://developer.openstack.org/api-ref/identity/v2/index.html?expanded=list-extensions-detail Change-Id: I3a9c702123fd1b76d45214a89ec0583caf3719f0
1 parent 9ede5cd commit 2a48861

File tree

3 files changed

+78
-4
lines changed

3 files changed

+78
-4
lines changed

etc/proxy-server.conf-sample

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ delay_auth_decision = False
156156
# Keystone server details
157157
auth_uri = http://keystonehost:35357/
158158

159+
# Identity Service API version to use. This is appended to the auth_uri.
160+
# Historically this defaulted to "2.0", but most modern deployments
161+
# should use "3".
162+
auth_version = 2.0
163+
159164
# Connect/read timeout to use when communicating with Keystone
160165
http_timeout = 10.0
161166

swift3/s3_token_middleware.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ def __init__(self, app, conf):
160160
if parsed.query or parsed.fragment or '@' in parsed.netloc:
161161
raise ConfigFileError('Invalid auth_uri; must not include '
162162
'username, query, or fragment')
163+
self._request_uri += '/v%s/s3tokens' % conf.get('auth_version', '2.0')
163164

164165
# SSL
165166
insecure = config_true_value(conf.get('insecure'))
@@ -194,7 +195,7 @@ def _deny_request(self, code):
194195
def _json_request(self, creds_json):
195196
headers = {'Content-Type': 'application/json'}
196197
try:
197-
response = requests.post('%s/v2.0/s3tokens' % self._request_uri,
198+
response = requests.post(self._request_uri,
198199
headers=headers, data=creds_json,
199200
verify=self._verify,
200201
timeout=self._timeout)

swift3/test/unit/test_s3_token_middleware.py

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,28 @@ def test_authorized_http(self):
284284
req.get_response(self.middleware)
285285
self._assert_authorized(req)
286286

287+
def test_authorized_v3(self):
288+
protocol = 'http'
289+
host = 'fakehost'
290+
port = 35357
291+
self.requests_mock.post(
292+
'%s://%s:%s/v3/s3tokens' % (protocol, host, port),
293+
status_code=201, json=GOOD_RESPONSE_V2)
294+
295+
self.middleware = (
296+
s3_token.filter_factory({'auth_protocol': 'http',
297+
'auth_host': host,
298+
'auth_port': port,
299+
'auth_version': '3'})(self.app))
300+
req = Request.blank('/v1/AUTH_cfa/c/o')
301+
req.environ['swift3.auth_details'] = {
302+
'access_key': u'access',
303+
'signature': u'signature',
304+
'string_to_sign': u'token',
305+
}
306+
req.get_response(self.middleware)
307+
self._assert_authorized(req)
308+
287309
def test_authorized_trailing_slash(self):
288310
self.middleware = s3_token.filter_factory({
289311
'auth_uri': self.TEST_AUTH_URI + '/'})(self.app)
@@ -355,20 +377,44 @@ def test_insecure_option(self):
355377
middleware = s3_token.filter_factory(config)(self.app)
356378
self.assertIs('false_ind', middleware._verify)
357379

380+
def test_auth_version(self):
381+
for conf, expected in [
382+
# if provided just host/scheme, tack on the default
383+
# version/endpoint like before
384+
({'auth_uri': 'https://example.com'},
385+
'https://example.com/v2.0/s3tokens'),
386+
# if provided a version-specific URI, trust it
387+
({'auth_uri': 'https://example.com:5000',
388+
'auth_version': '2.0'},
389+
'https://example.com:5000/v2.0/s3tokens'),
390+
({'auth_uri': 'http://example.com', 'auth_version': '3'},
391+
'http://example.com/v3/s3tokens'),
392+
# even try to allow for future versions
393+
({'auth_uri': 'http://example.com', 'auth_version': '4.25'},
394+
'http://example.com/v4.25/s3tokens'),
395+
# keystone running under mod_wsgi often has a path prefix
396+
({'auth_uri': 'https://example.com/identity'},
397+
'https://example.com/identity/v2.0/s3tokens'),
398+
# doesn't really work to include version in auth_uri
399+
({'auth_uri': 'https://example.com/v2.0'},
400+
'https://example.com/v2.0/v2.0/s3tokens')]:
401+
middleware = s3_token.filter_factory(conf)(self.app)
402+
self.assertEqual(expected, middleware._request_uri)
403+
358404
def test_ipv6_auth_host_option(self):
359405
config = {}
360406
ipv6_addr = '::FFFF:129.144.52.38'
361-
identity_uri = 'https://[::FFFF:129.144.52.38]:35357'
407+
request_uri = 'https://[::FFFF:129.144.52.38]:35357/v2.0/s3tokens'
362408

363409
# Raw IPv6 address should work
364410
config['auth_host'] = ipv6_addr
365411
middleware = s3_token.filter_factory(config)(self.app)
366-
self.assertEqual(identity_uri, middleware._request_uri)
412+
self.assertEqual(request_uri, middleware._request_uri)
367413

368414
# ...as should workarounds already in use
369415
config['auth_host'] = '[%s]' % ipv6_addr
370416
middleware = s3_token.filter_factory(config)(self.app)
371-
self.assertEqual(identity_uri, middleware._request_uri)
417+
self.assertEqual(request_uri, middleware._request_uri)
372418

373419
# ... with no config, we should get config error
374420
del config['auth_host']
@@ -742,6 +788,28 @@ def test_authorized_http(self):
742788
req.get_response(self.middleware)
743789
self._assert_authorized(req)
744790

791+
def test_authorized_v3(self):
792+
protocol = 'http'
793+
host = 'fakehost'
794+
port = 35357
795+
self.requests_mock.post(
796+
'%s://%s:%s/v3/s3tokens' % (protocol, host, port),
797+
status_code=201, json=GOOD_RESPONSE_V3)
798+
799+
self.middleware = (
800+
s3_token.filter_factory({'auth_protocol': 'http',
801+
'auth_host': host,
802+
'auth_port': port,
803+
'auth_version': '3'})(self.app))
804+
req = Request.blank('/v1/AUTH_cfa/c/o')
805+
req.environ['swift3.auth_details'] = {
806+
'access_key': u'access',
807+
'signature': u'signature',
808+
'string_to_sign': u'token',
809+
}
810+
req.get_response(self.middleware)
811+
self._assert_authorized(req)
812+
745813
def test_authorized_trailing_slash(self):
746814
self.middleware = s3_token.filter_factory({
747815
'auth_uri': self.TEST_AUTH_URI + '/'})(self.app)

0 commit comments

Comments
 (0)