225 lines
12 KiB
Diff
225 lines
12 KiB
Diff
From 8d23da1302dde9d38bbc227d9aba30da919b60c8 Mon Sep 17 00:00:00 2001
|
|
From: Adam Young <ayoung@redhat.com>
|
|
Date: Mon, 13 May 2013 16:07:51 -0400
|
|
Subject: [PATCH] Check token Expiration
|
|
|
|
Backport for Folsom.
|
|
|
|
Bug 1179615
|
|
|
|
Change-Id: I8516d87ffc72cf35d3bff6fc21cb5324da4ad2bb
|
|
---
|
|
keystone/middleware/auth_token.py | 30 +++++++++++++--------
|
|
tests/signing/Makefile | 2 +-
|
|
tests/signing/auth_token_revoked.pem | 10 +++----
|
|
tests/signing/auth_token_scoped_expired.json | 1 +
|
|
tests/signing/auth_token_scoped_expired.pem | 40 ++++++++++++++++++++++++++++
|
|
tests/test_auth_token_middleware.py | 10 +++++++
|
|
6 files changed, 76 insertions(+), 17 deletions(-)
|
|
create mode 100644 tests/signing/auth_token_scoped_expired.json
|
|
create mode 100644 tests/signing/auth_token_scoped_expired.pem
|
|
|
|
diff --git a/keystone/middleware/auth_token.py b/keystone/middleware/auth_token.py
|
|
index 01e6c58..b1a574b 100644
|
|
--- a/keystone/middleware/auth_token.py
|
|
+++ b/keystone/middleware/auth_token.py
|
|
@@ -95,6 +95,7 @@ HTTP_X_ROLE
|
|
|
|
import datetime
|
|
import httplib
|
|
+import iso8601
|
|
import json
|
|
import logging
|
|
import os
|
|
@@ -259,13 +260,12 @@ class AuthProtocol(object):
|
|
self._token_revocation_list_fetched_time = None
|
|
self.token_revocation_list_cache_timeout = \
|
|
datetime.timedelta(seconds=0)
|
|
+ self._iso8601 = iso8601
|
|
if memcache_servers:
|
|
try:
|
|
import memcache
|
|
- import iso8601
|
|
LOG.info('Using memcache for caching token')
|
|
self._cache = memcache.Client(memcache_servers.split(','))
|
|
- self._iso8601 = iso8601
|
|
except ImportError as e:
|
|
LOG.warn('disabled caching due to missing libraries %s', e)
|
|
|
|
@@ -512,7 +512,8 @@ class AuthProtocol(object):
|
|
data = json.loads(verified)
|
|
else:
|
|
data = self.verify_uuid_token(user_token, retry)
|
|
- self._cache_put(token_id, data)
|
|
+ expires = self._confirm_token_not_expired(data)
|
|
+ self._cache_put(token_id, data, expires)
|
|
return data
|
|
except Exception as e:
|
|
LOG.debug('Token validation failure.', exc_info=True)
|
|
@@ -642,7 +643,19 @@ class AuthProtocol(object):
|
|
else:
|
|
LOG.debug('Cached Token %s seems expired', token)
|
|
|
|
- def _cache_put(self, token, data):
|
|
+ def _confirm_token_not_expired(self, data):
|
|
+ if 'token' in data.get('access', {}):
|
|
+ timestamp = data['access']['token']['expires']
|
|
+ expires = self._iso8601.parse_date(timestamp).strftime('%s')
|
|
+ else:
|
|
+ LOG.error('invalid token format')
|
|
+ raise InvalidUserToken('Token authorization failed')
|
|
+ if time.time() >= float(expires):
|
|
+ self.LOG.debug('Token expired a %s', timestamp)
|
|
+ raise InvalidUserToken('Token authorization failed')
|
|
+ return expires
|
|
+
|
|
+ def _cache_put(self, token, data, expires):
|
|
"""Put token data into the cache.
|
|
|
|
Stores the parsed expire date in cache allowing
|
|
@@ -650,12 +663,6 @@ class AuthProtocol(object):
|
|
"""
|
|
if self._cache and data:
|
|
key = 'tokens/%s' % token
|
|
- if 'token' in data.get('access', {}):
|
|
- timestamp = data['access']['token']['expires']
|
|
- expires = self._iso8601.parse_date(timestamp).strftime('%s')
|
|
- else:
|
|
- LOG.error('invalid token format')
|
|
- return
|
|
LOG.debug('Storing %s token in memcache', token)
|
|
self._cache.set(key,
|
|
(data, expires),
|
|
@@ -693,7 +700,8 @@ class AuthProtocol(object):
|
|
additional_headers=headers)
|
|
|
|
if response.status == 200:
|
|
- self._cache_put(user_token, data)
|
|
+ expires = self._confirm_token_not_expired(data)
|
|
+ self._cache_put(user_token, data, expires)
|
|
return data
|
|
if response.status == 404:
|
|
# FIXME(ja): I'm assuming the 404 status means that user_token is
|
|
diff --git a/tests/signing/Makefile b/tests/signing/Makefile
|
|
index b56c000..27f5ff8 100644
|
|
--- a/tests/signing/Makefile
|
|
+++ b/tests/signing/Makefile
|
|
@@ -19,7 +19,7 @@
|
|
|
|
.SUFFIXES: .json .pem
|
|
|
|
-SOURCES=auth_token_unscoped.json auth_token_scoped.json revocation_list.json
|
|
+SOURCES=auth_token_unscoped.json auth_token_scoped.json auth_token_scoped.json auth_token_scoped_expired.json revocation_list.json
|
|
SIGNED=$(SOURCES:.json=.pem)
|
|
TARGETS=$(SIGNED)
|
|
|
|
diff --git a/tests/signing/auth_token_revoked.pem b/tests/signing/auth_token_revoked.pem
|
|
index 186c080..27cef18 100644
|
|
--- a/tests/signing/auth_token_revoked.pem
|
|
+++ b/tests/signing/auth_token_revoked.pem
|
|
@@ -24,7 +24,7 @@ MC4wLjE6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVy
|
|
bmFsVVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsICJwdWJsaWNV
|
|
UkwiOiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAifV0sICJlbmRwb2ludHNf
|
|
bGlua3MiOiBbXSwgInR5cGUiOiAiaWRlbnRpdHkiLCAibmFtZSI6ICJrZXlzdG9u
|
|
-ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjAxMi0wNi0wMlQxNDo0NzozNFoi
|
|
+ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjExMi0wNi0wMlQxNDo0NzozNFoi
|
|
LCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJlbmFibGVkIjogdHJ1
|
|
ZSwgImRlc2NyaXB0aW9uIjogbnVsbCwgIm5hbWUiOiAidGVuYW50X25hbWUxIiwg
|
|
ImlkIjogInRlbmFudF9pZDEifX0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJyZXZv
|
|
@@ -33,8 +33,8 @@ LCAiaWQiOiAicmV2b2tlZF91c2VyX2lkMSIsICJyb2xlcyI6IFt7Im5hbWUiOiAi
|
|
cm9sZTEifSwgeyJuYW1lIjogInJvbGUyIn1dLCAibmFtZSI6ICJyZXZva2VkX3Vz
|
|
ZXJuYW1lMSJ9fX0NCjGB9zCB9AIBATBUME8xFTATBgNVBAoTDFJlZCBIYXQsIElu
|
|
YzERMA8GA1UEBxMIV2VzdGZvcmQxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxCzAJ
|
|
-BgNVBAYTAlVTAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIGAXstA+yZ5N/cS
|
|
-+i7Mmlhi585cckvwSVAGj9huPTpqBItpbO44+U3yUojEwcghomtpygI/wzUa8Z40
|
|
-UW/L3nGlATlOG833zhGvLKrp76GIitYMgk1e0OEmzGXeAWLnQZFev8ooMPs9rwYW
|
|
-MgEdAfDMWWqX+Tb7exdboLpRUiCQx1c=
|
|
+BgNVBAYTAlVTAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIGAdnQ5zU60aOc+
|
|
+TGK+5ESmYbOllqe7QGkcB2fWzuiIY4/9l53X0m3ThYNzxeloJ0NgETLWoHO24xIi
|
|
+YoCUtAGP8BQI0D21Amg4Nb3jBxiwObzdONytEpAYOXxMq8pDMgboi8eU0esch1jJ
|
|
+r+9/uR3R/xksWkPtPsl+qnt/KpUsL+A=
|
|
-----END CMS-----
|
|
diff --git a/tests/signing/auth_token_scoped_expired.json b/tests/signing/auth_token_scoped_expired.json
|
|
new file mode 100644
|
|
index 0000000..d36d8cf
|
|
--- /dev/null
|
|
+++ b/tests/signing/auth_token_scoped_expired.json
|
|
@@ -0,0 +1 @@
|
|
+{"access": {"serviceCatalog": [{"endpoints": [{"adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", "region": "regionOne", "internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", "publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a"}], "endpoints_links": [], "type": "volume", "name": "volume"}, {"endpoints": [{"adminURL": "http://127.0.0.1:9292/v1", "region": "regionOne", "internalURL": "http://127.0.0.1:9292/v1", "publicURL": "http://127.0.0.1:9292/v1"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", "region": "regionOne", "internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", "publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a"}], "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://127.0.0.1:35357/v2.0", "region": "RegionOne", "internalURL": "http://127.0.0.1:35357/v2.0", "publicURL": "http://127.0.0.1:5000/v2.0"}], "endpoints_links": [], "type": "identity", "name": "keystone"}],"token": {"expires": "2010-06-02T14:47:34Z", "id": "placeholder", "tenant": {"enabled": true, "description": null, "name": "tenant_name1", "id": "tenant_id1"}}, "user": {"username": "user_name1", "roles_links": ["role1","role2"], "id": "user_id1", "roles": [{"name": "role1"}, {"name": "role2"}], "name": "user_name1"}}}
|
|
diff --git a/tests/signing/auth_token_scoped_expired.pem b/tests/signing/auth_token_scoped_expired.pem
|
|
new file mode 100644
|
|
index 0000000..8116b11
|
|
--- /dev/null
|
|
+++ b/tests/signing/auth_token_scoped_expired.pem
|
|
@@ -0,0 +1,40 @@
|
|
+-----BEGIN CMS-----
|
|
+MIIG9QYJKoZIhvcNAQcCoIIG5jCCBuICAQExCTAHBgUrDgMCGjCCBc4GCSqGSIb3
|
|
+DQEHAaCCBb8EggW7eyJhY2Nlc3MiOiB7InNlcnZpY2VDYXRhbG9nIjogW3siZW5k
|
|
+cG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3Yx
|
|
+LzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInJlZ2lvbiI6ICJy
|
|
+ZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2
|
|
+L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInB1YmxpY1VS
|
|
+TCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThh
|
|
+NjBmY2Y4OWJiNjYxN2EifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUi
|
|
+OiAidm9sdW1lIiwgIm5hbWUiOiAidm9sdW1lIn0sIHsiZW5kcG9pbnRzIjogW3si
|
|
+YWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwgInJlZ2lvbiI6
|
|
+ICJyZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5
|
|
+MjkyL3YxIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEi
|
|
+fV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiaW1hZ2UiLCAibmFt
|
|
+ZSI6ICJnbGFuY2UifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRw
|
|
+Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5
|
|
+YmI2NjE3YSIsICJyZWdpb24iOiAicmVnaW9uT25lIiwgImludGVybmFsVVJMIjog
|
|
+Imh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYw
|
|
+ZmNmODliYjY2MTdhIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3
|
|
+NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSJ9XSwgImVu
|
|
+ZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAi
|
|
+bm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xMjcu
|
|
+MC4wLjE6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVy
|
|
+bmFsVVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsICJwdWJsaWNV
|
|
+UkwiOiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAifV0sICJlbmRwb2ludHNf
|
|
+bGlua3MiOiBbXSwgInR5cGUiOiAiaWRlbnRpdHkiLCAibmFtZSI6ICJrZXlzdG9u
|
|
+ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjAxMC0wNi0wMlQxNDo0NzozNFoi
|
|
+LCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJlbmFibGVkIjogdHJ1
|
|
+ZSwgImRlc2NyaXB0aW9uIjogbnVsbCwgIm5hbWUiOiAidGVuYW50X25hbWUxIiwg
|
|
+ImlkIjogInRlbmFudF9pZDEifX0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJ1c2Vy
|
|
+X25hbWUxIiwgInJvbGVzX2xpbmtzIjogWyJyb2xlMSIsInJvbGUyIl0sICJpZCI6
|
|
+ICJ1c2VyX2lkMSIsICJyb2xlcyI6IFt7Im5hbWUiOiAicm9sZTEifSwgeyJuYW1l
|
|
+IjogInJvbGUyIn1dLCAibmFtZSI6ICJ1c2VyX25hbWUxIn19fQ0KMYH/MIH8AgEB
|
|
+MFwwVzELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVVuc2V0MQ4wDAYDVQQHEwVVbnNl
|
|
+dDEOMAwGA1UEChMFVW5zZXQxGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbQIBATAH
|
|
+BgUrDgMCGjANBgkqhkiG9w0BAQEFAASBgJP+wKRwFaPY8xXAolDd6gmlID41yuAw
|
|
+nd+IKeD54Ack0NI9h/M0Iv2LzTo0l84VbMOijmq++kbtdnDJ2pn4VAoNk7dQcTTy
|
|
+lz2c78Xnu0NXvq7gsPRF4zDtIpjHbUXJ3ZRPHs342suG7Tb4nvQAbxYMJQHSN10k
|
|
+W6w+gEeN7t7V
|
|
+-----END CMS-----
|
|
diff --git a/tests/test_auth_token_middleware.py b/tests/test_auth_token_middleware.py
|
|
index e6893ee..dfe424f 100644
|
|
--- a/tests/test_auth_token_middleware.py
|
|
+++ b/tests/test_auth_token_middleware.py
|
|
@@ -154,6 +154,9 @@ def setUpModule(self):
|
|
signing_path = os.path.join(os.path.dirname(__file__), 'signing')
|
|
with open(os.path.join(signing_path, 'auth_token_scoped.pem')) as f:
|
|
self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read())
|
|
+ with open(os.path.join(signing_path,
|
|
+ 'auth_token_scoped_expired.pem')) as f:
|
|
+ self.SIGNED_TOKEN_SCOPED_EXPIRED = cms.cms_to_token(f.read())
|
|
with open(os.path.join(signing_path, 'auth_token_unscoped.pem')) as f:
|
|
self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read())
|
|
with open(os.path.join(signing_path, 'auth_token_revoked.pem')) as f:
|
|
@@ -612,6 +615,13 @@ class AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest):
|
|
self.middleware(req.environ, self.start_fake_response)
|
|
self.assertEqual(self.middleware._cache.set_value, None)
|
|
|
|
+ def test_expired(self):
|
|
+ req = webob.Request.blank('/')
|
|
+ token = SIGNED_TOKEN_SCOPED_EXPIRED
|
|
+ req.headers['X-Auth-Token'] = token
|
|
+ self.middleware(req.environ, self.start_fake_response)
|
|
+ self.assertEqual(self.response_status, 401)
|
|
+
|
|
def test_memcache_set_invalid(self):
|
|
req = webob.Request.blank('/')
|
|
req.headers['X-Auth-Token'] = 'invalid-token'
|
|
--
|
|
1.8.1.2
|
|
|