Allow user to scope a token to either project or a domain by passing "scope_to" (and "domain_name") argument to Identity v3 class constructor.
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/23d4355a Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/23d4355a Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/23d4355a Branch: refs/heads/trunk Commit: 23d4355a1c86cefdeb04936265a820723a3f5c15 Parents: 9910bd5 Author: Tomaz Muraus <[email protected]> Authored: Thu Aug 14 11:30:08 2014 +0200 Committer: Tomaz Muraus <[email protected]> Committed: Thu Aug 14 11:48:40 2014 +0200 ---------------------------------------------------------------------- libcloud/common/openstack_identity.py | 61 +++++++++++++++----- libcloud/test/common/test_openstack_identity.py | 49 +++++++++++++++- 2 files changed, 92 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/23d4355a/libcloud/common/openstack_identity.py ---------------------------------------------------------------------- diff --git a/libcloud/common/openstack_identity.py b/libcloud/common/openstack_identity.py index dec8f43..f208258 100644 --- a/libcloud/common/openstack_identity.py +++ b/libcloud/common/openstack_identity.py @@ -879,8 +879,24 @@ class OpenStackIdentity_3_0_Connection(OpenStackIdentityConnection): name = 'OpenStack Identity API v3.x' auth_version = '3.0' - def __init__(self, auth_url, user_id, key, tenant_name=None, timeout=None, - parent_conn=None): + def __init__(self, auth_url, user_id, key, tenant_name=None, + domain_name='Default', scope_to='project', + timeout=None, parent_conn=None): + """ + :param tenant_name: Name of the project this user belongs to. Note: + When scope_to is set to project, this argument + control to which project to scope the token to. + :type tenant_name: ``str`` + + :param domain_name: Domain the user belongs to. Note: Then scope_to + is set to token, this argument controls to which + domain to scope the token to. + :type domain_name: ``str`` + + :param scope_to: Whether to scope a token to a "project" or a + "domain" + :type scope_to: ``str`` + """ super(OpenStackIdentity_3_0_Connection, self).__init__(auth_url=auth_url, user_id=user_id, @@ -888,6 +904,19 @@ class OpenStackIdentity_3_0_Connection(OpenStackIdentityConnection): tenant_name=tenant_name, timeout=timeout, parent_conn=parent_conn) + if scope_to not in ['project', 'domain']: + raise ValueError('Invalid value for "scope_to" argument: %s' % + (scope_to)) + + if scope_to == 'project' and (not tenant_name or not domain_name): + raise ValueError('Must provide tenant_name and domain_name ' + 'argument') + elif scope_to == 'domain' and not domain_name: + raise ValueError('Must provide domain_name argument') + + self.tenant_name = tenant_name + self.domain_name = domain_name + self.scope_to = scope_to self.auth_user_roles = None def authenticate(self, force=False): @@ -897,9 +926,6 @@ class OpenStackIdentity_3_0_Connection(OpenStackIdentityConnection): if not self._is_authentication_needed(force=force): return self - # TODO: Support for custom domain - domain = 'Default' - data = { 'auth': { 'identity': { @@ -907,33 +933,36 @@ class OpenStackIdentity_3_0_Connection(OpenStackIdentityConnection): 'password': { 'user': { 'domain': { - 'name': domain + 'name': self.domain_name }, 'name': self.user_id, 'password': self.key } } - }, - 'scope': { - 'project': { - 'domain': { - 'name': domain - }, - 'name': self.tenant_name - } } } } - if self.tenant_name: + if self.scope_to == 'project': + # Scope token to project (tenant) data['auth']['scope'] = { 'project': { 'domain': { - 'name': domain + 'name': self.domain_name }, 'name': self.tenant_name } } + elif self.domain_name: + # Scope token to domain + data['auth']['scope'] = { + 'domain': { + 'name': self.domain_name + } + } + else: + raise ValueError('Token needs to be scoped either to project or ' + 'a domain') data = json.dumps(data) response = self.request('/v3/auth/tokens', data=data, http://git-wip-us.apache.org/repos/asf/libcloud/blob/23d4355a/libcloud/test/common/test_openstack_identity.py ---------------------------------------------------------------------- diff --git a/libcloud/test/common/test_openstack_identity.py b/libcloud/test/common/test_openstack_identity.py index e84222b..6057401 100644 --- a/libcloud/test/common/test_openstack_identity.py +++ b/libcloud/test/common/test_openstack_identity.py @@ -14,7 +14,6 @@ # limitations under the License. import sys -import unittest import datetime try: @@ -33,6 +32,7 @@ from libcloud.common.openstack_identity import OpenStackServiceCatalog from libcloud.common.openstack_identity import OpenStackIdentity_3_0_Connection from libcloud.compute.drivers.openstack import OpenStack_1_0_NodeDriver +from libcloud.test import unittest from libcloud.test import MockHttp from libcloud.test.secrets import OPENSTACK_PARAMS from libcloud.test.file_fixtures import ComputeFileFixtures @@ -229,9 +229,54 @@ class OpenStackIdentity_3_0_ConnectionTests(unittest.TestCase): self.auth_instance = OpenStackIdentity_3_0_Connection(auth_url='http://none', user_id='test', - key='test') + key='test', + tenant_name='test') self.auth_instance.auth_token = 'mock' + def test_scope_to_argument(self): + # Invalid scope_to value + expected_msg = 'Invalid value for "scope_to" argument: foo' + self.assertRaisesRegexp(ValueError, expected_msg, + OpenStackIdentity_3_0_Connection, + auth_url='http://none', + user_id='test', + key='test', + scope_to='foo') + + # Missing tenant_name + expected_msg = 'Must provide tenant_name and domain_name argument' + self.assertRaisesRegexp(ValueError, expected_msg, + OpenStackIdentity_3_0_Connection, + auth_url='http://none', + user_id='test', + key='test', + scope_to='project') + + # Missing domain_name + expected_msg = 'Must provide domain_name argument' + self.assertRaisesRegexp(ValueError, expected_msg, + OpenStackIdentity_3_0_Connection, + auth_url='http://none', + user_id='test', + key='test', + scope_to='domain', + domain_name=None) + + # Scope to project all ok + OpenStackIdentity_3_0_Connection(auth_url='http://none', + user_id='test', + key='test', + scope_to='project', + tenant_name='test', + domain_name='Default') + # Scope to domain + OpenStackIdentity_3_0_Connection(auth_url='http://none', + user_id='test', + key='test', + scope_to='domain', + tenant_name=None, + domain_name='Default') + def test_list_supported_versions(self): OpenStackIdentity_3_0_MockHttp.type = 'v3'
