Ensure token validation works irrespective of padding
In change I674bad86ccc9027ac3b365c10b3b142fc9d73c17 we removed the padding from Fernet tokens. This commit makes it so that we can validate Fernet tokens that come in with and without padding. Change-Id: I60e52af6c4cb39f2d136540a487bba8505a2c6b4 Closes-Bug: 1491926
This commit is contained in:
parent
aa8dc5c9c5
commit
90aca98058
@ -16,7 +16,9 @@ import hashlib
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import msgpack
|
||||
from oslo_utils import timeutils
|
||||
from six.moves import urllib
|
||||
|
||||
from keystone.common import config
|
||||
from keystone.common import utils
|
||||
@ -58,6 +60,10 @@ class TestFernetTokenProvider(unit.TestCase):
|
||||
|
||||
|
||||
class TestTokenFormatter(unit.TestCase):
|
||||
def setUp(self):
|
||||
super(TestTokenFormatter, self).setUp()
|
||||
self.useFixture(ksfixtures.KeyRepository(self.config_fixture))
|
||||
|
||||
def test_restore_padding(self):
|
||||
# 'a' will result in '==' padding, 'aa' will result in '=' padding, and
|
||||
# 'aaa' will result in no padding.
|
||||
@ -73,6 +79,39 @@ class TestTokenFormatter(unit.TestCase):
|
||||
)
|
||||
self.assertEqual(encoded_string, encoded_str_with_padding_restored)
|
||||
|
||||
def test_legacy_padding_validation(self):
|
||||
first_value = uuid.uuid4().hex
|
||||
second_value = uuid.uuid4().hex
|
||||
payload = (first_value, second_value)
|
||||
msgpack_payload = msgpack.packb(payload)
|
||||
|
||||
# NOTE(lbragstad): This method perserves the way that keystone used to
|
||||
# percent encode the tokens, prior to bug #1491926.
|
||||
def legacy_pack(payload):
|
||||
tf = token_formatters.TokenFormatter()
|
||||
encrypted_payload = tf.crypto.encrypt(payload)
|
||||
|
||||
# the encrypted_payload is returned with padding appended
|
||||
self.assertTrue(encrypted_payload.endswith('='))
|
||||
|
||||
# using urllib.parse.quote will percent encode the padding, like
|
||||
# keystone did in Kilo.
|
||||
percent_encoded_payload = urllib.parse.quote(encrypted_payload)
|
||||
|
||||
# ensure that the padding was actaully percent encoded
|
||||
self.assertTrue(percent_encoded_payload.endswith('%3D'))
|
||||
return percent_encoded_payload
|
||||
|
||||
token_with_legacy_padding = legacy_pack(msgpack_payload)
|
||||
tf = token_formatters.TokenFormatter()
|
||||
|
||||
# demonstrate the we can validate a payload that has been percent
|
||||
# encoded with the Fernet logic that existed in Kilo
|
||||
serialized_payload = tf.unpack(token_with_legacy_padding)
|
||||
returned_payload = msgpack.unpackb(serialized_payload)
|
||||
self.assertEqual(first_value, returned_payload[0])
|
||||
self.assertEqual(second_value, returned_payload[1])
|
||||
|
||||
|
||||
class TestPayloads(unit.TestCase):
|
||||
def test_uuid_hex_to_byte_conversions(self):
|
||||
|
@ -22,6 +22,7 @@ from oslo_log import log
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
from six.moves import map
|
||||
from six.moves import urllib
|
||||
|
||||
from keystone.auth import plugins as auth_plugins
|
||||
from keystone.common import utils as ks_utils
|
||||
@ -73,8 +74,19 @@ class TokenFormatter(object):
|
||||
"""Unpack a token, and validate the payload."""
|
||||
token = six.binary_type(token)
|
||||
|
||||
# Restore padding on token before decoding it
|
||||
token = TokenFormatter.restore_padding(token)
|
||||
# TODO(lbragstad): Restore padding on token before decoding it.
|
||||
# Initially in Kilo, Fernet tokens were returned to the user with
|
||||
# padding appended to the token. Later in Liberty this padding was
|
||||
# removed and restored in the Fernet provider. The following if
|
||||
# statement ensures that we can validate tokens with and without token
|
||||
# padding, in the event of an upgrade and the tokens that are issued
|
||||
# throughout the upgrade. Remove this if statement when Mitaka opens
|
||||
# for development and exclusively use the restore_padding() class
|
||||
# method.
|
||||
if token.endswith('%3D'):
|
||||
token = urllib.parse.unquote(token)
|
||||
else:
|
||||
token = TokenFormatter.restore_padding(token)
|
||||
|
||||
try:
|
||||
return self.crypto.decrypt(token)
|
||||
|
Loading…
Reference in New Issue
Block a user