Handle federated tokens
Federated tokens don't include domains in the user object. Keystoneclient should be able to estimate whether the token is a federated one and, if so, don't expect user domain information. In case of the federated token keystoneclient returns None in response to user_domain_name and user_domain_id calls. Co-Authored-By: Steve Martinelli <stevemar@ca.ibm.com> Closes-Bug: #1346820 Change-Id: I3453275fa1b0a41b1c015b0c3a92895a77d69a41
This commit is contained in:
		 Marek Denis
					Marek Denis
				
			
				
					committed by
					
						 Steve Martinelli
						Steve Martinelli
					
				
			
			
				
	
			
			
			 Steve Martinelli
						Steve Martinelli
					
				
			
						parent
						
							3305c7be4b
						
					
				
				
					commit
					7006f9b008
				
			| @@ -388,6 +388,14 @@ class AccessInfo(dict): | |||||||
|         """ |         """ | ||||||
|         raise NotImplementedError() |         raise NotImplementedError() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_federated(self): | ||||||
|  |         """Returns true if federation was used to get the token. | ||||||
|  |  | ||||||
|  |         :returns: boolean | ||||||
|  |         """ | ||||||
|  |         raise NotImplementedError() | ||||||
|  |  | ||||||
|  |  | ||||||
| class AccessInfoV2(AccessInfo): | class AccessInfoV2(AccessInfo): | ||||||
|     """An object for encapsulating a raw v2 auth token from identity |     """An object for encapsulating a raw v2 auth token from identity | ||||||
| @@ -576,6 +584,10 @@ class AccessInfoV2(AccessInfo): | |||||||
|     def oauth_consumer_id(self): |     def oauth_consumer_id(self): | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_federated(self): | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |  | ||||||
| class AccessInfoV3(AccessInfo): | class AccessInfoV3(AccessInfo): | ||||||
|     """An object for encapsulating a raw v3 auth token from identity |     """An object for encapsulating a raw v3 auth token from identity | ||||||
| @@ -604,6 +616,10 @@ class AccessInfoV3(AccessInfo): | |||||||
|     def has_service_catalog(self): |     def has_service_catalog(self): | ||||||
|         return 'catalog' in self |         return 'catalog' in self | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_federated(self): | ||||||
|  |         return 'OS-FEDERATION' in self['user'] | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def expires(self): |     def expires(self): | ||||||
|         return timeutils.parse_isotime(self['expires_at']) |         return timeutils.parse_isotime(self['expires_at']) | ||||||
| @@ -618,11 +634,21 @@ class AccessInfoV3(AccessInfo): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def user_domain_id(self): |     def user_domain_id(self): | ||||||
|  |         try: | ||||||
|             return self['user']['domain']['id'] |             return self['user']['domain']['id'] | ||||||
|  |         except KeyError: | ||||||
|  |             if self.is_federated: | ||||||
|  |                 return None | ||||||
|  |             raise | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def user_domain_name(self): |     def user_domain_name(self): | ||||||
|  |         try: | ||||||
|             return self['user']['domain']['name'] |             return self['user']['domain']['name'] | ||||||
|  |         except KeyError: | ||||||
|  |             if self.is_federated: | ||||||
|  |                 return None | ||||||
|  |             raise | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def role_ids(self): |     def role_ids(self): | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ from keystoneclient.fixture.discovery import *  # noqa | |||||||
| from keystoneclient.fixture.exception import FixtureValidationError  # noqa | from keystoneclient.fixture.exception import FixtureValidationError  # noqa | ||||||
| from keystoneclient.fixture.v2 import Token as V2Token  # noqa | from keystoneclient.fixture.v2 import Token as V2Token  # noqa | ||||||
| from keystoneclient.fixture.v3 import Token as V3Token  # noqa | from keystoneclient.fixture.v3 import Token as V3Token  # noqa | ||||||
|  | from keystoneclient.fixture.v3 import V3FederationToken  # noqa | ||||||
|  |  | ||||||
| __all__ = ['DiscoveryList', | __all__ = ['DiscoveryList', | ||||||
|            'FixtureValidationError', |            'FixtureValidationError', | ||||||
| @@ -32,4 +33,5 @@ __all__ = ['DiscoveryList', | |||||||
|            'V3Discovery', |            'V3Discovery', | ||||||
|            'V2Token', |            'V2Token', | ||||||
|            'V3Token', |            'V3Token', | ||||||
|  |            'V3FederationToken', | ||||||
|            ] |            ] | ||||||
|   | |||||||
| @@ -352,3 +352,31 @@ class Token(dict): | |||||||
|     def set_oauth(self, access_token_id=None, consumer_id=None): |     def set_oauth(self, access_token_id=None, consumer_id=None): | ||||||
|         self.oauth_access_token_id = access_token_id or uuid.uuid4().hex |         self.oauth_access_token_id = access_token_id or uuid.uuid4().hex | ||||||
|         self.oauth_consumer_id = consumer_id or uuid.uuid4().hex |         self.oauth_consumer_id = consumer_id or uuid.uuid4().hex | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class V3FederationToken(Token): | ||||||
|  |     """A V3 Keystone Federation token that can be used for testing. | ||||||
|  |  | ||||||
|  |     Similar to V3Token, this object is designed to allow clients to generate | ||||||
|  |     a correct V3 federation token for use in test code. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, methods=None, identity_provider=None, protocol=None, | ||||||
|  |                  groups=None): | ||||||
|  |         methods = methods or ['saml2'] | ||||||
|  |         super(V3FederationToken, self).__init__(methods=methods) | ||||||
|  |         # NOTE(stevemar): Federated tokens do not have a domain for the user | ||||||
|  |         del self._user['domain'] | ||||||
|  |         self.add_federation_info_to_user(identity_provider, protocol, groups) | ||||||
|  |  | ||||||
|  |     def add_federation_info_to_user(self, identity_provider=None, | ||||||
|  |                                     protocol=None, groups=None): | ||||||
|  |         data = { | ||||||
|  |             "OS-FEDERATION": { | ||||||
|  |                 "identity_provider": identity_provider or uuid.uuid4().hex, | ||||||
|  |                 "protocol": protocol or uuid.uuid4().hex, | ||||||
|  |                 "groups": groups or [{"id": uuid.uuid4().hex}] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         self._user.update(data) | ||||||
|  |         return data | ||||||
|   | |||||||
| @@ -181,3 +181,10 @@ class AccessInfoTest(utils.TestCase): | |||||||
|         auth_ref = access.AccessInfo.factory(body=token, |         auth_ref = access.AccessInfo.factory(body=token, | ||||||
|                                              auth_token=new_auth_token) |                                              auth_token=new_auth_token) | ||||||
|         self.assertEqual(new_auth_token, auth_ref.auth_token) |         self.assertEqual(new_auth_token, auth_ref.auth_token) | ||||||
|  |  | ||||||
|  |     def test_federated_property_standard_token(self): | ||||||
|  |         """Check if is_federated property returns expected value.""" | ||||||
|  |         token = fixture.V3Token() | ||||||
|  |         token.set_project_scope() | ||||||
|  |         auth_ref = access.AccessInfo.factory(body=token) | ||||||
|  |         self.assertFalse(auth_ref.is_federated) | ||||||
|   | |||||||
| @@ -13,7 +13,9 @@ | |||||||
| import copy | import copy | ||||||
| import uuid | import uuid | ||||||
|  |  | ||||||
|  | from keystoneclient import access | ||||||
| from keystoneclient import exceptions | from keystoneclient import exceptions | ||||||
|  | from keystoneclient import fixture | ||||||
| from keystoneclient.tests.v3 import utils | from keystoneclient.tests.v3 import utils | ||||||
| from keystoneclient.v3.contrib.federation import base | from keystoneclient.v3.contrib.federation import base | ||||||
| from keystoneclient.v3.contrib.federation import identity_providers | from keystoneclient.v3.contrib.federation import identity_providers | ||||||
| @@ -385,3 +387,25 @@ class FederationDomainTests(utils.TestCase): | |||||||
|         self.assertEqual(len(domains_ref), len(returned_list)) |         self.assertEqual(len(domains_ref), len(returned_list)) | ||||||
|         for domain in returned_list: |         for domain in returned_list: | ||||||
|             self.assertIsInstance(domain, self.model) |             self.assertIsInstance(domain, self.model) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FederatedTokenTests(utils.TestCase): | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         super(FederatedTokenTests, self).setUp() | ||||||
|  |         token = fixture.V3FederationToken() | ||||||
|  |         token.set_project_scope() | ||||||
|  |         token.add_role() | ||||||
|  |         self.federated_token = access.AccessInfo.factory(body=token) | ||||||
|  |  | ||||||
|  |     def test_federated_property_federated_token(self): | ||||||
|  |         """Check if is_federated property returns expected value.""" | ||||||
|  |         self.assertTrue(self.federated_token.is_federated) | ||||||
|  |  | ||||||
|  |     def test_get_user_domain_name(self): | ||||||
|  |         """Ensure a federated user's domain name does not exist.""" | ||||||
|  |         self.assertIsNone(self.federated_token.user_domain_name) | ||||||
|  |  | ||||||
|  |     def test_get_user_domain_id(self): | ||||||
|  |         """Ensure a federated user's domain ID does not exist.""" | ||||||
|  |         self.assertIsNone(self.federated_token.user_domain_id) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user