From 7cc02c80cfb1976271fa8b6271091fcd35c1cb34 Mon Sep 17 00:00:00 2001 From: Joe Heck Date: Thu, 1 Nov 2012 15:36:31 -0700 Subject: fixes bug 1074172 updated diablo token based on output from diablo/stable keystone added expiry to example tokens for test_auth_middleware added a stack based HTTP response to test_auth_middleware to verify sequencing Change-Id: I738b0e9c1a0e62ad86adb95ec0b73f621513f7d4 --- keystone/middleware/auth_token.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'keystone') diff --git a/keystone/middleware/auth_token.py b/keystone/middleware/auth_token.py index 5c198e83..43261f29 100644 --- a/keystone/middleware/auth_token.py +++ b/keystone/middleware/auth_token.py @@ -159,6 +159,16 @@ opts = [ CONF.register_opts(opts, group='keystone_authtoken') +def will_expire_soon(expiry): + """ Determines if expiration is about to occur. + + :param expiry: a datetime of the expected expiration + :returns: boolean : true if expiration is within 30 seconds + """ + soon = (timeutils.utcnow() + datetime.timedelta(seconds=30)) + return expiry < soon + + class InvalidUserToken(Exception): pass @@ -230,6 +240,7 @@ class AuthProtocol(object): # Credentials used to verify this component with the Auth service since # validating tokens is a privileged call self.admin_token = self._conf_get('admin_token') + self.admin_token_expiry = None self.admin_user = self._conf_get('admin_user') self.admin_password = self._conf_get('admin_password') self.admin_tenant_name = self._conf_get('admin_tenant_name') @@ -345,12 +356,21 @@ class AuthProtocol(object): def get_admin_token(self): """Return admin token, possibly fetching a new one. + if self.admin_token_expiry is set from fetching an admin token, check + it for expiration, and request a new token is the existing token + is about to expire. + :return admin token id :raise ServiceError when unable to retrieve token from keystone """ + if self.admin_token_expiry: + if will_expire_soon(self.admin_token_expiry): + self.admin_token = None + if not self.admin_token: - self.admin_token = self._request_admin_token() + (self.admin_token, + self.admin_token_expiry) = self._request_admin_token() return self.admin_token @@ -455,11 +475,17 @@ class AuthProtocol(object): try: token = data['access']['token']['id'] + expiry = data['access']['token']['expires'] assert token - return token + assert expiry + datetime_expiry = timeutils.parse_isotime(expiry) + return (token, timeutils.normalize_time(datetime_expiry)) except (AssertionError, KeyError): LOG.warn("Unexpected response from keystone service: %s", data) raise ServiceError('invalid json response') + except (ValueError): + LOG.warn("Unable to parse expiration time from token: %s", data) + raise ServiceError('invalid json response') def _validate_user_token(self, user_token, retry=True): """Authenticate user using PKI @@ -771,10 +797,16 @@ class AuthProtocol(object): with open(self.revoked_file_name, 'w') as f: f.write(value) - def fetch_revocation_list(self): + def fetch_revocation_list(self, retry=True): headers = {'X-Auth-Token': self.get_admin_token()} response, data = self._json_request('GET', '/v2.0/tokens/revoked', additional_headers=headers) + if response.status == 401: + if retry: + LOG.info('Keystone rejected admin token %s, resetting admin ' + 'token', headers) + self.admin_token = None + return self.fetch_revocation_list(retry=False) if response.status != 200: raise ServiceError('Unable to fetch token revocation list.') if (not 'signed' in data): -- cgit