Hello community, here is the log from the commit of package openstack-keystone for openSUSE:Factory checked in at 2013-03-08 09:29:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openstack-keystone (Old) and /work/SRC/openSUSE:Factory/.openstack-keystone.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openstack-keystone", Maintainer is "radma...@suse.com" Changes: -------- --- /work/SRC/openSUSE:Factory/openstack-keystone/openstack-keystone.changes 2013-02-22 16:55:56.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.openstack-keystone.new/openstack-keystone.changes 2013-03-08 09:29:08.000000000 +0100 @@ -1,0 +2,7 @@ +Tue Mar 5 16:51:28 UTC 2013 - cloud-de...@suse.de + +- Update to version 2012.2.4+git.1362502288.8690166: + + Sync timeutils to pick up normalize fix. + + Backport of fix for 24-hour failure of pki. + +-------------------------------------------------------------------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openstack-keystone-doc.spec ++++++ --- /var/tmp/diff_new_pack.GJMiEy/_old 2013-03-08 09:29:09.000000000 +0100 +++ /var/tmp/diff_new_pack.GJMiEy/_new 2013-03-08 09:29:09.000000000 +0100 @@ -19,7 +19,7 @@ %define component keystone Name: openstack-%{component}-doc -Version: 2012.2.4+git.1361527873.37b3532 +Version: 2012.2.4+git.1362502288.8690166 Release: 0 License: Apache-2.0 Summary: OpenStack Identity Service (Keystone) - Documentation ++++++ openstack-keystone.spec ++++++ --- /var/tmp/diff_new_pack.GJMiEy/_old 2013-03-08 09:29:09.000000000 +0100 +++ /var/tmp/diff_new_pack.GJMiEy/_new 2013-03-08 09:29:09.000000000 +0100 @@ -23,7 +23,7 @@ %define hybrid keystone-hybrid-backend-folsom Name: openstack-%{component} -Version: 2012.2.4+git.1361527873.37b3532 +Version: 2012.2.4+git.1362502288.8690166 Release: 0 License: Apache-2.0 Summary: OpenStack Identity Service (Keystone) ++++++ keystone-hybrid-backend-folsom.tar.gz ++++++ ++++++ keystone-stable-folsom.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/keystone-2012.2.4/ChangeLog new/keystone-2012.2.4/ChangeLog --- old/keystone-2012.2.4/ChangeLog 2013-02-20 02:12:22.000000000 +0100 +++ new/keystone-2012.2.4/ChangeLog 2013-03-05 15:24:55.000000000 +0100 @@ -1,3 +1,44 @@ +commit 86901664189c62fce6f8f81619da0896cce469a1 +Author: Joe Heck <he...@mac.com> +Date: Thu Nov 1 15:36:31 2012 -0700 + + Backport of fix for 24-hour failure of pki. + + A 401 from the admin token was being treated as an invalid user token + and the admin token was never re-requested. This would cause all + services to incorrectly report all tokens as invalid after the service + had been running for 24 hours. This change re-requests the admin token + and attempts to revalidate instead of returning 401. + + Original commit message follows: + + 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 + (cherry picked from commit 7cc02c80cfb1976271fa8b6271091fcd35c1cb34) + + keystone/middleware/auth_token.py | 38 ++++++++++++++-- + tests/test_auth_token_middleware.py | 85 +++++++++++++++++++++++++++++++++++ + 2 files changed, 120 insertions(+), 3 deletions(-) + +commit 790c87e8bc401ef202e715a324a6053aaa9e2d5e +Author: Vishvananda Ishaya <vishvana...@gmail.com> +Date: Mon Mar 4 13:37:46 2013 -0800 + + Sync timeutils to pick up normalize fix. + + Required to backport fix for bug 1074172. + + Change-Id: I6003abedcfc6ba9d287cabda35c0bbc821519008 + + keystone/openstack/common/timeutils.py | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + commit 37b3532884f30fc979f633abe9be2b694d16887a Merge: 8a22745 f0b4d30 Author: Jenkins <jenk...@review.openstack.org> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/keystone-2012.2.4/keystone/middleware/auth_token.py new/keystone-2012.2.4/keystone/middleware/auth_token.py --- old/keystone-2012.2.4/keystone/middleware/auth_token.py 2013-02-20 02:08:12.000000000 +0100 +++ new/keystone-2012.2.4/keystone/middleware/auth_token.py 2013-03-05 15:22:06.000000000 +0100 @@ -159,6 +159,16 @@ 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 @@ # 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 @@ 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 @@ 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 @@ 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): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/keystone-2012.2.4/keystone/openstack/common/timeutils.py new/keystone-2012.2.4/keystone/openstack/common/timeutils.py --- old/keystone-2012.2.4/keystone/openstack/common/timeutils.py 2013-02-20 02:08:12.000000000 +0100 +++ new/keystone-2012.2.4/keystone/openstack/common/timeutils.py 2013-03-05 15:22:06.000000000 +0100 @@ -62,9 +62,11 @@ def normalize_time(timestamp): - """Normalize time in arbitrary timezone to UTC""" + """Normalize time in arbitrary timezone to UTC naive object""" offset = timestamp.utcoffset() - return timestamp.replace(tzinfo=None) - offset if offset else timestamp + if offset is None: + return timestamp + return timestamp.replace(tzinfo=None) - offset def is_older_than(before, seconds): @@ -121,7 +123,10 @@ def unmarshall_time(tyme): """Unmarshall a datetime dict.""" - return datetime.datetime(day=tyme['day'], month=tyme['month'], - year=tyme['year'], hour=tyme['hour'], - minute=tyme['minute'], second=tyme['second'], + return datetime.datetime(day=tyme['day'], + month=tyme['month'], + year=tyme['year'], + hour=tyme['hour'], + minute=tyme['minute'], + second=tyme['second'], microsecond=tyme['microsecond']) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/keystone-2012.2.4/tests/test_auth_token_middleware.py new/keystone-2012.2.4/tests/test_auth_token_middleware.py --- old/keystone-2012.2.4/tests/test_auth_token_middleware.py 2013-02-20 02:08:12.000000000 +0100 +++ new/keystone-2012.2.4/tests/test_auth_token_middleware.py 2013-03-05 15:22:06.000000000 +0100 @@ -69,6 +69,7 @@ 'access': { 'token': { 'id': UUID_TOKEN_DEFAULT, + 'expires': '2999-01-01T00:00:10Z', 'tenant': { 'id': 'tenant_id1', 'name': 'tenant_name1', @@ -89,6 +90,7 @@ 'access': { 'token': { 'id': VALID_DIABLO_TOKEN, + 'expires': '2999-01-01T00:00:10', 'tenantId': 'tenant_id1', }, 'user': { @@ -105,6 +107,7 @@ 'access': { 'token': { 'id': UUID_TOKEN_UNSCOPED, + 'expires': '2999-01-01T00:00:10Z', }, 'user': { 'id': 'user_id1', @@ -120,6 +123,7 @@ 'access': { 'token': { 'id': 'valid-token', + 'expires': '2999-01-01T00:00:10Z', 'tenant': { 'id': 'tenant_id1', 'name': 'tenant_name1', @@ -137,6 +141,8 @@ }, } +FAKE_RESPONSE_STACK = [] + # The data for these tests are signed using openssl and are stored in files # in the signing subdirectory. In order to keep the values consistent between @@ -223,6 +229,23 @@ return self.body +class FakeStackHTTPConnection(object): + + def __init__(self, *args, **kwargs): + pass + + def getresponse(self): + if len(FAKE_RESPONSE_STACK): + return FAKE_RESPONSE_STACK.pop() + return FakeHTTPResponse(500, jsonutils.dumps('UNEXPECTED RESPONSE')) + + def request(self, *_args, **_kwargs): + pass + + def close(self): + pass + + class FakeHTTPConnection(object): last_requested_url = '' @@ -339,6 +362,60 @@ self.response_headers = dict(headers) +class StackResponseAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): + """Auth Token middleware test setup that allows the tests to define + a stack of responses to HTTP requests in the test and get those + responses back in sequence for testing. + + Example:: + + resp1 = FakeHTTPResponse(401, jsonutils.dumps('')) + resp2 = FakeHTTPResponse(200, jsonutils.dumps({ + 'access': { + 'token': {'id': 'admin_token2'}, + }, + }) + FAKE_RESPONSE_STACK.append(resp1) + FAKE_RESPONSE_STACK.append(resp2) + + ... do your testing code here ... + + """ + + def setUp(self, expected_env=None): + super(StackResponseAuthTokenMiddlewareTest, self).setUp(expected_env) + self.middleware.http_client_class = FakeStackHTTPConnection + + def test_fetch_revocation_list_with_expire(self): + # first response to revocation list should return 401 Unauthorized + # to pretend to be an expired token + resp1 = FakeHTTPResponse(200, jsonutils.dumps({ + 'access': { + 'token': {'id': 'admin_token2'}, + }, + })) + resp2 = FakeHTTPResponse(401, jsonutils.dumps('')) + resp3 = FakeHTTPResponse(200, jsonutils.dumps({ + 'access': { + 'token': {'id': 'admin_token2'}, + }, + })) + resp4 = FakeHTTPResponse(200, SIGNED_REVOCATION_LIST) + + # first get_admin_token() call + FAKE_RESPONSE_STACK.append(resp1) + # request revocation list, get "unauthorized" due to simulated expired + # token + FAKE_RESPONSE_STACK.append(resp2) + # request a new admin_token + FAKE_RESPONSE_STACK.append(resp3) + # request revocation list, get the revocation list properly + FAKE_RESPONSE_STACK.append(resp4) + + fetched_list = jsonutils.loads(self.middleware.fetch_revocation_list()) + self.assertEqual(fetched_list, REVOCATION_LIST) + + class DiabloAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest): """Auth Token middleware should understand Diablo keystone responses.""" def setUp(self): @@ -564,3 +641,11 @@ self.assertEqual(self.response_status, 200) self.assertFalse(req.headers.get('X-Service-Catalog')) self.assertEqual(body, ['SUCCESS']) + + def test_will_expire_soon(self): + tenseconds = datetime.datetime.utcnow() + datetime.timedelta( + seconds=10) + self.assertTrue(auth_token.will_expire_soon(tenseconds)) + fortyseconds = datetime.datetime.utcnow() + datetime.timedelta( + seconds=40) + self.assertFalse(auth_token.will_expire_soon(fortyseconds)) -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org