Allow full v3 authentication
Allow authenticating with ids and fetching domain scoped tokens. Changes the acceptable parameters to more specific parameter names so that _id and _name parameters can no longer be confused. This tries to not change the config file and existing credential loading paths. Closes-Bug: #1420605 Change-Id: If5a889be5826d60bf61dbb84661a5896cb094875
This commit is contained in:
parent
1c78f96b71
commit
9750461e82
@ -76,7 +76,7 @@ class TestDefaultProjectId (base.BaseIdentityV3AdminTest):
|
|||||||
# create a new client with user's credentials (NOTE: unscoped token!)
|
# create a new client with user's credentials (NOTE: unscoped token!)
|
||||||
creds = auth.KeystoneV3Credentials(username=user_name,
|
creds = auth.KeystoneV3Credentials(username=user_name,
|
||||||
password=user_name,
|
password=user_name,
|
||||||
domain_name=dom_name)
|
user_domain_name=dom_name)
|
||||||
auth_provider = manager.get_auth_provider(creds)
|
auth_provider = manager.get_auth_provider(creds)
|
||||||
creds = auth_provider.fill_credentials()
|
creds = auth_provider.fill_credentials()
|
||||||
admin_client = clients.Manager(credentials=creds)
|
admin_client = clients.Manager(credentials=creds)
|
||||||
|
@ -144,11 +144,11 @@ class RolesV3TestJSON(base.BaseIdentityV3AdminTest):
|
|||||||
self.client.add_group_user(self.group_body['id'], self.user_body['id'])
|
self.client.add_group_user(self.group_body['id'], self.user_body['id'])
|
||||||
self.addCleanup(self.client.delete_group_user,
|
self.addCleanup(self.client.delete_group_user,
|
||||||
self.group_body['id'], self.user_body['id'])
|
self.group_body['id'], self.user_body['id'])
|
||||||
body = self.token.auth(user=self.user_body['id'],
|
body = self.token.auth(user_id=self.user_body['id'],
|
||||||
password=self.u_password,
|
password=self.u_password,
|
||||||
user_domain=self.domain['name'],
|
user_domain_name=self.domain['name'],
|
||||||
project=self.project['name'],
|
project_name=self.project['name'],
|
||||||
project_domain=self.domain['name'])
|
project_domain_name=self.domain['name'])
|
||||||
roles = body['token']['roles']
|
roles = body['token']['roles']
|
||||||
self.assertEqual(len(roles), 1)
|
self.assertEqual(len(roles), 1)
|
||||||
self.assertEqual(roles[0]['id'], self.role['id'])
|
self.assertEqual(roles[0]['id'], self.role['id'])
|
||||||
|
@ -36,7 +36,8 @@ class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
|
|||||||
email=u_email)
|
email=u_email)
|
||||||
self.addCleanup(self.client.delete_user, user['id'])
|
self.addCleanup(self.client.delete_user, user['id'])
|
||||||
# Perform Authentication
|
# Perform Authentication
|
||||||
resp = self.token.auth(user['id'], u_password).response
|
resp = self.token.auth(user_id=user['id'],
|
||||||
|
password=u_password).response
|
||||||
subject_token = resp['x-subject-token']
|
subject_token = resp['x-subject-token']
|
||||||
# Perform GET Token
|
# Perform GET Token
|
||||||
token_details = self.client.get_token(subject_token)
|
token_details = self.client.get_token(subject_token)
|
||||||
@ -87,7 +88,7 @@ class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
|
|||||||
role['id'])
|
role['id'])
|
||||||
|
|
||||||
# Get an unscoped token.
|
# Get an unscoped token.
|
||||||
token_auth = self.token.auth(user=user['id'],
|
token_auth = self.token.auth(user_id=user['id'],
|
||||||
password=user_password)
|
password=user_password)
|
||||||
|
|
||||||
token_id = token_auth.response['x-subject-token']
|
token_id = token_auth.response['x-subject-token']
|
||||||
@ -110,8 +111,8 @@ class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
|
|||||||
|
|
||||||
# Use the unscoped token to get a scoped token.
|
# Use the unscoped token to get a scoped token.
|
||||||
token_auth = self.token.auth(token=token_id,
|
token_auth = self.token.auth(token=token_id,
|
||||||
project=project1_name,
|
project_name=project1_name,
|
||||||
project_domain='Default')
|
project_domain_name='Default')
|
||||||
token1_id = token_auth.response['x-subject-token']
|
token1_id = token_auth.response['x-subject-token']
|
||||||
|
|
||||||
self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
|
self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
|
||||||
@ -140,8 +141,8 @@ class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
|
|||||||
|
|
||||||
# Now get another scoped token using the unscoped token.
|
# Now get another scoped token using the unscoped token.
|
||||||
token_auth = self.token.auth(token=token_id,
|
token_auth = self.token.auth(token=token_id,
|
||||||
project=project2_name,
|
project_name=project2_name,
|
||||||
project_domain='Default')
|
project_domain_name='Default')
|
||||||
|
|
||||||
self.assertEqual(project2['id'],
|
self.assertEqual(project2['id'],
|
||||||
token_auth['token']['project']['id'])
|
token_auth['token']['project']['id'])
|
||||||
|
@ -79,7 +79,8 @@ class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
|
|||||||
new_password = data_utils.rand_name('pass1')
|
new_password = data_utils.rand_name('pass1')
|
||||||
self.client.update_user_password(user['id'], new_password,
|
self.client.update_user_password(user['id'], new_password,
|
||||||
original_password)
|
original_password)
|
||||||
resp = self.token.auth(user['id'], new_password).response
|
resp = self.token.auth(user_id=user['id'],
|
||||||
|
password=new_password).response
|
||||||
subject_token = resp['x-subject-token']
|
subject_token = resp['x-subject-token']
|
||||||
# Perform GET Token to verify and confirm password is updated
|
# Perform GET Token to verify and confirm password is updated
|
||||||
token_details = self.client.get_token(subject_token)
|
token_details = self.client.get_token(subject_token)
|
||||||
|
@ -328,11 +328,17 @@ class KeystoneV3AuthProvider(KeystoneAuthProvider):
|
|||||||
|
|
||||||
def _auth_params(self):
|
def _auth_params(self):
|
||||||
return dict(
|
return dict(
|
||||||
user=self.credentials.username,
|
user_id=self.credentials.user_id,
|
||||||
|
username=self.credentials.username,
|
||||||
password=self.credentials.password,
|
password=self.credentials.password,
|
||||||
project=self.credentials.tenant_name,
|
project_id=self.credentials.project_id,
|
||||||
user_domain=self.credentials.user_domain_name,
|
project_name=self.credentials.project_name,
|
||||||
project_domain=self.credentials.project_domain_name,
|
user_domain_id=self.credentials.user_domain_id,
|
||||||
|
user_domain_name=self.credentials.user_domain_name,
|
||||||
|
project_domain_id=self.credentials.project_domain_id,
|
||||||
|
project_domain_name=self.credentials.project_domain_name,
|
||||||
|
domain_id=self.credentials.domain_id,
|
||||||
|
domain_name=self.credentials.domain_name,
|
||||||
auth_data=True)
|
auth_data=True)
|
||||||
|
|
||||||
def _fill_credentials(self, auth_data_body):
|
def _fill_credentials(self, auth_data_body):
|
||||||
@ -569,7 +575,7 @@ class KeystoneV3Credentials(Credentials):
|
|||||||
Credentials suitable for the Keystone Identity V3 API
|
Credentials suitable for the Keystone Identity V3 API
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ATTRIBUTES = ['domain_name', 'password', 'tenant_name', 'username',
|
ATTRIBUTES = ['domain_id', 'domain_name', 'password', 'username',
|
||||||
'project_domain_id', 'project_domain_name', 'project_id',
|
'project_domain_id', 'project_domain_name', 'project_id',
|
||||||
'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']
|
||||||
@ -615,6 +621,8 @@ class KeystoneV3Credentials(Credentials):
|
|||||||
- None
|
- None
|
||||||
- Project id (optional domain)
|
- Project id (optional domain)
|
||||||
- Project name and its domain id/name
|
- Project name and its domain id/name
|
||||||
|
- Domain id
|
||||||
|
- Domain name
|
||||||
"""
|
"""
|
||||||
valid_user_domain = any(
|
valid_user_domain = any(
|
||||||
[self.user_domain_id is not None,
|
[self.user_domain_id is not None,
|
||||||
@ -625,11 +633,16 @@ class KeystoneV3Credentials(Credentials):
|
|||||||
valid_user = any(
|
valid_user = any(
|
||||||
[self.user_id is not None,
|
[self.user_id is not None,
|
||||||
self.username is not None and valid_user_domain])
|
self.username is not None and valid_user_domain])
|
||||||
valid_project = any(
|
valid_project_scope = any(
|
||||||
[self.project_name is None and self.project_id is None,
|
[self.project_name is None and self.project_id is None,
|
||||||
self.project_id is not None,
|
self.project_id is not None,
|
||||||
self.project_name is not None and valid_project_domain])
|
self.project_name is not None and valid_project_domain])
|
||||||
return all([self.password is not None, valid_user, valid_project])
|
valid_domain_scope = any(
|
||||||
|
[self.domain_id is None and self.domain_name is None,
|
||||||
|
self.domain_id or self.domain_name])
|
||||||
|
return all([self.password is not None,
|
||||||
|
valid_user,
|
||||||
|
valid_project_scope and valid_domain_scope])
|
||||||
|
|
||||||
|
|
||||||
IDENTITY_VERSION = {'v2': (KeystoneV2Credentials, KeystoneV2AuthProvider),
|
IDENTITY_VERSION = {'v2': (KeystoneV2Credentials, KeystoneV2AuthProvider),
|
||||||
|
@ -37,22 +37,30 @@ class V3TokenClientJSON(rest_client.RestClient):
|
|||||||
|
|
||||||
self.auth_url = auth_url
|
self.auth_url = auth_url
|
||||||
|
|
||||||
def auth(self, user=None, password=None, project=None, user_type='id',
|
def auth(self, user_id=None, username=None, password=None, project_id=None,
|
||||||
user_domain=None, project_domain=None, token=None):
|
project_name=None, user_domain_id=None, user_domain_name=None,
|
||||||
|
project_domain_id=None, project_domain_name=None, domain_id=None,
|
||||||
|
domain_name=None, token=None):
|
||||||
"""
|
"""
|
||||||
:param user: user id or name, as specified in user_type
|
:param user_id: user id
|
||||||
:param user_domain: the user domain
|
:param username: user name
|
||||||
:param project_domain: the project domain
|
:param user_domain_id: the user domain id
|
||||||
|
:param user_domain_name: the user domain name
|
||||||
|
:param project_domain_id: the project domain id
|
||||||
|
:param project_domain_name: the project domain name
|
||||||
|
:param domain_id: a domain id to scope to
|
||||||
|
:param domain_name: a domain name to scope to
|
||||||
|
:param project_id: a project id to scope to
|
||||||
|
:param project_name: a project name to scope to
|
||||||
:param token: a token to re-scope.
|
:param token: a token to re-scope.
|
||||||
|
|
||||||
Accepts different combinations of credentials. Restrictions:
|
Accepts different combinations of credentials.
|
||||||
- project and domain are only name (no id)
|
|
||||||
Sample sample valid combinations:
|
Sample sample valid combinations:
|
||||||
- token
|
- token
|
||||||
- token, project, project_domain
|
- token, project_name, project_domain_id
|
||||||
- user_id, password
|
- user_id, password
|
||||||
- username, password, user_domain
|
- username, password, user_domain_id
|
||||||
- username, password, project, user_domain, project_domain
|
- username, password, project_name, user_domain_id, project_domain_id
|
||||||
Validation is left to the server side.
|
Validation is left to the server side.
|
||||||
"""
|
"""
|
||||||
creds = {
|
creds = {
|
||||||
@ -68,25 +76,45 @@ class V3TokenClientJSON(rest_client.RestClient):
|
|||||||
id_obj['token'] = {
|
id_obj['token'] = {
|
||||||
'id': token
|
'id': token
|
||||||
}
|
}
|
||||||
if user and password:
|
|
||||||
|
if (user_id or username) and password:
|
||||||
id_obj['methods'].append('password')
|
id_obj['methods'].append('password')
|
||||||
id_obj['password'] = {
|
id_obj['password'] = {
|
||||||
'user': {
|
'user': {
|
||||||
'password': password,
|
'password': password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if user_type == 'id':
|
if user_id:
|
||||||
id_obj['password']['user']['id'] = user
|
id_obj['password']['user']['id'] = user_id
|
||||||
else:
|
else:
|
||||||
id_obj['password']['user']['name'] = user
|
id_obj['password']['user']['name'] = username
|
||||||
if user_domain is not None:
|
|
||||||
_domain = dict(name=user_domain)
|
_domain = None
|
||||||
|
if user_domain_id is not None:
|
||||||
|
_domain = dict(id=user_domain_id)
|
||||||
|
elif user_domain_name is not None:
|
||||||
|
_domain = dict(name=user_domain_name)
|
||||||
|
if _domain:
|
||||||
id_obj['password']['user']['domain'] = _domain
|
id_obj['password']['user']['domain'] = _domain
|
||||||
if project is not None:
|
|
||||||
_domain = dict(name=project_domain)
|
if (project_id or project_name):
|
||||||
_project = dict(name=project, domain=_domain)
|
_project = dict()
|
||||||
scope = dict(project=_project)
|
|
||||||
creds['auth']['scope'] = scope
|
if project_id:
|
||||||
|
_project['id'] = project_id
|
||||||
|
elif project_name:
|
||||||
|
_project['name'] = project_name
|
||||||
|
|
||||||
|
if project_domain_id is not None:
|
||||||
|
_project['domain'] = {'id': project_domain_id}
|
||||||
|
elif project_domain_name is not None:
|
||||||
|
_project['domain'] = {'name': project_domain_name}
|
||||||
|
|
||||||
|
creds['auth']['scope'] = dict(project=_project)
|
||||||
|
elif domain_id:
|
||||||
|
creds['auth']['scope'] = dict(domain={'id': domain_id})
|
||||||
|
elif domain_name:
|
||||||
|
creds['auth']['scope'] = dict(domain={'name': domain_name})
|
||||||
|
|
||||||
body = json.dumps(creds)
|
body = json.dumps(creds)
|
||||||
resp, body = self.post(self.auth_url, body=body)
|
resp, body = self.post(self.auth_url, body=body)
|
||||||
@ -120,15 +148,22 @@ class V3TokenClientJSON(rest_client.RestClient):
|
|||||||
|
|
||||||
return resp, json.loads(resp_body)
|
return resp, json.loads(resp_body)
|
||||||
|
|
||||||
def get_token(self, user, password, project=None, project_domain='Default',
|
def get_token(self, **kwargs):
|
||||||
user_domain='Default', auth_data=False):
|
|
||||||
"""
|
"""
|
||||||
:param user: username
|
|
||||||
Returns (token id, token data) for supplied credentials
|
Returns (token id, token data) for supplied credentials
|
||||||
"""
|
"""
|
||||||
body = self.auth(user, password, project, user_type='name',
|
|
||||||
user_domain=user_domain,
|
auth_data = kwargs.pop('auth_data', False)
|
||||||
project_domain=project_domain)
|
|
||||||
|
if not (kwargs.get('user_domain_id') or
|
||||||
|
kwargs.get('user_domain_name')):
|
||||||
|
kwargs['user_domain_name'] = 'Default'
|
||||||
|
|
||||||
|
if not (kwargs.get('project_domain_id') or
|
||||||
|
kwargs.get('project_domain_name')):
|
||||||
|
kwargs['project_domain_name'] = 'Default'
|
||||||
|
|
||||||
|
body = self.auth(**kwargs)
|
||||||
|
|
||||||
token = body.response.get('x-subject-token')
|
token = body.response.get('x-subject-token')
|
||||||
if auth_data:
|
if auth_data:
|
||||||
|
@ -43,7 +43,8 @@ class FakeKeystoneV3Credentials(auth.KeystoneV3Credentials):
|
|||||||
username='fake_username',
|
username='fake_username',
|
||||||
password='fake_password',
|
password='fake_password',
|
||||||
user_domain_name='fake_domain_name',
|
user_domain_name='fake_domain_name',
|
||||||
project_name='fake_tenant_name'
|
project_name='fake_tenant_name',
|
||||||
|
project_domain_name='fake_domain_name'
|
||||||
)
|
)
|
||||||
super(FakeKeystoneV3Credentials, self).__init__(**creds)
|
super(FakeKeystoneV3Credentials, self).__init__(**creds)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user