Merge "Control identity plugin reauthentication"

This commit is contained in:
Jenkins 2014-08-06 01:51:30 +00:00 committed by Gerrit Code Review
commit a505ffbf17
4 changed files with 91 additions and 24 deletions

View File

@ -34,12 +34,14 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
username=None,
password=None,
token=None,
trust_id=None):
trust_id=None,
reauthenticate=True):
super(BaseIdentityPlugin, self).__init__()
self.auth_url = auth_url
self.auth_ref = None
self.reauthenticate = reauthenticate
self._endpoint_cache = {}
@ -81,6 +83,28 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
"""
return self.get_access(session).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.auth_ref:
# authentication was never fetched.
return True
if not self.reauthenticate:
# don't re-authenticate if it has been disallowed.
return False
if self.auth_ref.will_expire_soon(self.MIN_TOKEN_LIFE_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, session, **kwargs):
"""Fetch or return a current AccessInfo object.
@ -91,8 +115,7 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
:returns AccessInfo: Valid AccessInfo
"""
if (not self.auth_ref or
self.auth_ref.will_expire_soon(self.MIN_TOKEN_LIFE_SECONDS)):
if self._needs_reauthenticate():
self.auth_ref = self.get_auth_ref(session)
return self.auth_ref

View File

@ -43,15 +43,20 @@ 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

View File

@ -34,7 +34,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.
@ -46,9 +47,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

View File

@ -11,14 +11,17 @@
# under the License.
import abc
import datetime
import uuid
import six
from keystoneclient import access
from keystoneclient.auth import base
from keystoneclient.auth.identity import v2
from keystoneclient.auth.identity import v3
from keystoneclient import fixture
from keystoneclient.openstack.common import timeutils
from keystoneclient import session
from keystoneclient.tests import utils
@ -45,7 +48,7 @@ class CommonIdentityTests(object):
self.stub_auth_data()
@abc.abstractmethod
def create_auth_plugin(self):
def create_auth_plugin(self, **kwargs):
"""Create an auth plugin that makes sense for the auth data.
It doesn't really matter what auth mechanism is used but it should be
@ -53,13 +56,17 @@ class CommonIdentityTests(object):
"""
@abc.abstractmethod
def stub_auth_data(self):
"""Stub out authentication data.
def get_auth_data(self, **kwargs):
"""Return fake authentication data.
This should register a valid token response and ensure that the compute
endpoints are set to TEST_COMPUTE_PUBLIC, _INTERNAL and _ADMIN.
"""
def stub_auth_data(self, **kwargs):
token = self.get_auth_data(**kwargs)
self.stub_auth(json=token)
@abc.abstractproperty
def version(self):
"""The API version being tested."""
@ -177,6 +184,31 @@ class CommonIdentityTests(object):
self.assertEqual(self.TEST_URL, auth_url)
def _create_expired_auth_plugin(self, **kwargs):
expires = timeutils.utcnow() - datetime.timedelta(minutes=20)
expired_token = self.get_auth_data(expires=expires)
expired_auth_ref = access.AccessInfo.factory(body=expired_token)
body = 'SUCCESS'
self.stub_url('GET', ['path'],
base_url=self.TEST_COMPUTE_ADMIN, body=body)
a = self.create_auth_plugin(**kwargs)
a.auth_ref = expired_auth_ref
return a
def test_reauthenticate(self):
a = self._create_expired_auth_plugin()
expired_auth_ref = a.auth_ref
s = session.Session(auth=a)
self.assertIsNot(expired_auth_ref, a.get_access(s))
def test_no_reauthenticate(self):
a = self._create_expired_auth_plugin(reauthenticate=False)
expired_auth_ref = a.auth_ref
s = session.Session(auth=a)
self.assertIs(expired_auth_ref, a.get_access(s))
class V3(CommonIdentityTests, utils.TestCase):
@ -184,8 +216,8 @@ class V3(CommonIdentityTests, utils.TestCase):
def version(self):
return 'v3'
def stub_auth_data(self):
token = fixture.V3Token()
def get_auth_data(self, **kwargs):
token = fixture.V3Token(**kwargs)
region = 'RegionOne'
svc = token.add_service('identity')
@ -197,7 +229,7 @@ class V3(CommonIdentityTests, utils.TestCase):
internal=self.TEST_COMPUTE_INTERNAL,
region=region)
self.stub_auth(json=token)
return token
def stub_auth(self, subject_token=None, **kwargs):
if not subject_token:
@ -206,10 +238,11 @@ class V3(CommonIdentityTests, utils.TestCase):
kwargs.setdefault('headers', {})['X-Subject-Token'] = subject_token
self.stub_url('POST', ['auth', 'tokens'], **kwargs)
def create_auth_plugin(self):
return v3.Password(self.TEST_URL,
username=self.TEST_USER,
password=self.TEST_PASS)
def create_auth_plugin(self, **kwargs):
kwargs.setdefault('auth_url', self.TEST_URL)
kwargs.setdefault('username', self.TEST_USER)
kwargs.setdefault('password', self.TEST_PASS)
return v3.Password(**kwargs)
class V2(CommonIdentityTests, utils.TestCase):
@ -218,13 +251,14 @@ class V2(CommonIdentityTests, utils.TestCase):
def version(self):
return 'v2.0'
def create_auth_plugin(self):
return v2.Password(self.TEST_URL,
username=self.TEST_USER,
password=self.TEST_PASS)
def create_auth_plugin(self, **kwargs):
kwargs.setdefault('auth_url', self.TEST_URL)
kwargs.setdefault('username', self.TEST_USER)
kwargs.setdefault('password', self.TEST_PASS)
return v2.Password(**kwargs)
def stub_auth_data(self):
token = fixture.V2Token()
def get_auth_data(self, **kwargs):
token = fixture.V2Token(**kwargs)
region = 'RegionOne'
svc = token.add_service('identity')
@ -236,7 +270,7 @@ class V2(CommonIdentityTests, utils.TestCase):
admin=self.TEST_COMPUTE_ADMIN,
region=region)
self.stub_auth(json=token)
return token
def stub_auth(self, **kwargs):
self.stub_url('POST', ['tokens'], **kwargs)