diff options
author | José Padilla <jpadilla@webapplicate.com> | 2015-03-17 10:08:44 -0400 |
---|---|---|
committer | José Padilla <jpadilla@webapplicate.com> | 2015-03-17 10:08:44 -0400 |
commit | d47163117bef52392f314406ad0a4177e2a65e16 (patch) | |
tree | 7920c174502cad2d6d8721a3925736738fd33d94 | |
parent | 492e96f91da493924fd1e6f279054935d5ad69e4 (diff) | |
parent | 7c4e96b3a56e7d8b8a4b05b086639c1e2ac25cca (diff) | |
download | pyjwt-d47163117bef52392f314406ad0a4177e2a65e16.tar.gz |
Merge pull request #103 from mark-adams/contrib-algorithms
Back from the dead: PyCrypto and ECDSA
-rw-r--r-- | .travis.yml | 4 | ||||
-rw-r--r-- | jwt/algorithms.py | 33 | ||||
-rw-r--r-- | jwt/contrib/__init__.py | 0 | ||||
-rw-r--r-- | jwt/contrib/algorithms/__init__.py | 0 | ||||
-rw-r--r-- | jwt/contrib/algorithms/py_ecdsa.py | 60 | ||||
-rw-r--r-- | jwt/contrib/algorithms/pycrypto.py | 47 | ||||
-rw-r--r-- | tests/contrib/__init__.py | 0 | ||||
-rw-r--r-- | tests/contrib/test_algorithms.py | 193 | ||||
-rw-r--r-- | tests/test_algorithms.py | 44 | ||||
-rw-r--r-- | tests/utils.py | 7 | ||||
-rw-r--r-- | tox.ini | 25 |
11 files changed, 376 insertions, 37 deletions
diff --git a/.travis.yml b/.travis.yml index 62aee8e..6dbb1b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,16 @@ language: python sudo: false env: + - TOXENV=pep8 - TOXENV=py26 - TOXENV=py27 - TOXENV=py32 - TOXENV=py33 - TOXENV=py34 - - TOXENV=pep8 - TOXENV=py34-nocrypto - TOXENV=py27-nocrypto + - TOXENV=py34-contrib-crypto + - TOXENV=py27-contrib-crypto install: - pip install tox coveralls script: diff --git a/jwt/algorithms.py b/jwt/algorithms.py index d347dcc..720d675 100644 --- a/jwt/algorithms.py +++ b/jwt/algorithms.py @@ -23,18 +23,18 @@ def _register_default_algorithms(): Registers the algorithms that are implemented by the library. """ register_algorithm('none', NoneAlgorithm()) - register_algorithm('HS256', HMACAlgorithm(hashlib.sha256)) - register_algorithm('HS384', HMACAlgorithm(hashlib.sha384)) - register_algorithm('HS512', HMACAlgorithm(hashlib.sha512)) + register_algorithm('HS256', HMACAlgorithm(HMACAlgorithm.SHA256)) + register_algorithm('HS384', HMACAlgorithm(HMACAlgorithm.SHA384)) + register_algorithm('HS512', HMACAlgorithm(HMACAlgorithm.SHA512)) if has_crypto: - register_algorithm('RS256', RSAAlgorithm(hashes.SHA256())) - register_algorithm('RS384', RSAAlgorithm(hashes.SHA384())) - register_algorithm('RS512', RSAAlgorithm(hashes.SHA512())) + register_algorithm('RS256', RSAAlgorithm(RSAAlgorithm.SHA256)) + register_algorithm('RS384', RSAAlgorithm(RSAAlgorithm.SHA384)) + register_algorithm('RS512', RSAAlgorithm(RSAAlgorithm.SHA512)) - register_algorithm('ES256', ECAlgorithm(hashes.SHA256())) - register_algorithm('ES384', ECAlgorithm(hashes.SHA384())) - register_algorithm('ES512', ECAlgorithm(hashes.SHA512())) + register_algorithm('ES256', ECAlgorithm(ECAlgorithm.SHA256)) + register_algorithm('ES384', ECAlgorithm(ECAlgorithm.SHA384)) + register_algorithm('ES512', ECAlgorithm(ECAlgorithm.SHA512)) class Algorithm(object): @@ -83,6 +83,10 @@ class HMACAlgorithm(Algorithm): Performs signing and verification operations using HMAC and the specified hash function. """ + SHA256 = hashlib.sha256 + SHA384 = hashlib.sha384 + SHA512 = hashlib.sha512 + def __init__(self, hash_alg): self.hash_alg = hash_alg @@ -108,9 +112,12 @@ if has_crypto: Performs signing and verification operations using RSASSA-PKCS-v1_5 and the specified hash function. """ + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 def __init__(self, hash_alg): - self.hash_alg = hash_alg + self.hash_alg = hash_alg() def prepare_key(self, key): if isinstance(key, interfaces.RSAPrivateKey) or \ @@ -162,8 +169,12 @@ if has_crypto: Performs signing and verification operations using ECDSA and the specified hash function """ + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + def __init__(self, hash_alg): - self.hash_alg = hash_alg + self.hash_alg = hash_alg() def prepare_key(self, key): if isinstance(key, interfaces.EllipticCurvePrivateKey) or \ diff --git a/jwt/contrib/__init__.py b/jwt/contrib/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/jwt/contrib/__init__.py diff --git a/jwt/contrib/algorithms/__init__.py b/jwt/contrib/algorithms/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/jwt/contrib/algorithms/__init__.py diff --git a/jwt/contrib/algorithms/py_ecdsa.py b/jwt/contrib/algorithms/py_ecdsa.py new file mode 100644 index 0000000..dea2710 --- /dev/null +++ b/jwt/contrib/algorithms/py_ecdsa.py @@ -0,0 +1,60 @@ +# Note: This file is named py_ecdsa.py because import behavior in Python 2 +# would cause ecdsa.py to squash the ecdsa library that it depends upon. + +import hashlib + +import ecdsa + +from jwt.algorithms import Algorithm +from jwt.compat import string_types, text_type + + +class ECAlgorithm(Algorithm): + """ + Performs signing and verification operations using + ECDSA and the specified hash function + + This class requires the ecdsa package to be installed. + + This is based off of the implementation in PyJWT 0.3.2 + """ + SHA256 = hashlib.sha256 + SHA384 = hashlib.sha384 + SHA512 = hashlib.sha512 + + def __init__(self, hash_alg): + self.hash_alg = hash_alg + + def prepare_key(self, key): + + if isinstance(key, ecdsa.SigningKey) or \ + isinstance(key, ecdsa.VerifyingKey): + return key + + if isinstance(key, string_types): + if isinstance(key, text_type): + key = key.encode('utf-8') + + # Attempt to load key. We don't know if it's + # a Signing Key or a Verifying Key, so we try + # the Verifying Key first. + try: + key = ecdsa.VerifyingKey.from_pem(key) + except ecdsa.der.UnexpectedDER: + key = ecdsa.SigningKey.from_pem(key) + + else: + raise TypeError('Expecting a PEM-formatted key.') + + return key + + def sign(self, msg, key): + return key.sign(msg, hashfunc=self.hash_alg, + sigencode=ecdsa.util.sigencode_der) + + def verify(self, msg, key, sig): + try: + return key.verify(sig, msg, hashfunc=self.hash_alg, + sigdecode=ecdsa.util.sigdecode_der) + except ecdsa.der.UnexpectedDER: + return False diff --git a/jwt/contrib/algorithms/pycrypto.py b/jwt/contrib/algorithms/pycrypto.py new file mode 100644 index 0000000..e6afaa5 --- /dev/null +++ b/jwt/contrib/algorithms/pycrypto.py @@ -0,0 +1,47 @@ +import Crypto.Hash.SHA256 +import Crypto.Hash.SHA384 +import Crypto.Hash.SHA512 + +from Crypto.PublicKey import RSA +from Crypto.Signature import PKCS1_v1_5 + +from jwt.algorithms import Algorithm +from jwt.compat import string_types, text_type + + +class RSAAlgorithm(Algorithm): + """ + Performs signing and verification operations using + RSASSA-PKCS-v1_5 and the specified hash function. + + This class requires PyCrypto package to be installed. + + This is based off of the implementation in PyJWT 0.3.2 + """ + SHA256 = Crypto.Hash.SHA256 + SHA384 = Crypto.Hash.SHA384 + SHA512 = Crypto.Hash.SHA512 + + def __init__(self, hash_alg): + self.hash_alg = hash_alg + + def prepare_key(self, key): + + if isinstance(key, RSA._RSAobj): + return key + + if isinstance(key, string_types): + if isinstance(key, text_type): + key = key.encode('utf-8') + + key = RSA.importKey(key) + else: + raise TypeError('Expecting a PEM- or RSA-formatted key.') + + return key + + def sign(self, msg, key): + return PKCS1_v1_5.new(key).sign(self.hash_alg.new(msg)) + + def verify(self, msg, key, sig): + return PKCS1_v1_5.new(key).verify(self.hash_alg.new(msg), sig) diff --git a/tests/contrib/__init__.py b/tests/contrib/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/contrib/__init__.py diff --git a/tests/contrib/test_algorithms.py b/tests/contrib/test_algorithms.py new file mode 100644 index 0000000..2b156f8 --- /dev/null +++ b/tests/contrib/test_algorithms.py @@ -0,0 +1,193 @@ +import base64 + +from ..compat import unittest +from ..utils import ensure_bytes, ensure_unicode, key_path + +try: + from jwt.contrib.algorithms.pycrypto import RSAAlgorithm + has_pycrypto = True +except ImportError: + has_pycrypto = False + +try: + from jwt.contrib.algorithms.py_ecdsa import ECAlgorithm + has_ecdsa = True +except ImportError: + has_ecdsa = False + + +@unittest.skipIf(not has_pycrypto, 'Not supported without PyCrypto library') +class TestPycryptoAlgorithms(unittest.TestCase): + def setUp(self): # noqa + pass + + def test_rsa_should_parse_pem_public_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey2_rsa.pub.pem'), 'r') as pem_key: + algo.prepare_key(pem_key.read()) + + def test_rsa_should_accept_unicode_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa'), 'r') as rsa_key: + algo.prepare_key(ensure_unicode(rsa_key.read())) + + def test_rsa_should_reject_non_string_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with self.assertRaises(TypeError): + algo.prepare_key(None) + + def test_rsa_sign_should_generate_correct_signature_value(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + jwt_message = ensure_bytes('Hello World!') + + expected_sig = base64.b64decode(ensure_bytes( + 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' + '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' + '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' + 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' + 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' + 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) + + with open(key_path('testkey_rsa'), 'r') as keyfile: + jwt_key = algo.prepare_key(keyfile.read()) + + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: + jwt_pub_key = algo.prepare_key(keyfile.read()) + + algo.sign(jwt_message, jwt_key) + result = algo.verify(jwt_message, jwt_pub_key, expected_sig) + self.assertTrue(result) + + def test_rsa_verify_should_return_false_if_signature_invalid(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + jwt_message = ensure_bytes('Hello World!') + + jwt_sig = base64.b64decode(ensure_bytes( + 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' + '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' + '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' + 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' + 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' + 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) + + jwt_sig += ensure_bytes('123') # Signature is now invalid + + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: + jwt_pub_key = algo.prepare_key(keyfile.read()) + + result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) + self.assertFalse(result) + + def test_rsa_verify_should_return_true_if_signature_valid(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + jwt_message = ensure_bytes('Hello World!') + + jwt_sig = base64.b64decode(ensure_bytes( + 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' + '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' + '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' + 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' + 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' + 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) + + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: + jwt_pub_key = algo.prepare_key(keyfile.read()) + + result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) + self.assertTrue(result) + + def test_rsa_prepare_key_should_be_idempotent(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: + jwt_pub_key_first = algo.prepare_key(keyfile.read()) + jwt_pub_key_second = algo.prepare_key(jwt_pub_key_first) + + self.assertEqual(jwt_pub_key_first, jwt_pub_key_second) + + +@unittest.skipIf(not has_ecdsa, 'Not supported without ecdsa library') +class TestEcdsaAlgorithms(unittest.TestCase): + def test_ec_should_reject_non_string_key(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + with self.assertRaises(TypeError): + algo.prepare_key(None) + + def test_ec_should_accept_unicode_key(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + with open(key_path('testkey_ec'), 'r') as ec_key: + algo.prepare_key(ensure_unicode(ec_key.read())) + + def test_ec_sign_should_generate_correct_signature_value(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + jwt_message = ensure_bytes('Hello World!') + + expected_sig = base64.b64decode(ensure_bytes( + 'MIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT5' + '5FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif' + '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' + 'zJ8hSJmbw==')) + + with open(key_path('testkey_ec'), 'r') as keyfile: + jwt_key = algo.prepare_key(keyfile.read()) + + with open(key_path('testkey_ec.pub'), 'r') as keyfile: + jwt_pub_key = algo.prepare_key(keyfile.read()) + + algo.sign(jwt_message, jwt_key) + result = algo.verify(jwt_message, jwt_pub_key, expected_sig) + self.assertTrue(result) + + def test_ec_verify_should_return_false_if_signature_invalid(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + jwt_message = ensure_bytes('Hello World!') + + jwt_sig = base64.b64decode(ensure_bytes( + 'MIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT5' + '5FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif' + '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' + 'zJ8hSJmbw==')) + + jwt_sig += ensure_bytes('123') # Signature is now invalid + + with open(key_path('testkey_ec.pub'), 'r') as keyfile: + jwt_pub_key = algo.prepare_key(keyfile.read()) + + result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) + self.assertFalse(result) + + def test_ec_verify_should_return_true_if_signature_valid(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + jwt_message = ensure_bytes('Hello World!') + + jwt_sig = base64.b64decode(ensure_bytes( + 'MIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT5' + '5FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif' + '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' + 'zJ8hSJmbw==')) + + with open(key_path('testkey_ec.pub'), 'r') as keyfile: + jwt_pub_key = algo.prepare_key(keyfile.read()) + + result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) + self.assertTrue(result) + + def test_ec_prepare_key_should_be_idempotent(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + with open(key_path('testkey_ec.pub'), 'r') as keyfile: + jwt_pub_key_first = algo.prepare_key(keyfile.read()) + jwt_pub_key_second = algo.prepare_key(jwt_pub_key_first) + + self.assertEqual(jwt_pub_key_first, jwt_pub_key_second) diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py index 73ebb05..0fafc4d 100644 --- a/tests/test_algorithms.py +++ b/tests/test_algorithms.py @@ -1,13 +1,11 @@ import base64 -import hashlib from jwt.algorithms import Algorithm, HMACAlgorithm from .compat import unittest -from .utils import ensure_bytes, ensure_unicode +from .utils import ensure_bytes, ensure_unicode, key_path try: - from cryptography.hazmat.primitives import hashes from jwt.algorithms import RSAAlgorithm, ECAlgorithm has_crypto = True @@ -38,7 +36,7 @@ class TestAlgorithms(unittest.TestCase): algo.verify('message', 'key', 'signature') def test_hmac_should_reject_nonstring_key(self): - algo = HMACAlgorithm(hashlib.sha256()) + algo = HMACAlgorithm(HMACAlgorithm.SHA256) with self.assertRaises(TypeError) as context: algo.prepare_key(object()) @@ -47,34 +45,34 @@ class TestAlgorithms(unittest.TestCase): self.assertEqual(str(exception), 'Expecting a string- or bytes-formatted key.') def test_hmac_should_accept_unicode_key(self): - algo = HMACAlgorithm(hashlib.sha256()) + algo = HMACAlgorithm(HMACAlgorithm.SHA256) algo.prepare_key(ensure_unicode('awesome')) @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_rsa_should_parse_pem_public_key(self): - algo = RSAAlgorithm(hashes.SHA256()) + algo = RSAAlgorithm(RSAAlgorithm.SHA256) - with open('tests/keys/testkey2_rsa.pub.pem', 'r') as pem_key: + with open(key_path('testkey2_rsa.pub.pem'), 'r') as pem_key: algo.prepare_key(pem_key.read()) @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_rsa_should_accept_unicode_key(self): - algo = RSAAlgorithm(hashes.SHA256()) + algo = RSAAlgorithm(RSAAlgorithm.SHA256) - with open('tests/keys/testkey_rsa', 'r') as rsa_key: + with open(key_path('testkey_rsa'), 'r') as rsa_key: algo.prepare_key(ensure_unicode(rsa_key.read())) @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_rsa_should_reject_non_string_key(self): - algo = RSAAlgorithm(hashes.SHA256()) + algo = RSAAlgorithm(RSAAlgorithm.SHA256) with self.assertRaises(TypeError): algo.prepare_key(None) @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_rsa_verify_should_return_false_if_signature_invalid(self): - algo = RSAAlgorithm(hashes.SHA256()) + algo = RSAAlgorithm(RSAAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') @@ -86,9 +84,9 @@ class TestAlgorithms(unittest.TestCase): 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) - jwt_sig = jwt_sig + ensure_bytes('123') # Signature is now invalid + jwt_sig += ensure_bytes('123') # Signature is now invalid - with open('tests/keys/testkey_rsa.pub', 'r') as keyfile: + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) @@ -96,7 +94,7 @@ class TestAlgorithms(unittest.TestCase): @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_rsa_verify_should_return_true_if_signature_valid(self): - algo = RSAAlgorithm(hashes.SHA256()) + algo = RSAAlgorithm(RSAAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') @@ -108,7 +106,7 @@ class TestAlgorithms(unittest.TestCase): 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) - with open('tests/keys/testkey_rsa.pub', 'r') as keyfile: + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) @@ -116,21 +114,21 @@ class TestAlgorithms(unittest.TestCase): @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_ec_should_reject_non_string_key(self): - algo = ECAlgorithm(hashes.SHA256()) + algo = ECAlgorithm(ECAlgorithm.SHA256) with self.assertRaises(TypeError): algo.prepare_key(None) @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_ec_should_accept_unicode_key(self): - algo = ECAlgorithm(hashes.SHA256()) + algo = ECAlgorithm(ECAlgorithm.SHA256) - with open('tests/keys/testkey_ec', 'r') as ec_key: + with open(key_path('testkey_ec'), 'r') as ec_key: algo.prepare_key(ensure_unicode(ec_key.read())) @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_ec_verify_should_return_false_if_signature_invalid(self): - algo = ECAlgorithm(hashes.SHA256()) + algo = ECAlgorithm(ECAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') @@ -140,9 +138,9 @@ class TestAlgorithms(unittest.TestCase): '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' 'zJ8hSJmbw==')) - jwt_sig = ensure_bytes('123') # Signature is now invalid + jwt_sig += ensure_bytes('123') # Signature is now invalid - with open('tests/keys/testkey_ec.pub', 'r') as keyfile: + with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) @@ -150,7 +148,7 @@ class TestAlgorithms(unittest.TestCase): @unittest.skipIf(not has_crypto, 'Not supported without cryptography library') def test_ec_verify_should_return_true_if_signature_valid(self): - algo = ECAlgorithm(hashes.SHA256()) + algo = ECAlgorithm(ECAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') @@ -160,7 +158,7 @@ class TestAlgorithms(unittest.TestCase): '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' 'zJ8hSJmbw==')) - with open('tests/keys/testkey_ec.pub', 'r') as keyfile: + with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) diff --git a/tests/utils.py b/tests/utils.py index 7b6d70e..4d455b5 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,3 +1,5 @@ +import os + from .compat import text_type @@ -13,3 +15,8 @@ def ensure_unicode(key): key = key.decode() return key + + +def key_path(key_name): + return os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'keys', key_name) @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, py32, py33, py34, py34-nocrypto, pep8 +envlist = py26, py27, py27-contrib-crypto, py27-nocrypto, py32, py33, py34, py34-contrib-crypto, py34-nocrypto, pep8 [testenv] commands = @@ -11,6 +11,28 @@ deps = unittest2 coverage +[testenv:py34-contrib-crypto] +basepython = python3.4 +commands = + coverage erase + coverage run setup.py test + coverage report -m +deps = + pycrypto + ecdsa + coverage + +[testenv:py27-contrib-crypto] +basepython = python2.7 +commands = + coverage erase + coverage run setup.py test + coverage report -m +deps = + pycrypto + ecdsa + coverage + [testenv:py34-nocrypto] basepython = python3.4 commands = @@ -35,6 +57,5 @@ deps = flake8 flake8-import-order pep8-naming - unittest2 commands = flake8 |