Skip to content

Commit 7dd3d4a

Browse files
authored
Merge pull request jpadilla#231 from vimalloc/master
Better error messages when missing cryptography package
2 parents 5caa1af + 439f9a3 commit 7dd3d4a

File tree

7 files changed

+25
-2
lines changed

7 files changed

+25
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88
-------------------------------------------------------------------------
99
### Changed
1010
- Renamed commandline script `jwt` to `jwt-cli` to avoid issues with the script clobbering the `jwt` module in some circumstances.
11+
- Better error messages when using an algorithm that requires the cryptography package, but it isn't available [#230][230]
1112

1213
### Fixed
1314

jwt/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,6 @@ def main():
131131
else:
132132
p.print_help()
133133

134+
134135
if __name__ == '__main__':
135136
main()

jwt/algorithms.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
except ImportError:
3232
has_crypto = False
3333

34+
requires_cryptography = set(['RS256', 'RS384', 'RS512', 'ES256', 'ES384',
35+
'ES521', 'ES512', 'PS256', 'PS384', 'PS512'])
36+
3437

3538
def get_default_algorithms():
3639
"""
@@ -171,6 +174,7 @@ def sign(self, msg, key):
171174
def verify(self, msg, key, sig):
172175
return constant_time_compare(sig, self.sign(msg, key))
173176

177+
174178
if has_crypto:
175179

176180
class RSAAlgorithm(Algorithm):

jwt/api_jws.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
from collections import Mapping
66

7-
from .algorithms import Algorithm, get_default_algorithms # NOQA
7+
from .algorithms import (
8+
Algorithm, get_default_algorithms, has_crypto, requires_cryptography # NOQA
9+
)
810
from .compat import binary_type, string_types, text_type
911
from .exceptions import DecodeError, InvalidAlgorithmError, InvalidTokenError
1012
from .utils import base64url_decode, base64url_encode, force_bytes, merge_dict
@@ -101,7 +103,13 @@ def encode(self, payload, key, algorithm='HS256', headers=None,
101103
signature = alg_obj.sign(signing_input, key)
102104

103105
except KeyError:
104-
raise NotImplementedError('Algorithm not supported')
106+
if not has_crypto and algorithm in requires_cryptography:
107+
raise NotImplementedError(
108+
"Algorithm '%s' could not be found. Do you have cryptography "
109+
"installed?" % algorithm
110+
)
111+
else:
112+
raise NotImplementedError('Algorithm not supported')
105113

106114
segments.append(base64url_encode(signature))
107115

@@ -198,6 +206,7 @@ def _validate_kid(self, kid):
198206
if not isinstance(kid, string_types):
199207
raise InvalidTokenError('Key ID header parameter must be a string')
200208

209+
201210
_jws_global_obj = PyJWS()
202211
encode = _jws_global_obj.encode
203212
decode = _jws_global_obj.decode

tests/keys/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def load_hmac_key():
1919

2020
return base64url_decode(force_bytes(keyobj['k']))
2121

22+
2223
try:
2324
from cryptography.hazmat.primitives.asymmetric import ec
2425
from cryptography.hazmat.backends import default_backend

tests/test_api_jws.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ def test_invalid_crypto_alg(self, jws, payload):
303303
with pytest.raises(NotImplementedError):
304304
jws.encode(payload, 'secret', algorithm='HS1024')
305305

306+
@pytest.mark.skipif(has_crypto, reason='Scenario requires cryptography to not be installed')
307+
def test_missing_crypto_library_better_error_messages(self, jws, payload):
308+
with pytest.raises(NotImplementedError) as excinfo:
309+
jws.encode(payload, 'secret', algorithm='RS256')
310+
assert 'cryptography' in str(excinfo.value)
311+
306312
def test_unicode_secret(self, jws, payload):
307313
secret = '\xc2'
308314
jws_message = jws.encode(payload, secret)

tests/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def key_path(key_name):
1313
return os.path.join(os.path.dirname(os.path.realpath(__file__)),
1414
'keys', key_name)
1515

16+
1617
# Borrowed from `cryptography`
1718
if hasattr(int, "from_bytes"):
1819
int_from_bytes = int.from_bytes

0 commit comments

Comments
 (0)