diff --git a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py index a56fe2765..8f6576f58 100644 --- a/keystoneclient/common/cms.py +++ b/keystoneclient/common/cms.py @@ -261,7 +261,7 @@ def cms_to_token(cms_text): return signed_text -def cms_hash_token(token_id): +def cms_hash_token(token_id, mode='md5'): """Hash PKI tokens. return: for ans1_token, returns the hash of the passed in token @@ -270,7 +270,7 @@ def cms_hash_token(token_id): if token_id is None: return None if is_ans1_token(token_id): - hasher = hashlib.md5() + hasher = hashlib.new(mode) if isinstance(token_id, six.text_type): token_id = token_id.encode('utf-8') hasher.update(token_id) diff --git a/keystoneclient/tests/test_cms.py b/keystoneclient/tests/test_cms.py index dbb8706d4..e5fe55bcd 100644 --- a/keystoneclient/tests/test_cms.py +++ b/keystoneclient/tests/test_cms.py @@ -15,6 +15,7 @@ import subprocess import mock import testresources +from testtools import matchers from keystoneclient.common import cms from keystoneclient import exceptions @@ -111,6 +112,32 @@ class CMSTest(utils.TestCase, testresources.ResourcedTestCase): self.examples.SIGNING_CERT_FILE, self.examples.SIGNING_CA_FILE)) + def test_cms_hash_token_no_token_id(self): + token_id = None + self.assertThat(cms.cms_hash_token(token_id), matchers.Is(None)) + + def test_cms_hash_token_not_pki(self): + """If the token_id is not a PKI token then it returns the token_id.""" + token = 'something' + self.assertFalse(cms.is_ans1_token(token)) + self.assertThat(cms.cms_hash_token(token), matchers.Is(token)) + + def test_cms_hash_token_default_md5(self): + """The default hash method is md5.""" + token = self.examples.SIGNED_TOKEN_SCOPED + token_id_default = cms.cms_hash_token(token) + token_id_md5 = cms.cms_hash_token(token, mode='md5') + self.assertThat(token_id_default, matchers.Equals(token_id_md5)) + # md5 hash is 32 chars. + self.assertThat(token_id_default, matchers.HasLength(32)) + + def test_cms_hash_token_sha256(self): + """Can also hash with sha256.""" + token = self.examples.SIGNED_TOKEN_SCOPED + token_id = cms.cms_hash_token(token, mode='sha256') + # sha256 hash is 64 chars. + self.assertThat(token_id, matchers.HasLength(64)) + def load_tests(loader, tests, pattern): return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/tests/test_utils.py b/keystoneclient/tests/test_utils.py index 909fe9344..a55978a0c 100644 --- a/keystoneclient/tests/test_utils.py +++ b/keystoneclient/tests/test_utils.py @@ -14,8 +14,11 @@ import logging import sys import six +import testresources +from testtools import matchers from keystoneclient import exceptions +from keystoneclient.tests import client_fixtures from keystoneclient.tests import utils as test_utils from keystoneclient import utils @@ -204,3 +207,34 @@ class TestPositional(test_utils.TestCase): def test_normal_method(self): self.assertEqual((self, 1, 2), self.normal_method(1, b=2)) self.assertRaises(TypeError, self.normal_method, 1, 2) + + +class HashSignedTokenTestCase(test_utils.TestCase, + testresources.ResourcedTestCase): + """Unit tests for utils.hash_signed_token().""" + + resources = [('examples', client_fixtures.EXAMPLES_RESOURCE)] + + def test_default_md5(self): + """The default hash method is md5.""" + token = self.examples.SIGNED_TOKEN_SCOPED + if six.PY3: + token = token.encode('utf-8') + token_id_default = utils.hash_signed_token(token) + token_id_md5 = utils.hash_signed_token(token, mode='md5') + self.assertThat(token_id_default, matchers.Equals(token_id_md5)) + # md5 hash is 32 chars. + self.assertThat(token_id_default, matchers.HasLength(32)) + + def test_sha256(self): + """Can also hash with sha256.""" + token = self.examples.SIGNED_TOKEN_SCOPED + if six.PY3: + token = token.encode('utf-8') + token_id = utils.hash_signed_token(token, mode='sha256') + # sha256 hash is 64 chars. + self.assertThat(token_id, matchers.HasLength(64)) + + +def load_tests(loader, tests, pattern): + return testresources.OptimisingTestSuite(tests) diff --git a/keystoneclient/utils.py b/keystoneclient/utils.py index 00d58b76c..01f134ee1 100644 --- a/keystoneclient/utils.py +++ b/keystoneclient/utils.py @@ -141,8 +141,8 @@ def isunauthenticated(f): return getattr(f, 'unauthenticated', False) -def hash_signed_token(signed_text): - hash_ = hashlib.md5() +def hash_signed_token(signed_text, mode='md5'): + hash_ = hashlib.new(mode) hash_.update(signed_text) return hash_.hexdigest()