summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDolph Mathews <dolph.mathews@gmail.com>2015-03-18 03:18:31 +0000
committerDolph Mathews <dolph.mathews@gmail.com>2015-03-18 14:05:39 +0000
commit68a54c2cf1a7210abae9292aede5737203eb733a (patch)
tree9b84a7cc775dfa5ba01b9ef3c89121bc4297750a
parenta998ead704ece4cfa8519b980228192ab354c10b (diff)
URL quote Fernet tokens
The padding in base64.urlsafe_b64encode()'s output is not actually URL safe, so you have to quote the result when it's of variable length. In addition, Fernet tokens can always be handled as bytes, despite being passed in from json.loads() as Unicode. Change-Id: I72dbd4ddc066706f6af6ea2f2bcd5f0a6cb9b30c Closes-Bug: 1433372 Closes-Bug: 1431669
Notes
Notes (review): Verified+2: Jenkins Code-Review+2: ayoung <ayoung@redhat.com> Workflow+1: ayoung <ayoung@redhat.com> Code-Review+2: Brant Knudson <bknudson@us.ibm.com> Code-Review+1: Samuel de Medeiros Queiroz <samuel@lsd.ufcg.edu.br> Submitted-by: Jenkins Submitted-at: Wed, 18 Mar 2015 22:59:15 +0000 Reviewed-on: https://review.openstack.org/165279 Project: openstack/keystone Branch: refs/heads/master
-rw-r--r--keystone/tests/unit/test_v3_federation.py2
-rw-r--r--keystone/token/providers/fernet/token_formatters.py17
2 files changed, 15 insertions, 4 deletions
diff --git a/keystone/tests/unit/test_v3_federation.py b/keystone/tests/unit/test_v3_federation.py
index c15cab5..0e20469 100644
--- a/keystone/tests/unit/test_v3_federation.py
+++ b/keystone/tests/unit/test_v3_federation.py
@@ -2402,7 +2402,7 @@ class FernetFederatedTokenTests(FederationTests, FederatedSetupMixin):
2402 2402
2403 def test_federated_unscoped_token(self): 2403 def test_federated_unscoped_token(self):
2404 resp = self._issue_unscoped_token() 2404 resp = self._issue_unscoped_token()
2405 self.assertEqual(184, len(resp.headers['X-Subject-Token'])) 2405 self.assertEqual(186, len(resp.headers['X-Subject-Token']))
2406 2406
2407 def test_federated_unscoped_token_with_multiple_groups(self): 2407 def test_federated_unscoped_token_with_multiple_groups(self):
2408 assertion = 'ANOTHER_CUSTOMER_ASSERTION' 2408 assertion = 'ANOTHER_CUSTOMER_ASSERTION'
diff --git a/keystone/token/providers/fernet/token_formatters.py b/keystone/token/providers/fernet/token_formatters.py
index 35fe9e0..30cbc3e 100644
--- a/keystone/token/providers/fernet/token_formatters.py
+++ b/keystone/token/providers/fernet/token_formatters.py
@@ -21,6 +21,7 @@ from oslo_config import cfg
21from oslo_log import log 21from oslo_log import log
22from oslo_utils import timeutils 22from oslo_utils import timeutils
23import six 23import six
24from six.moves import urllib
24 25
25from keystone.auth import plugins as auth_plugins 26from keystone.auth import plugins as auth_plugins
26from keystone import exception 27from keystone import exception
@@ -64,19 +65,29 @@ class TokenFormatter(object):
64 65
65 def pack(self, payload): 66 def pack(self, payload):
66 """Pack a payload for transport as a token.""" 67 """Pack a payload for transport as a token."""
67 return self.crypto.encrypt(payload) 68 # base64 padding (if any) is not URL-safe
69 return urllib.parse.quote(self.crypto.encrypt(payload))
68 70
69 def unpack(self, token): 71 def unpack(self, token):
70 """Unpack a token, and validate the payload.""" 72 """Unpack a token, and validate the payload."""
73 token = urllib.parse.unquote(six.binary_type(token))
74
71 try: 75 try:
72 return self.crypto.decrypt(token, ttl=CONF.token.expiration) 76 return self.crypto.decrypt(token)
73 except fernet.InvalidToken as e: 77 except fernet.InvalidToken as e:
74 raise exception.Unauthorized(six.text_type(e)) 78 raise exception.Unauthorized(six.text_type(e))
75 79
76 @classmethod 80 @classmethod
77 def creation_time(cls, fernet_token): 81 def creation_time(cls, fernet_token):
78 """Returns the creation time of a valid Fernet token.""" 82 """Returns the creation time of a valid Fernet token."""
79 # fernet tokens are base64 encoded, so we need to unpack them first 83 # tokens may be transmitted as Unicode, but they're just ASCII
84 # (pypi/cryptography will refuse to operate on Unicode input)
85 fernet_token = six.binary_type(fernet_token)
86
87 # the base64 padding on fernet tokens is made URL-safe
88 fernet_token = urllib.parse.unquote(fernet_token)
89
90 # fernet tokens are base64 encoded and the padding made URL-safe
80 token_bytes = base64.urlsafe_b64decode(fernet_token) 91 token_bytes = base64.urlsafe_b64decode(fernet_token)
81 92
82 # slice into the byte array to get just the timestamp 93 # slice into the byte array to get just the timestamp