Sync up with latest keystoneclient changes

Change-Id: I895534b2d30dec8e38461e07ebf03ea8f466dad9
This commit is contained in:
Terry Howe 2014-09-02 08:36:28 -06:00
parent 8ba7650d02
commit 40ae1ffeaa
6 changed files with 102 additions and 15 deletions

View File

@ -18,7 +18,7 @@ Session object
provides an HTTP request method. The transport is also to be used by
the authenticator if needed.
* authenticator - An authenticator derived from
``openstack.auth.base.BaseAuthenticator`` that provides get_token and
``openstack.auth.base.BaseAuthPlugin`` that provides get_token and
get_endpoint methods for the session.
All the other methods of the session accept the following parameters:

View File

@ -33,7 +33,7 @@ from openstack.auth import base
from openstack.auth.identity import authenticator
class TestAuthenticator(base.BaseAuthenticator):
class TestAuthenticator(base.BaseAuthPlugin):
def __init__(self, token, endpoint):
super(TestAuthenticator, self).__init__()
self.token = token

View File

@ -16,7 +16,7 @@ import six
@six.add_metaclass(abc.ABCMeta)
class BaseAuthenticator(object):
class BaseAuthPlugin(object):
"""The basic structure of an authenticator."""
@abc.abstractmethod
@ -54,3 +54,18 @@ class BaseAuthenticator(object):
:returns string: The base URL that will be used to talk to the
required service or None if not available.
"""
def invalidate(self):
"""Invalidate the current authentication data.
This should result in fetching a new token on next call.
A plugin may be invalidated if an Unauthorized HTTP response is
returned to indicate that the token may have been revoked or is
otherwise now invalid.
:returns bool: True if there was something that the plugin did to
invalidate. This means that it makes sense to try again.
If nothing happens returns False to indicate give up.
"""
return False

View File

@ -18,15 +18,16 @@ from openstack.auth import base
@six.add_metaclass(abc.ABCMeta)
class BaseIdentityPlugin(base.BaseAuthenticator):
class BaseIdentityPlugin(base.BaseAuthPlugin):
# Consider a token valid if it does not expire for this many seconds
BEST_BEFORE_SECONDS = 1
def __init__(self, auth_url=None):
def __init__(self, auth_url=None, reauthenticate=True):
super(BaseIdentityPlugin, self).__init__()
self.auth_url = auth_url
self.access_info = None
self.reauthenticate = reauthenticate
@abc.abstractmethod
def authorize(self, transport, **kwargs):
@ -52,6 +53,28 @@ class BaseIdentityPlugin(base.BaseAuthenticator):
"""
return self.get_access(transport).auth_token
def _needs_reauthenticate(self):
"""Return if the existing token needs to be re-authenticated.
The token should be refreshed if it is about to expire.
:returns: True if the plugin should fetch a new token. False otherwise.
"""
if not self.access_info:
# authentication was never fetched.
return True
if not self.reauthenticate:
# don't re-authenticate if it has been disallowed.
return False
if self.access_info.will_expire_soon(self.BEST_BEFORE_SECONDS):
# if it's about to expire we should re-authenticate now.
return True
# otherwise it's fine and use the existing one.
return False
def get_access(self, transport):
"""Fetch or return a current AccessInfo object.
@ -62,12 +85,27 @@ class BaseIdentityPlugin(base.BaseAuthenticator):
:returns AccessInfo: Valid AccessInfo
"""
if (not self.access_info or
self.access_info.will_expire_soon(self.BEST_BEFORE_SECONDS)):
if self._needs_reauthenticate():
self.access_info = self.authorize(transport)
return self.access_info
def invalidate(self):
"""Invalidate the current authentication data.
This should result in fetching a new token on next call.
A plugin may be invalidated if an Unauthorized HTTP response is
returned to indicate that the token may have been revoked or is
otherwise now invalid.
:returns bool: True if there was something that the plugin did to
invalidate. This means that it makes sense to try again.
If nothing happens returns False to indicate give up.
"""
self.access_info = None
return True
def get_endpoint(self, transport, service, **kwargs):
"""Return a valid endpoint for a service.

View File

@ -13,6 +13,7 @@
# under the License.
import abc
import logging
import six
@ -20,21 +21,29 @@ from openstack.auth import access
from openstack.auth.identity import base
from openstack import exceptions
_logger = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class Auth(base.BaseIdentityPlugin):
def __init__(self, auth_url,
trust_id=None,
tenant_id=None,
tenant_name=None):
tenant_name=None,
reauthenticate=True):
"""Construct an Identity V2 Authentication Plugin.
:param string auth_url: Identity service endpoint for authorization.
:param string trust_id: Trust ID for trust scoping.
:param string tenant_id: Tenant ID for project scoping.
:param string tenant_name: Tenant name for project scoping.
:param bool reauthenticate: Allow fetching a new token if the current
one is going to expire.
(optional) default True
"""
super(Auth, self).__init__(auth_url=auth_url)
super(Auth, self).__init__(auth_url=auth_url,
reauthenticate=reauthenticate)
self.trust_id = trust_id
self.tenant_id = tenant_id
@ -42,7 +51,7 @@ class Auth(base.BaseIdentityPlugin):
def authorize(self, transport, **kwargs):
headers = {'Accept': 'application/json'}
url = self.auth_url + '/tokens'
url = self.auth_url.rstrip('/') + '/tokens'
params = {'auth': self.get_auth_data(headers)}
if self.tenant_id:
@ -52,6 +61,7 @@ class Auth(base.BaseIdentityPlugin):
if self.trust_id:
params['auth']['trust_id'] = self.trust_id
_logger.debug('Making authentication request to %s', url)
resp = transport.post(url, json=params, headers=headers)
try:
@ -73,20 +83,38 @@ class Auth(base.BaseIdentityPlugin):
class Password(Auth):
def __init__(self, auth_url, username, password, **kwargs):
def __init__(self, auth_url, username=None, password=None, user_id=None,
**kwargs):
"""A plugin for authenticating with a username and password.
A username or user_id must be provided.
:param string auth_url: Identity service endpoint for authorization.
:param string username: Username for authentication.
:param string password: Password for authentication.
:param string user_id: User ID for authentication.
:raises TypeError: if a user_id or username is not provided.
"""
super(Password, self).__init__(auth_url, **kwargs)
if not (user_id or username):
msg = 'You need to specify either a username or user_id'
raise TypeError(msg)
self.user_id = user_id
self.username = username
self.password = password
def get_auth_data(self, headers=None):
return {'passwordCredentials': {'username': self.username,
'password': self.password}}
auth = {'password': self.password}
if self.username:
auth['username'] = self.username
elif self.user_id:
auth['userId'] = self.user_id
return {'passwordCredentials': auth}
class Token(Auth):

View File

@ -33,7 +33,8 @@ class Auth(base.BaseIdentityPlugin):
project_id=None,
project_name=None,
project_domain_id=None,
project_domain_name=None):
project_domain_name=None,
reauthenticate=True):
"""Construct an Identity V3 Authentication Plugin.
:param string auth_url: Identity service endpoint for authentication.
@ -45,9 +46,13 @@ class Auth(base.BaseIdentityPlugin):
:param string project_name: Project name for project scoping.
:param string project_domain_id: Project's domain ID for project.
:param string project_domain_name: Project's domain name for project.
:param bool reauthenticate: Allow fetching a new token if the current
one is going to expire.
(optional) default True
"""
super(Auth, self).__init__(auth_url=auth_url)
super(Auth, self).__init__(auth_url=auth_url,
reauthenticate=reauthenticate)
self.auth_methods = auth_methods
self.trust_id = trust_id
@ -104,6 +109,7 @@ class Auth(base.BaseIdentityPlugin):
elif self.trust_id:
body['auth']['scope'] = {'OS-TRUST:trust': {'id': self.trust_id}}
_logger.debug('Making authentication request to %s', self.token_url)
resp = transport.post(self.token_url, json=body, headers=headers)
try: