221 lines
9.7 KiB
Python
221 lines
9.7 KiB
Python
# 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)
|