Skip to content
Permalink
Browse files

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
  • Loading branch information...
matthewoliver committed May 1, 2018
1 parent 3313392 commit 2d25fc4b91752345e95892d872329c2557d545d6
@@ -441,6 +441,22 @@ user_test5_tester5 = testing5 service
# move between domains, you should disable backwards compatible name matching
# in ACLs by setting allow_names_in_acls to false:
# allow_names_in_acls = true
#
# 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

[filter:s3api]
use = egg:swift#s3api
@@ -16,7 +16,8 @@
from swift.common.http import is_success
from swift.common.middleware import acl as swift_acl
from swift.common.request_helpers import get_sys_meta_prefix
from swift.common.swob import HTTPNotFound, HTTPForbidden, HTTPUnauthorized
from swift.common.swob import HTTPNotFound, HTTPForbidden, HTTPUnauthorized, \
Request
from swift.common.utils import config_read_reseller_options, list_from_csv
from swift.proxy.controllers.base import get_account_info
import functools
@@ -167,6 +168,26 @@ class KeystoneAuth(object):
allow_overrides = false
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
:param app: The next WSGI app in the pipeline
:param conf: The dict of configuration values
"""
@@ -192,10 +213,15 @@ def __init__(self, app, conf):
self.default_domain_id = conf.get('default_domain_id', 'default')
self.allow_names_in_acls = swift_utils.config_true_value(
conf.get('allow_names_in_acls', 'true'))
self.use_dynamic_reseller = swift_utils.config_true_value(
conf.get('use_dynamic_reseller', 'false'))

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

if self.use_dynamic_reseller:
self._set_dynamic_name(environ, env_identity)

# Check if one of the middleware like tempurl or formpost have
# set the swift.authorize_override environ and want to control the
# authentication
@@ -266,6 +292,22 @@ def _keystone_identity(self, environ):
identity['auth_version'] = auth_version
return identity

def _set_dynamic_name(self, environ, env_identity):
try:
part = Request(environ).split_path(2, 4, True)
version, account, container, obj = part
except ValueError:
return

if account and account in self.reseller_prefixes:
path = "/%s/%s%s" % (version, account,
env_identity['tenant'][0])
if container:
path = "%s/%s" % (path, container)
if obj:
path = '%s/%s' % (path, obj)
environ['PATH_INFO'] = path

def _get_account_name(self, prefix, tenant_id):
return '%s%s' % (prefix, tenant_id)

@@ -340,6 +340,30 @@ def test_project_domain_id_sysmeta_set_unknown_with_v2(self):
self.assertEqual(headers_sent['X-Account-Sysmeta-Project-Domain-Id'],
UNKNOWN_ID)

def test_use_dynamic_reseller(self):
reseller_prefix = self.test_auth.reseller_prefixes[0]
headers = get_identity_headers()
self.test_auth.use_dynamic_reseller = True

def test(path, expected_path):
req = self._make_request(path=path, headers=headers)
resp = req.get_response(self.test_auth)
self.assertEqual(resp.request.path, expected_path)

tests = [
{'path': '/v1/%s/c/o' % reseller_prefix,
'expected_path': '/v1/%s%s/c/o' % (reseller_prefix,
headers['X_TENANT_ID'])},
{'path': '/v1/%s/c/o' % '',
'expected_path': '/v1//c/o'},
{'path': '/v1/%s/c/o' % 'BLAH_',
'expected_path': '/v1/BLAH_/c/o'},
{'path': '/v1/%s%s/c/o' % (reseller_prefix, '291912'),
'expected_path': '/v1/%s%s/c/o' % (reseller_prefix, '291912')}]

for params in tests:
test(**params)


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

subreq = Request.blank(

0 comments on commit 2d25fc4

Please sign in to comment.
You can’t perform that action at this time.