diff options
Diffstat (limited to 'keystoneclient/v3/client.py')
-rw-r--r-- | keystoneclient/v3/client.py | 180 |
1 files changed, 161 insertions, 19 deletions
diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py index c0b613e..6c11ab1 100644 --- a/keystoneclient/v3/client.py +++ b/keystoneclient/v3/client.py @@ -15,10 +15,11 @@ import json import logging +from keystoneclient import exceptions from keystoneclient.v2_0 import client from keystoneclient.v3 import credentials -from keystoneclient.v3 import endpoints from keystoneclient.v3 import domains +from keystoneclient.v3 import endpoints from keystoneclient.v3 import groups from keystoneclient.v3 import policies from keystoneclient.v3 import projects @@ -33,40 +34,60 @@ _logger = logging.getLogger(__name__) class Client(client.Client): """Client for the OpenStack Identity API v3. + :param string user_id: User ID for authentication. (optional) :param string username: Username for authentication. (optional) + :param string user_domain_id: User's domain ID for authentication. + (optional) + :param string user_domain_name: User's domain name for authentication. + (optional) :param string password: Password for authentication. (optional) :param string token: Token for authentication. (optional) - :param string tenant_name: Tenant id. (optional) - :param string tenant_id: Tenant name. (optional) - :param string auth_url: Keystone service endpoint for authorization. + :param string domain_id: Domain ID for domain scoping. (optional) + :param string domain_name: Domain name for domain scoping. (optional) + :param string project_id: Project ID for project scoping. (optional) + :param string project_name: Project name for project scoping. (optional) + :param string project_domain_id: Project's domain ID for project + scoping. (optional) + :param string project_domain_name: Project's domain name for project + scoping. (optional) + :param string tenant_name: Tenant name. (optional) + The tenant_name keyword argument is deprecated, + use project_name instead. + :param string tenant_id: Tenant id. (optional) + The tenant_id keyword argument is deprecated, + use project_id instead. + :param string auth_url: Identity service endpoint for authorization. :param string region_name: Name of a region to select when choosing an endpoint from the service catalog. - :param string endpoint: A user-supplied endpoint URL for the keystone + :param string endpoint: A user-supplied endpoint URL for the identity service. Lazy-authentication is possible for API service calls if endpoint is set at - instantiation.(optional) + instantiation. (optional) :param integer timeout: Allows customization of the timeout for client http requests. (optional) Example:: >>> from keystoneclient.v3 import client - >>> keystone = client.Client(username=USER, + >>> keystone = client.Client(user_domain_name=DOMAIN_NAME, + ... username=USER, ... password=PASS, - ... tenant_name=TENANT_NAME, + ... project_domain_name=PROJECT_DOMAIN_NAME, + ... project_name=PROJECT_NAME, ... auth_url=KEYSTONE_URL) ... - >>> keystone.tenants.list() + >>> keystone.projects.list() ... >>> user = keystone.users.get(USER_ID) >>> user.delete() """ - def __init__(self, endpoint=None, **kwargs): - """ Initialize a new client for the Keystone v3.0 API. """ - super(Client, self).__init__(endpoint=endpoint, **kwargs) + def __init__(self, **kwargs): + """ Initialize a new client for the Keystone v3 API. """ + super(Client, self).__init__(**kwargs) + self.version = 'v3' self.credentials = credentials.CredentialManager(self) self.endpoints = endpoints.EndpointManager(self) self.domains = domains.DomainManager(self) @@ -77,12 +98,133 @@ class Client(client.Client): self.services = services.ServiceManager(self) self.users = users.UserManager(self) - # NOTE(gabriel): If we have a pre-defined endpoint then we can - # get away with lazy auth. Otherwise auth immediately. - if endpoint: - self.management_url = endpoint - else: - self.authenticate() - def serialize(self, entity): return json.dumps(entity, sort_keys=True) + + def process_token(self): + """ Extract and process information from the new auth_ref. + + And set the relevant authentication information. + """ + super(Client, self).process_token() + if self.auth_ref.domain_scoped: + if not self.auth_ref.domain_id: + raise exceptions.AuthorizationFailure( + "Token didn't provide domain_id") + if self.management_url is None and self.auth_ref.management_url: + self.management_url = self.auth_ref.management_url[0] + self.domain_name = self.auth_ref.domain_name + self.domain_id = self.auth_ref.domain_id + + def get_raw_token_from_identity_service(self, auth_url, user_id=None, + username=None, + user_domain_id=None, + user_domain_name=None, + password=None, + domain_id=None, domain_name=None, + project_id=None, project_name=None, + project_domain_id=None, + project_domain_name=None, + token=None, **kwargs): + """ Authenticate against the v3 Identity API. + + :returns: (``resp``, ``body``) if authentication was successful. + :raises: AuthorizationFailure if unable to authenticate or validate + the existing authorization token + :raises: Unauthorized if authentication fails due to invalid token + + """ + try: + return self._do_auth( + auth_url, + user_id=user_id, + username=username, + user_domain_id=user_domain_id, + user_domain_name=user_domain_name, + password=password, + domain_id=domain_id, + domain_name=domain_name, + project_id=project_id, + project_name=project_name, + project_domain_id=project_domain_id, + project_domain_name=project_domain_name, + token=token) + except (exceptions.AuthorizationFailure, exceptions.Unauthorized): + _logger.debug('Authorization failed.') + raise + except Exception as e: + raise exceptions.AuthorizationFailure('Authorization failed: ' + '%s' % e) + + def _do_auth(self, auth_url, user_id=None, username=None, + user_domain_id=None, user_domain_name=None, password=None, + domain_id=None, domain_name=None, + project_id=None, project_name=None, project_domain_id=None, + project_domain_name=None, token=None): + headers = {} + url = auth_url + "/auth/tokens" + body = {'auth': {'identity': {}}} + ident = body['auth']['identity'] + + if token: + headers['X-Auth-Token'] = token + + ident['methods'] = ['token'] + ident['token'] = {} + ident['token']['id'] = token + + if password: + ident['methods'] = ['password'] + ident['password'] = {} + ident['password']['user'] = {} + user = ident['password']['user'] + user['password'] = password + + if user_id: + user['id'] = user_id + elif username: + user['name'] = username + + if user_domain_id or user_domain_name: + user['domain'] = {} + if user_domain_id: + user['domain']['id'] = user_domain_id + elif user_domain_name: + user['domain']['name'] = user_domain_name + + if (domain_id or domain_name) and (project_id or project_name): + raise ValueError('Authentication cannot be scoped to both domain' + ' and project.') + + if domain_id or domain_name: + body['auth']['scope'] = {} + scope = body['auth']['scope'] + scope['domain'] = {} + + if domain_id: + scope['domain']['id'] = domain_id + elif domain_name: + scope['domain']['name'] = domain_name + + if project_id or project_name: + body['auth']['scope'] = {} + scope = body['auth']['scope'] + scope['project'] = {} + + if project_id: + scope['project']['id'] = project_id + elif project_name: + scope['project']['name'] = project_name + + if project_domain_id or project_domain_name: + scope['project']['domain'] = {} + if project_domain_id: + scope['project']['domain']['id'] = project_domain_id + elif project_domain_name: + scope['project']['domain']['name'] = project_domain_name + + if not (ident or token): + raise ValueError('Authentication method required (e.g. password)') + + resp, body = self.request(url, 'POST', body=body, headers=headers) + return resp, body |