diff --git a/bin/swift b/bin/swift index 0cac5d659c..37e0da0411 100755 --- a/bin/swift +++ b/bin/swift @@ -176,17 +176,6 @@ def json_request(method, url, **kwargs): return resp, body -def get_conn(options): - """ - Return a connection building it from the options. - """ - return Connection(options.auth, - options.user, - options.key, - snet=options.snet, - auth_version=options.auth_version) - - def _get_auth_v1_0(url, user, key, snet): parsed, conn = http_connection(url) conn.request('GET', parsed.path, '', @@ -209,15 +198,10 @@ def _get_auth_v1_0(url, user, key, snet): resp.getheader('x-auth-token')) -def _get_auth_v2_0(url, user, key, snet): - if ':' in user: - tenant, user = user.split(':') - else: - tenant = user - - body = {"auth": {"tenantName": tenant, - "passwordCredentials": - {"username": user, "password": key}}} +def _get_auth_v2_0(url, user, tenant_name, key, snet): + body = {'auth': {'passwordCredentials': + {'password': key, 'username': user}, + 'tenantName': tenant_name}} token_url = urljoin(url, "tokens") resp, body = json_request("POST", token_url, body=body) token_id = None @@ -243,7 +227,7 @@ def _get_auth_v2_0(url, user, key, snet): return url, token_id -def get_auth(url, user, key, snet=False, auth_version="1.0"): +def get_auth(url, user, key, snet=False, tenant_name=None, auth_version="1.0"): """ Get authentication/authorization credentials. @@ -257,14 +241,18 @@ def get_auth(url, user, key, snet=False, auth_version="1.0"): :param user: user to authenticate as :param key: key or password for authorization :param snet: use SERVICENET internal network (see above), default is False - :param auth_version: OpenStack authentication version (default is 1.0) + :param auth_version: OpenStack auth version, default is 1.0 + :param tenant_name: The tenant/account name, required when connecting + to a auth 2.0 system. :returns: tuple of (storage URL, auth token) :raises: ClientException: HTTP GET request to auth URL failed """ if auth_version in ["1.0", "1"]: return _get_auth_v1_0(url, user, key, snet) elif auth_version in ["2.0", "2"]: - return _get_auth_v2_0(url, user, key, snet) + if not tenant_name: + raise ClientException('No tenant specified') + return _get_auth_v2_0(url, user, tenant_name, key, snet) def get_account(url, token, marker=None, limit=None, prefix=None, @@ -818,9 +806,10 @@ class Connection(object): def __init__(self, authurl, user, key, retries=5, preauthurl=None, preauthtoken=None, snet=False, starting_backoff=1, + tenant_name=None, auth_version="1"): """ - :param authurl: authenitcation URL + :param authurl: authentication URL :param user: user name to authenticate as :param key: key/password to authenticate with :param retries: Number of times to retry the request before failing @@ -828,7 +817,9 @@ class Connection(object): :param preauthtoken: authentication token (if you have already authenticated) :param snet: use SERVICENET internal network default is False - :param auth_version: Openstack auth version. + :param auth_version: OpenStack auth version, default is 1.0 + :param tenant_name: The tenant/account name, required when connecting + to a auth 2.0 system. """ self.authurl = authurl self.user = user @@ -841,9 +832,12 @@ class Connection(object): self.snet = snet self.starting_backoff = starting_backoff self.auth_version = auth_version + self.tenant_name = tenant_name def get_auth(self): - return get_auth(self.authurl, self.user, self.key, snet=self.snet, + return get_auth(self.authurl, self.user, + self.key, snet=self.snet, + tenant_name=self.tenant_name, auth_version=self.auth_version) def http_connection(self): @@ -971,6 +965,18 @@ class Connection(object): # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +def get_conn(options): + """ + Return a connection building it from the options. + """ + return Connection(options.auth, + options.user, + options.key, + snet=options.snet, + tenant_name=options.os_tenant_name, + auth_version=options.auth_version) + + def mkdirs(path): try: makedirs(path) @@ -1931,6 +1937,9 @@ Example: parser.add_option('--os_username', dest='os_username', default=environ.get('OS_USERNAME'), help=SUPPRESS_HELP) + parser.add_option('--os_tenant_name', dest='os_tenant_name', + default=environ.get('OS_TENANT_NAME'), + help=SUPPRESS_HELP) parser.add_option('--os_password', dest='os_password', default=environ.get('OS_PASSWORD'), help=SUPPRESS_HELP) diff --git a/swift/common/client.py b/swift/common/client.py index 8fcb7e983a..5b9351e8b5 100644 --- a/swift/common/client.py +++ b/swift/common/client.py @@ -179,21 +179,17 @@ def _get_auth_v1_0(url, user, key, snet): if snet: parsed = list(urlparse(url)) # Second item in the list is the netloc - parsed[1] = 'snet-' + parsed[1] + netloc = parsed[1] + parsed[1] = 'snet-' + netloc url = urlunparse(parsed) return url, resp.getheader('x-storage-token', resp.getheader('x-auth-token')) -def _get_auth_v2_0(url, user, key, snet): - if ':' in user: - tenant, user = user.split(':') - else: - tenant = user - - body = {"auth": {"tenantName": tenant, - "passwordCredentials": - {"username": user, "password": key}}} +def _get_auth_v2_0(url, user, tenant_name, key, snet): + body = {'auth': {'passwordCredentials': + {'password': key, 'username': user}, + 'tenantName': tenant_name}} token_url = urljoin(url, "tokens") resp, body = json_request("POST", token_url, body=body) token_id = None @@ -219,7 +215,7 @@ def _get_auth_v2_0(url, user, key, snet): return url, token_id -def get_auth(url, user, key, snet=False, auth_version="1.0"): +def get_auth(url, user, key, snet=False, tenant_name=None, auth_version="1.0"): """ Get authentication/authorization credentials. @@ -233,14 +229,18 @@ def get_auth(url, user, key, snet=False, auth_version="1.0"): :param user: user to authenticate as :param key: key or password for authorization :param snet: use SERVICENET internal network (see above), default is False - :param auth_version: OpenStack authentication version (default is 1.0) + :param auth_version: OpenStack auth version, default is 1.0 + :param tenant_name: The tenant/account name, required when connecting + to a auth 2.0 system. :returns: tuple of (storage URL, auth token) :raises: ClientException: HTTP GET request to auth URL failed """ if auth_version in ["1.0", "1"]: return _get_auth_v1_0(url, user, key, snet) elif auth_version in ["2.0", "2"]: - return _get_auth_v2_0(url, user, key, snet) + if not tenant_name: + raise ClientException('No tenant specified') + return _get_auth_v2_0(url, user, tenant_name, key, snet) def get_account(url, token, marker=None, limit=None, prefix=None, @@ -794,6 +794,7 @@ class Connection(object): def __init__(self, authurl, user, key, retries=5, preauthurl=None, preauthtoken=None, snet=False, starting_backoff=1, + tenant_name=None, auth_version="1"): """ :param authurl: authentication URL @@ -804,7 +805,9 @@ class Connection(object): :param preauthtoken: authentication token (if you have already authenticated) :param snet: use SERVICENET internal network default is False - :param auth_version: Openstack auth version. + :param auth_version: OpenStack auth version, default is 1.0 + :param tenant_name: The tenant/account name, required when connecting + to a auth 2.0 system. """ self.authurl = authurl self.user = user @@ -817,9 +820,12 @@ class Connection(object): self.snet = snet self.starting_backoff = starting_backoff self.auth_version = auth_version + self.tenant_name = tenant_name def get_auth(self): - return get_auth(self.authurl, self.user, self.key, snet=self.snet, + return get_auth(self.authurl, self.user, + self.key, snet=self.snet, + tenant_name=self.tenant_name, auth_version=self.auth_version) def http_connection(self): diff --git a/test/unit/common/test_client.py b/test/unit/common/test_client.py index d527e6b1cd..b1ff852d76 100644 --- a/test/unit/common/test_client.py +++ b/test/unit/common/test_client.py @@ -178,10 +178,23 @@ class TestGetAuth(MockHttpTest): return c.json_dumps(body) c.http_connection = self.fake_http_connection(200, return_read=read) url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf', - auth_version="2.0") + tenant_name='asdf', auth_version="2.0") self.assertTrue(url.startswith("http")) self.assertTrue(token) + def test_auth_v2_no_tenant_name(self): + def read(*args, **kwargs): + acct_url = 'http://127.0.01/AUTH_FOO' + body = {'access': {'serviceCatalog': + [{u'endpoints': [{'publicURL': acct_url}], + 'type': 'object-store'}], + 'token': {'id': 'XXXXXXX'}}} + return c.json_dumps(body) + c.http_connection = self.fake_http_connection(200, return_read=read) + self.assertRaises(c.ClientException, c.get_auth, + 'http://www.tests.com', 'asdf', 'asdf', + auth_version='2.0') + class TestGetAccount(MockHttpTest):