Skip to content

Commit 2d25fc4

Browse files
committed
Add use_dynamic_reseller option to keystoneauth
By default we assume the incoming request will point to a complete account, meaning the object storage endpoint in keystone will end with something like: '<uri>/v1/AUTH_%(tenant_id)s' If you enable `use_dynamic_reseller` then the keystoneauth middleware will pull the tenant_id from keystone import environment. Allowing an endpoint of the form: '<uri>/v1/AUTH_/' This shortcut makes configuration easier, but can only be reliably used when on your own account and providing a token. API elements like tempurl and public containers need the full account in the path. To enable this dynamic reseller account completion you need to enable `use_dynamic_reseller` which is by default `false`:: use_dynamic_reseller = true Change-Id: I3f0a28de298c02c8d3aefe1473d7226563f11cac
1 parent 3313392 commit 2d25fc4

3 files changed

Lines changed: 84 additions & 1 deletion

File tree

etc/proxy-server.conf-sample

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,22 @@ user_test5_tester5 = testing5 service
441441
# move between domains, you should disable backwards compatible name matching
442442
# in ACLs by setting allow_names_in_acls to false:
443443
# allow_names_in_acls = true
444+
#
445+
# By default we assume the incoming request will point to a complete
446+
# account, meaning the object storage endpoint in keystone will end with
447+
# something like '<uri>/v1/AUTH_%(tenant_id)s'.
448+
#
449+
# If you enable ``use_dynamic_reseller`` then the keystoneauth middleware
450+
# will pull the tenant_id from keystone import environment. Allowing an
451+
# endpoint of the form '<uri>/v1/AUTH_/'.
452+
#
453+
# This shortcut makes configuration easier, but can only be reliably used
454+
# when on your own account and providing a token. API elements like tempurl
455+
# and public containers need the full account in the path.
456+
# To enable this dynamic reseller account completion you need to enable
457+
# ``use_dynamic_reseller`` which is by default ``false``::
458+
#
459+
# use_dynamic_reseller = true
444460

445461
[filter:s3api]
446462
use = egg:swift#s3api

swift/common/middleware/keystoneauth.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
from swift.common.http import is_success
1717
from swift.common.middleware import acl as swift_acl
1818
from swift.common.request_helpers import get_sys_meta_prefix
19-
from swift.common.swob import HTTPNotFound, HTTPForbidden, HTTPUnauthorized
19+
from swift.common.swob import HTTPNotFound, HTTPForbidden, HTTPUnauthorized, \
20+
Request
2021
from swift.common.utils import config_read_reseller_options, list_from_csv
2122
from swift.proxy.controllers.base import get_account_info
2223
import functools
@@ -167,6 +168,26 @@ class KeystoneAuth(object):
167168
168169
allow_overrides = false
169170
171+
By default we assume the incoming request will point to a complete
172+
account, meaning the object storage endpoint in keystone will end with
173+
something like::
174+
175+
'<uri>/v1/AUTH_%(tenant_id)s'
176+
177+
If you enable ``use_dynamic_reseller`` then the keystoneauth middleware
178+
will pull the tenant_id from keystone import environment. Allowing an
179+
endpoint of the form::
180+
181+
'<uri>/v1/AUTH_/'
182+
183+
This shortcut makes configuration easier, but can only be reliably used
184+
when on your own account and providing a token. API elements like tempurl
185+
and public containers need the full account in the path.
186+
To enable this dynamic reseller account completion you need to enable
187+
``use_dynamic_reseller`` which is by default ``false``::
188+
189+
use_dynamic_reseller = true
190+
170191
:param app: The next WSGI app in the pipeline
171192
:param conf: The dict of configuration values
172193
"""
@@ -192,10 +213,15 @@ def __init__(self, app, conf):
192213
self.default_domain_id = conf.get('default_domain_id', 'default')
193214
self.allow_names_in_acls = swift_utils.config_true_value(
194215
conf.get('allow_names_in_acls', 'true'))
216+
self.use_dynamic_reseller = swift_utils.config_true_value(
217+
conf.get('use_dynamic_reseller', 'false'))
195218

196219
def __call__(self, environ, start_response):
197220
env_identity = self._keystone_identity(environ)
198221

222+
if self.use_dynamic_reseller:
223+
self._set_dynamic_name(environ, env_identity)
224+
199225
# Check if one of the middleware like tempurl or formpost have
200226
# set the swift.authorize_override environ and want to control the
201227
# authentication
@@ -266,6 +292,22 @@ def _keystone_identity(self, environ):
266292
identity['auth_version'] = auth_version
267293
return identity
268294

295+
def _set_dynamic_name(self, environ, env_identity):
296+
try:
297+
part = Request(environ).split_path(2, 4, True)
298+
version, account, container, obj = part
299+
except ValueError:
300+
return
301+
302+
if account and account in self.reseller_prefixes:
303+
path = "/%s/%s%s" % (version, account,
304+
env_identity['tenant'][0])
305+
if container:
306+
path = "%s/%s" % (path, container)
307+
if obj:
308+
path = '%s/%s' % (path, obj)
309+
environ['PATH_INFO'] = path
310+
269311
def _get_account_name(self, prefix, tenant_id):
270312
return '%s%s' % (prefix, tenant_id)
271313

test/unit/common/middleware/test_keystoneauth.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,30 @@ def test_project_domain_id_sysmeta_set_unknown_with_v2(self):
340340
self.assertEqual(headers_sent['X-Account-Sysmeta-Project-Domain-Id'],
341341
UNKNOWN_ID)
342342

343+
def test_use_dynamic_reseller(self):
344+
reseller_prefix = self.test_auth.reseller_prefixes[0]
345+
headers = get_identity_headers()
346+
self.test_auth.use_dynamic_reseller = True
347+
348+
def test(path, expected_path):
349+
req = self._make_request(path=path, headers=headers)
350+
resp = req.get_response(self.test_auth)
351+
self.assertEqual(resp.request.path, expected_path)
352+
353+
tests = [
354+
{'path': '/v1/%s/c/o' % reseller_prefix,
355+
'expected_path': '/v1/%s%s/c/o' % (reseller_prefix,
356+
headers['X_TENANT_ID'])},
357+
{'path': '/v1/%s/c/o' % '',
358+
'expected_path': '/v1//c/o'},
359+
{'path': '/v1/%s/c/o' % 'BLAH_',
360+
'expected_path': '/v1/BLAH_/c/o'},
361+
{'path': '/v1/%s%s/c/o' % (reseller_prefix, '291912'),
362+
'expected_path': '/v1/%s%s/c/o' % (reseller_prefix, '291912')}]
363+
364+
for params in tests:
365+
test(**params)
366+
343367

344368
class SwiftAuthMultiple(SwiftAuth):
345369
"""Runs same tests as SwiftAuth with multiple reseller prefixes
@@ -860,6 +884,7 @@ def fake_start_response(*args, **kwargs):
860884
pass
861885
the_env = self._get_identity(
862886
tenant_id='test', roles=['reselleradmin'])
887+
the_env['PATH_INFO'] = ''
863888
self.test_auth(the_env, fake_start_response)
864889

865890
subreq = Request.blank(

0 commit comments

Comments
 (0)