Fix V3 credential behavior, documentation

Fixing V3 credential behavior so that contradicting parameter combinations
do not result in unpredictable behavior.  Updating accounts.yaml.sample
file to reference the correct location of the credentials
classes and to describe the updated behavior of Identity V3 attributes.

Change-Id: I29efe778afcb1e4a55dffd6a8ed8212d62a4dd15
This commit is contained in:
John Warren 2016-02-26 15:32:37 -05:00
parent 271b340572
commit b10c6caa1a
3 changed files with 76 additions and 3 deletions

View File

@ -3,7 +3,25 @@
# This is required to provide isolation between test for running in parallel # This is required to provide isolation between test for running in parallel
# #
# Valid fields for credentials are defined in the descendants of # Valid fields for credentials are defined in the descendants of
# auth.Credentials - see KeystoneV[2|3]Credentials.CONF_ATTRIBUTES # lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES
#
# The fields in KeystoneV3Credentials behave as follows:
#
# tenant_[id|name] also sets project_[id|name].
#
# project_[id|name] also sets tenant_[id|name].
#
# Providing distinct values for both tenant_[id|name] and project_[id|name]
# will result in an InvalidCredentials exception.
#
# The value of project_domain_[id|name] is used for user_domain_[id|name] if
# the latter is not specified.
#
# The value of user_domain_[id|name] is used for project_domain_[id|name] if
# the latter is not specified.
#
# The value of domain_[id|name] is used for project_domain_[id|name] if not
# specified and user_domain_[id|name] if not specified.
- username: 'user_1' - username: 'user_1'
tenant_name: 'test_tenant_1' tenant_name: 'test_tenant_1'

View File

@ -622,6 +622,9 @@ class KeystoneV2Credentials(Credentials):
return None not in (self.username, self.password) return None not in (self.username, self.password)
COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')]
class KeystoneV3Credentials(Credentials): class KeystoneV3Credentials(Credentials):
"""Credentials suitable for the Keystone Identity V3 API""" """Credentials suitable for the Keystone Identity V3 API"""
@ -630,6 +633,16 @@ class KeystoneV3Credentials(Credentials):
'project_name', 'tenant_id', 'tenant_name', 'user_domain_id', 'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
'user_domain_name', 'user_id'] 'user_domain_name', 'user_id']
def _apply_credentials(self, attr):
for (key1, key2) in COLLISIONS:
val1 = attr.get(key1)
val2 = attr.get(key2)
if val1 and val2 and val1 != val2:
msg = ('Cannot have conflicting values for %s and %s' %
(key1, key2))
raise exceptions.InvalidCredentials(msg)
super(KeystoneV3Credentials, self)._apply_credentials(attr)
def __setattr__(self, key, value): def __setattr__(self, key, value):
parent = super(KeystoneV3Credentials, self) parent = super(KeystoneV3Credentials, self)
# for tenant_* set both project and tenant # for tenant_* set both project and tenant
@ -657,8 +670,10 @@ class KeystoneV3Credentials(Credentials):
parent.__setattr__('user_domain_name', value) parent.__setattr__('user_domain_name', value)
# support domain_name coming from config # support domain_name coming from config
if key == 'domain_name': if key == 'domain_name':
parent.__setattr__('user_domain_name', value) if self.user_domain_name is None:
parent.__setattr__('project_domain_name', value) parent.__setattr__('user_domain_name', value)
if self.project_domain_name is None:
parent.__setattr__('project_domain_name', value)
# finally trigger default behaviour for all attributes # finally trigger default behaviour for all attributes
parent.__setattr__(key, value) parent.__setattr__(key, value)

View File

@ -530,3 +530,43 @@ class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
expected = 'http://fake_url/v3' expected = 'http://fake_url/v3'
self._test_base_url_helper(expected, filters, ('token', auth_data)) self._test_base_url_helper(expected, filters, ('token', auth_data))
class TestKeystoneV3Credentials(base.TestCase):
def testSetAttrUserDomain(self):
creds = auth.KeystoneV3Credentials()
creds.user_domain_name = 'user_domain'
creds.domain_name = 'domain'
self.assertEqual('user_domain', creds.user_domain_name)
creds = auth.KeystoneV3Credentials()
creds.domain_name = 'domain'
creds.user_domain_name = 'user_domain'
self.assertEqual('user_domain', creds.user_domain_name)
def testSetAttrProjectDomain(self):
creds = auth.KeystoneV3Credentials()
creds.project_domain_name = 'project_domain'
creds.domain_name = 'domain'
self.assertEqual('project_domain', creds.user_domain_name)
creds = auth.KeystoneV3Credentials()
creds.domain_name = 'domain'
creds.project_domain_name = 'project_domain'
self.assertEqual('project_domain', creds.project_domain_name)
def testProjectTenantNoCollision(self):
creds = auth.KeystoneV3Credentials(tenant_id='tenant')
self.assertEqual('tenant', creds.project_id)
creds = auth.KeystoneV3Credentials(project_id='project')
self.assertEqual('project', creds.tenant_id)
creds = auth.KeystoneV3Credentials(tenant_name='tenant')
self.assertEqual('tenant', creds.project_name)
creds = auth.KeystoneV3Credentials(project_name='project')
self.assertEqual('project', creds.tenant_name)
def testProjectTenantCollision(self):
attrs = {'tenant_id': 'tenant', 'project_id': 'project'}
self.assertRaises(
exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)
attrs = {'tenant_name': 'tenant', 'project_name': 'project'}
self.assertRaises(
exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)