# Copyright 2011 Nebula, Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import warnings from keystoneclient.auth.identity import v2 as v2_auth from keystoneclient import exceptions from keystoneclient import httpclient from keystoneclient.i18n import _ from keystoneclient.v2_0 import certificates from keystoneclient.v2_0 import ec2 from keystoneclient.v2_0 import endpoints from keystoneclient.v2_0 import extensions from keystoneclient.v2_0 import roles from keystoneclient.v2_0 import services from keystoneclient.v2_0 import tenants from keystoneclient.v2_0 import tokens from keystoneclient.v2_0 import users _logger = logging.getLogger(__name__) class Client(httpclient.HTTPClient): """Client for the OpenStack Keystone v2.0 API. :param string username: Username for authentication. (optional) :param string password: Password for authentication. (optional) :param string token: Token for authentication. (optional) :param string tenant_id: Tenant id. (optional) :param string tenant_name: Tenant name. (optional) :param string auth_url: Keystone 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 service. Lazy-authentication is possible for API service calls if endpoint is set at instantiation.(optional) :param integer timeout: Allows customization of the timeout for client http requests. (optional) :param string original_ip: The original IP of the requesting user which will be sent to Keystone in a 'Forwarded' header. (optional) :param string cert: Path to the Privacy Enhanced Mail (PEM) file which contains the corresponding X.509 client certificate needed to established two-way SSL connection with the identity service. (optional) :param string key: Path to the Privacy Enhanced Mail (PEM) file which contains the unencrypted client private key needed to established two-way SSL connection with the identity service. (optional) :param string cacert: Path to the Privacy Enhanced Mail (PEM) file which contains the trusted authority X.509 certificates needed to established SSL connection with the identity service. (optional) :param boolean insecure: Does not perform X.509 certificate validation when establishing SSL connection with identity service. default: False (optional) :param dict auth_ref: To allow for consumers of the client to manage their own caching strategy, you may initialize a client with a previously captured auth_reference (token) :param boolean debug: Enables debug logging of all request and responses to keystone. default False (option) .. warning:: If debug is enabled, it may show passwords in plain text as a part of its output. .. warning:: Constructing an instance of this class without a session is deprecated as of the 1.7.0 release and will be removed in the 2.0.0 release. The client can be created and used like a user or in a strictly bootstrap mode. Normal operation expects a username, password, auth_url, and tenant_name or id to be provided. Other values will be lazily loaded as needed from the service catalog. Example:: >>> from keystoneauth1.identity import v2 >>> from keystoneauth1 import session >>> from keystoneclient.v2_0 import client >>> auth = v2.Password(auth_url=KEYSTONE_URL, ... username=USER, ... password=PASS, ... tenant_name=TENANT_NAME) >>> sess = session.Session(auth=auth) >>> keystone = client.Client(session=sess) >>> keystone.tenants.list() ... >>> user = keystone.users.get(USER_ID) >>> user.delete() Once authenticated, you can store and attempt to re-use the authenticated token. the auth_ref property on the client returns as a dictionary-like-object so that you can export and cache it, re-using it when initiating another client:: >>> from keystoneauth1.identity import v2 >>> from keystoneauth1 import session >>> from keystoneclient.v2_0 import client >>> auth = v2.Password(auth_url=KEYSTONE_URL, ... username=USER, ... password=PASS, ... tenant_name=TENANT_NAME) >>> sess = session.Session(auth=auth) >>> keystone = client.Client(session=sess) >>> auth_ref = keystone.auth_ref >>> # pickle or whatever you like here >>> new_client = client.Client(auth_ref=auth_ref) Alternatively, you can provide the administrative token configured in keystone and an endpoint to communicate with directly. See (``admin_token`` in ``keystone.conf``) In this case, authenticate() is not needed, and no service catalog will be loaded. Example:: >>> from keystoneauth1.identity import v2 >>> from keystoneauth1 import session >>> from keystoneclient.v2_0 import client >>> auth = v2.Token(auth_url='http://localhost:35357/v2.0', ... token='12345secret7890') >>> sess = session.Session(auth=auth) >>> keystone = client.Client(session=sess) >>> keystone.tenants.list() """ version = 'v2.0' def __init__(self, **kwargs): """Initialize a new client for the Keystone v2.0 API.""" if not kwargs.get('session'): warnings.warn( 'Constructing an instance of the ' 'keystoneclient.v2_0.client.Client class without a session is ' 'deprecated as of the 1.7.0 release and may be removed in ' 'the 2.0.0 release.', DeprecationWarning) super(Client, self).__init__(**kwargs) self.certificates = certificates.CertificatesManager(self._adapter) self.endpoints = endpoints.EndpointManager(self._adapter) self.extensions = extensions.ExtensionManager(self._adapter) self.roles = roles.RoleManager(self._adapter) self.services = services.ServiceManager(self._adapter) self.tokens = tokens.TokenManager(self._adapter) self.users = users.UserManager(self._adapter, self.roles) self.tenants = tenants.TenantManager(self._adapter, self.roles, self.users) # extensions self.ec2 = ec2.CredentialsManager(self._adapter) # DEPRECATED: if session is passed then we go to the new behaviour of # authenticating on the first required call. if not kwargs.get('session') and self.management_url is None: self.authenticate() def get_raw_token_from_identity_service(self, auth_url, username=None, password=None, tenant_name=None, tenant_id=None, token=None, project_name=None, project_id=None, trust_id=None, **kwargs): """Authenticate against the v2 Identity API. If a token is provided it will be used in preference over username and password. :returns: access.AccessInfo if authentication was successful. :raises keystoneclient.exceptions.AuthorizationFailure: if unable to authenticate or validate the existing authorization token """ try: if auth_url is None: raise ValueError(_("Cannot authenticate without an auth_url")) new_kwargs = {'trust_id': trust_id, 'tenant_id': project_id or tenant_id, 'tenant_name': project_name or tenant_name} if token: plugin = v2_auth.Token(auth_url, token, **new_kwargs) elif username and password: plugin = v2_auth.Password(auth_url, username, password, **new_kwargs) else: msg = _('A username and password or token is required.') raise exceptions.AuthorizationFailure(msg) return plugin.get_auth_ref(self.session) except (exceptions.AuthorizationFailure, exceptions.Unauthorized): _logger.debug("Authorization Failed.") raise except exceptions.EndpointNotFound: msg = ( _('There was no suitable authentication url for this request')) raise exceptions.AuthorizationFailure(msg) except Exception as e: raise exceptions.AuthorizationFailure( _("Authorization Failed: %s") % e)