diff options
author | José Padilla <jpadilla@webapplicate.com> | 2020-03-28 15:27:39 -0400 |
---|---|---|
committer | José Padilla <jpadilla@webapplicate.com> | 2020-04-06 09:35:51 -0400 |
commit | 24a5b2ff84dec9f109e3e32a10e5a079cb3e7ca8 (patch) | |
tree | 9f017a380a069c4006582376761a8838eeed4583 | |
parent | e490f9d8b8bc927a0fb337eed446a44858886242 (diff) | |
download | pyjwt-24a5b2ff84dec9f109e3e32a10e5a079cb3e7ca8.tar.gz |
Handle deprecations
-rw-r--r-- | jwt/api_jws.py | 25 | ||||
-rw-r--r-- | jwt/api_jwt.py | 30 | ||||
-rw-r--r-- | tests/test_api_jws.py | 130 | ||||
-rw-r--r-- | tests/test_api_jwt.py | 214 | ||||
-rw-r--r-- | tests/test_jwt.py | 4 |
5 files changed, 239 insertions, 164 deletions
diff --git a/jwt/api_jws.py b/jwt/api_jws.py index 6a1569e..7ed4467 100644 --- a/jwt/api_jws.py +++ b/jwt/api_jws.py @@ -1,6 +1,5 @@ import binascii import json -import warnings from .algorithms import requires_cryptography # NOQA from .algorithms import Algorithm, get_default_algorithms, has_crypto @@ -132,7 +131,6 @@ class PyJWS(object): self, jwt, # type: str key="", # type: str - verify=True, # type: bool algorithms=None, # type: List[str] options=None, # type: Dict complete=False, # type: bool @@ -143,23 +141,14 @@ class PyJWS(object): verify_signature = merged_options["verify_signature"] if verify_signature and not algorithms: - warnings.warn( - "It is strongly recommended that you pass in a " + raise DecodeError( + "It is required that you pass in a " + 'value for the "algorithms" argument when calling decode(). ' - + "This argument will be mandatory in a future version.", - DeprecationWarning, ) payload, signing_input, header, signature = self._load(jwt) - if not verify: - warnings.warn( - "The verify parameter is deprecated. " - "Please use verify_signature in options instead.", - DeprecationWarning, - stacklevel=2, - ) - elif verify_signature: + if verify_signature: self._verify_signature( payload, signing_input, header, signature, key, algorithms ) @@ -225,13 +214,7 @@ class PyJWS(object): return (payload, signing_input, header, signature) def _verify_signature( - self, - payload, - signing_input, - header, - signature, - key="", - algorithms=None, + self, payload, signing_input, header, signature, key, algorithms ): alg = header.get("alg") diff --git a/jwt/api_jwt.py b/jwt/api_jwt.py index 122204a..8749683 100644 --- a/jwt/api_jwt.py +++ b/jwt/api_jwt.py @@ -1,5 +1,4 @@ import json -import warnings from calendar import timegm from datetime import datetime, timedelta @@ -77,7 +76,6 @@ class PyJWT(PyJWS): self, jwt, # type: str key="", # type: str - verify=True, # type: bool algorithms=None, # type: List[str] options=None, # type: Dict complete=False, # type: bool @@ -85,20 +83,18 @@ class PyJWT(PyJWS): ): # type: (...) -> Dict[str, Any] - if verify and not algorithms: - warnings.warn( - "It is strongly recommended that you pass in a " - + 'value for the "algorithms" argument when calling decode(). ' - + "This argument will be mandatory in a future version.", - DeprecationWarning, - ) - payload, _, _, _ = self._load(jwt) if options is None: - options = {"verify_signature": verify} + options = {"verify_signature": True} else: - options.setdefault("verify_signature", verify) + options.setdefault("verify_signature", True) + + if options["verify_signature"] and not algorithms: + raise DecodeError( + "It is required that you pass in a " + + 'value for the "algorithms" argument when calling decode(). ' + ) decoded = super(PyJWT, self).decode( jwt, @@ -119,7 +115,7 @@ class PyJWT(PyJWS): if not isinstance(payload, dict): raise DecodeError("Invalid payload string: must be a json object") - if verify: + if options["verify_signature"]: merged_options = merge_dict(self.options, options) self._validate_claims(payload, merged_options, **kwargs) @@ -133,14 +129,6 @@ class PyJWT(PyJWS): self, payload, options, audience=None, issuer=None, leeway=0, **kwargs ): - if "verify_expiration" in kwargs: - options["verify_exp"] = kwargs.get("verify_expiration", True) - warnings.warn( - "The verify_expiration parameter is deprecated. " - "Please use verify_exp in options instead.", - DeprecationWarning, - ) - if isinstance(leeway, timedelta): leeway = leeway.total_seconds() diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py index 55db607..e2e51db 100644 --- a/tests/test_api_jws.py +++ b/tests/test_api_jws.py @@ -88,8 +88,8 @@ class TestJWS: def test_encode_decode(self, jws, payload): secret = "secret" - jws_message = jws.encode(payload, secret) - decoded_payload = jws.decode(jws_message, secret) + jws_message = jws.encode(payload, secret, algorithm="HS256") + decoded_payload = jws.decode(jws_message, secret, algorithms=["HS256"]) assert decoded_payload == payload @@ -98,7 +98,7 @@ class TestJWS: ): secret = "secret" jws_token = jws.encode(payload, secret, algorithm="HS256") - jws.decode(jws_token, secret) + jws.decode(jws_token, secret, algorithms=["HS256"]) with pytest.raises(InvalidAlgorithmError): jws.decode(jws_token, secret, algorithms=["HS384"]) @@ -111,7 +111,7 @@ class TestJWS: ".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8" ) - jws.decode(unicode_jws, secret) + jws.decode(unicode_jws, secret, algorithms=["HS256"]) def test_decode_missing_segments_throws_exception(self, jws): secret = "secret" @@ -122,7 +122,7 @@ class TestJWS: ) # Missing segment with pytest.raises(DecodeError) as context: - jws.decode(example_jws, secret) + jws.decode(example_jws, secret, algorithms=["HS256"]) exception = context.value assert str(exception) == "Not enough segments" @@ -132,7 +132,7 @@ class TestJWS: example_secret = "secret" with pytest.raises(DecodeError) as context: - jws.decode(example_jws, example_secret) + jws.decode(example_jws, example_secret, algorithms=["HS256"]) exception = context.value assert "Invalid token type" in str(exception) @@ -142,7 +142,7 @@ class TestJWS: example_secret = "secret" with pytest.raises(DecodeError) as context: - jws.decode(example_jws, example_secret) + jws.decode(example_jws, example_secret, algorithms=["HS256"]) exception = context.value assert "Invalid token type" in str(exception) @@ -156,7 +156,7 @@ class TestJWS: ) with pytest.raises(DecodeError) as context: - jws.decode(example_jws, secret) + jws.decode(example_jws, secret, algorithms=["HS256"]) exception = context.value assert str(exception) == "Invalid header string: must be a json object" @@ -181,7 +181,7 @@ class TestJWS: ) with pytest.raises(InvalidAlgorithmError) as context: - jws.decode(example_jws, "secret") + jws.decode(example_jws, "secret", algorithms=["hs256"]) exception = context.value assert str(exception) == "Algorithm not supported" @@ -193,11 +193,11 @@ class TestJWS: with pytest.raises(DecodeError) as excinfo: # Backward compat for ticket #315 - jws.decode(jws_message, bad_secret) + jws.decode(jws_message, bad_secret, algorithms=["HS256"]) assert "Signature verification failed" == str(excinfo.value) with pytest.raises(InvalidSignatureError) as excinfo: - jws.decode(jws_message, bad_secret) + jws.decode(jws_message, bad_secret, algorithms=["HS256"]) assert "Signature verification failed" == str(excinfo.value) def test_decodes_valid_jws(self, jws, payload): @@ -208,7 +208,9 @@ class TestJWS: b"gEW0pdU4kxPthjtehYdhxB9mMOGajt1xCKlGGXDJ8PM" ) - decoded_payload = jws.decode(example_jws, example_secret) + decoded_payload = jws.decode( + example_jws, example_secret, algorithms=["HS256"] + ) assert decoded_payload == payload @@ -228,7 +230,9 @@ class TestJWS: b"eyJoZWxsbyI6IndvcmxkIn0.TORyNQab_MoXM7DvNKaTwbrJr4UY" b"d2SsX8hhlnWelQFmPFSf_JzC2EbLnar92t-bXsDovzxp25ExazrVHkfPkQ" ) - decoded_payload = jws.decode(example_jws, example_pubkey) + decoded_payload = jws.decode( + example_jws, example_pubkey, algorithms=["ES256"] + ) json_payload = json.loads(force_unicode(decoded_payload)) assert json_payload == example_payload @@ -256,7 +260,9 @@ class TestJWS: b"uwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBr" b"qWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8A" ) - decoded_payload = jws.decode(example_jws, example_pubkey) + decoded_payload = jws.decode( + example_jws, example_pubkey, algorithms=["RS384"] + ) json_payload = json.loads(force_unicode(decoded_payload)) assert json_payload == example_payload @@ -269,24 +275,19 @@ class TestJWS: b"SIr03zM64awWRdPrAM_61QWsZchAtgDV3pphfHPPWkI" ) - decoded_payload = jws.decode(example_jws, key=example_secret) + decoded_payload = jws.decode( + example_jws, key=example_secret, algorithms=["HS256"] + ) assert decoded_payload == payload def test_allow_skip_verification(self, jws, payload): right_secret = "foo" jws_message = jws.encode(payload, right_secret) - decoded_payload = jws.decode(jws_message, verify=False) - - assert decoded_payload == payload - - def test_verify_false_deprecated(self, jws, recwarn): - example_jws = ( - b"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9" - b".eyJoZWxsbyI6ICJ3b3JsZCJ9" - b".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8" + decoded_payload = jws.decode( + jws_message, options={"verify_signature": False} ) - pytest.deprecated_call(jws.decode, example_jws, verify=False) + assert decoded_payload == payload def test_decode_with_optional_algorithms(self, jws): example_secret = "secret" @@ -296,7 +297,13 @@ class TestJWS: b"SIr03zM64awWRdPrAM_61QWsZchAtgDV3pphfHPPWkI" ) - pytest.deprecated_call(jws.decode, example_jws, key=example_secret) + with pytest.raises(DecodeError) as exc: + jws.decode(example_jws, key=example_secret) + + assert ( + 'It is required that you pass in a value for the "algorithms" argument when calling decode().' + in str(exc.value) + ) def test_decode_no_algorithms_verify_signature_false(self, jws): example_secret = "secret" @@ -306,23 +313,22 @@ class TestJWS: b"SIr03zM64awWRdPrAM_61QWsZchAtgDV3pphfHPPWkI" ) - try: - pytest.deprecated_call( - jws.decode, - example_jws, - key=example_secret, - options={"verify_signature": False}, - ) - except pytest.fail.Exception: - pass - else: - assert False, "Unexpected DeprecationWarning raised." + jws.decode( + example_jws, + key=example_secret, + options={"verify_signature": False}, + ) def test_load_no_verification(self, jws, payload): right_secret = "foo" jws_message = jws.encode(payload, right_secret) - decoded_payload = jws.decode(jws_message, key=None, verify=False) + decoded_payload = jws.decode( + jws_message, + key=None, + algorithms=["HS256"], + options={"verify_signature": False}, + ) assert decoded_payload == payload @@ -331,14 +337,14 @@ class TestJWS: jws_message = jws.encode(payload, right_secret) with pytest.raises(DecodeError): - jws.decode(jws_message) + jws.decode(jws_message, algorithms=["HS256"]) def test_verify_signature_with_no_secret(self, jws, payload): right_secret = "foo" jws_message = jws.encode(payload, right_secret) with pytest.raises(DecodeError) as exc: - jws.decode(jws_message) + jws.decode(jws_message, algorithms=["HS256"]) assert "Signature verification" in str(exc.value) @@ -352,7 +358,7 @@ class TestJWS: ) with pytest.raises(InvalidAlgorithmError): - jws.decode(example_jws, "secret") + jws.decode(example_jws, "secret", algorithms=["HS256"]) def test_invalid_crypto_alg(self, jws, payload): with pytest.raises(NotImplementedError): @@ -369,7 +375,7 @@ class TestJWS: def test_unicode_secret(self, jws, payload): secret = "\xc2" jws_message = jws.encode(payload, secret) - decoded_payload = jws.decode(jws_message, secret) + decoded_payload = jws.decode(jws_message, secret, algorithms=["HS256"]) assert decoded_payload == payload @@ -377,7 +383,7 @@ class TestJWS: secret = "\xc2" # char value that ascii codec cannot decode jws_message = jws.encode(payload, secret) - decoded_payload = jws.decode(jws_message, secret) + decoded_payload = jws.decode(jws_message, secret, algorithms=["HS256"]) assert decoded_payload == payload @@ -385,7 +391,7 @@ class TestJWS: secret = b"\xc2" # char value that ascii codec cannot decode jws_message = jws.encode(payload, secret) - decoded_payload = jws.decode(jws_message, secret) + decoded_payload = jws.decode(jws_message, secret, algorithms=["HS256"]) assert decoded_payload == payload @@ -398,7 +404,7 @@ class TestJWS: example_secret = "secret" with pytest.raises(DecodeError) as exc: - jws.decode(example_jws, example_secret) + jws.decode(example_jws, example_secret, algorithms=["HS256"]) assert "header padding" in str(exc.value) @@ -411,7 +417,7 @@ class TestJWS: example_secret = "secret" with pytest.raises(DecodeError) as exc: - jws.decode(example_jws, example_secret) + jws.decode(example_jws, example_secret, algorithms=["HS256"]) assert "Invalid header" in str(exc.value) @@ -424,7 +430,7 @@ class TestJWS: example_secret = "secret" with pytest.raises(DecodeError) as exc: - jws.decode(example_jws, example_secret) + jws.decode(example_jws, example_secret, algorithms=["HS256"]) assert "Invalid payload padding" in str(exc.value) @@ -437,7 +443,7 @@ class TestJWS: example_secret = "secret" with pytest.raises(DecodeError) as exc: - jws.decode(example_jws, example_secret) + jws.decode(example_jws, example_secret, algorithms=["HS256"]) assert "Invalid crypto padding" in str(exc.value) @@ -445,13 +451,13 @@ class TestJWS: jws_message = jws.encode(payload, key=None, algorithm=None) with pytest.raises(DecodeError): - jws.decode(jws_message) + jws.decode(jws_message, algorithms=["none"]) def test_decode_with_algo_none_and_verify_false_should_pass( self, jws, payload ): jws_message = jws.encode(payload, key=None, algorithm=None) - jws.decode(jws_message, verify=False) + jws.decode(jws_message, options={"verify_signature": False}) def test_get_unverified_header_returns_header_values(self, jws, payload): jws_message = jws.encode( @@ -499,7 +505,7 @@ class TestJWS: force_bytes(rsa_pub_file.read()), backend=default_backend() ) - jws.decode(jws_message, pub_rsakey) + jws.decode(jws_message, pub_rsakey, algorithms=["RS256"]) # string-formatted key with open("tests/keys/testkey_rsa", "r") as rsa_priv_file: @@ -508,7 +514,7 @@ class TestJWS: with open("tests/keys/testkey_rsa.pub", "r") as rsa_pub_file: pub_rsakey = rsa_pub_file.read() - jws.decode(jws_message, pub_rsakey) + jws.decode(jws_message, pub_rsakey, algorithms=["RS256"]) @pytest.mark.skipif( not has_crypto, reason="Not supported without cryptography library" @@ -527,7 +533,7 @@ class TestJWS: pub_rsakey = load_ssh_public_key( force_bytes(rsa_pub_file.read()), backend=default_backend() ) - jws.decode(jws_message, pub_rsakey) + jws.decode(jws_message, pub_rsakey, algorithms=["RS384"]) # string-formatted key with open("tests/keys/testkey_rsa", "r") as rsa_priv_file: @@ -536,7 +542,7 @@ class TestJWS: with open("tests/keys/testkey_rsa.pub", "r") as rsa_pub_file: pub_rsakey = rsa_pub_file.read() - jws.decode(jws_message, pub_rsakey) + jws.decode(jws_message, pub_rsakey, algorithms=["RS384"]) @pytest.mark.skipif( not has_crypto, reason="Not supported without cryptography library" @@ -555,7 +561,7 @@ class TestJWS: pub_rsakey = load_ssh_public_key( force_bytes(rsa_pub_file.read()), backend=default_backend() ) - jws.decode(jws_message, pub_rsakey) + jws.decode(jws_message, pub_rsakey, algorithms=["RS512"]) # string-formatted key with open("tests/keys/testkey_rsa", "r") as rsa_priv_file: @@ -564,7 +570,7 @@ class TestJWS: with open("tests/keys/testkey_rsa.pub", "r") as rsa_pub_file: pub_rsakey = rsa_pub_file.read() - jws.decode(jws_message, pub_rsakey) + jws.decode(jws_message, pub_rsakey, algorithms=["RS512"]) def test_rsa_related_algorithms(self, jws): jws = PyJWS() @@ -603,7 +609,7 @@ class TestJWS: pub_eckey = load_pem_public_key( force_bytes(ec_pub_file.read()), backend=default_backend() ) - jws.decode(jws_message, pub_eckey) + jws.decode(jws_message, pub_eckey, algorithms=["ES256"]) # string-formatted key with open("tests/keys/testkey_ec", "r") as ec_priv_file: @@ -612,7 +618,7 @@ class TestJWS: with open("tests/keys/testkey_ec.pub", "r") as ec_pub_file: pub_eckey = ec_pub_file.read() - jws.decode(jws_message, pub_eckey) + jws.decode(jws_message, pub_eckey, algorithms=["ES256"]) @pytest.mark.skipif( not has_crypto, reason="Can't run without cryptography library" @@ -632,7 +638,7 @@ class TestJWS: pub_eckey = load_pem_public_key( force_bytes(ec_pub_file.read()), backend=default_backend() ) - jws.decode(jws_message, pub_eckey) + jws.decode(jws_message, pub_eckey, algorithms=["ES384"]) # string-formatted key with open("tests/keys/testkey_ec", "r") as ec_priv_file: @@ -641,7 +647,7 @@ class TestJWS: with open("tests/keys/testkey_ec.pub", "r") as ec_pub_file: pub_eckey = ec_pub_file.read() - jws.decode(jws_message, pub_eckey) + jws.decode(jws_message, pub_eckey, algorithms=["ES384"]) @pytest.mark.skipif( not has_crypto, reason="Can't run without cryptography library" @@ -660,7 +666,7 @@ class TestJWS: pub_eckey = load_pem_public_key( force_bytes(ec_pub_file.read()), backend=default_backend() ) - jws.decode(jws_message, pub_eckey) + jws.decode(jws_message, pub_eckey, algorithms=["ES512"]) # string-formatted key with open("tests/keys/testkey_ec", "r") as ec_priv_file: @@ -669,7 +675,7 @@ class TestJWS: with open("tests/keys/testkey_ec.pub", "r") as ec_pub_file: pub_eckey = ec_pub_file.read() - jws.decode(jws_message, pub_eckey) + jws.decode(jws_message, pub_eckey, algorithms=["ES512"]) def test_ecdsa_related_algorithms(self, jws): jws = PyJWS() diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py index 4cc5ca7..1efc218 100644 --- a/tests/test_api_jwt.py +++ b/tests/test_api_jwt.py @@ -41,7 +41,9 @@ class TestJWT: b".eyJoZWxsbyI6ICJ3b3JsZCJ9" b".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8" ) - decoded_payload = jwt.decode(example_jwt, example_secret) + decoded_payload = jwt.decode( + example_jwt, example_secret, algorithms=["HS256"] + ) assert decoded_payload == example_payload @@ -54,7 +56,9 @@ class TestJWT: b".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8" ) - decoded_payload = jwt.decode(example_jwt, key=example_secret) + decoded_payload = jwt.decode( + example_jwt, key=example_secret, algorithms=["HS256"] + ) assert decoded_payload == example_payload @@ -67,7 +71,7 @@ class TestJWT: example_secret = "secret" with pytest.raises(DecodeError) as exc: - jwt.decode(example_jwt, example_secret) + jwt.decode(example_jwt, example_secret, algorithms=["HS256"]) assert "Invalid payload string" in str(exc.value) @@ -80,7 +84,7 @@ class TestJWT: ) with pytest.raises(DecodeError) as context: - jwt.decode(example_jwt, secret) + jwt.decode(example_jwt, secret, algorithms=["HS256"]) exception = context.value assert ( @@ -96,7 +100,7 @@ class TestJWT: ) with pytest.raises(TypeError) as context: - jwt.decode(example_jwt, secret, audience=1) + jwt.decode(example_jwt, secret, audience=1, algorithms=["HS256"]) exception = context.value assert str(exception) == "audience must be a string, iterable, or None" @@ -110,7 +114,12 @@ class TestJWT: ) with pytest.raises(InvalidAudienceError) as context: - jwt.decode(example_jwt, secret, audience="my_audience") + jwt.decode( + example_jwt, + secret, + audience="my_audience", + algorithms=["HS256"], + ) exception = context.value assert str(exception) == "Invalid claim format in token" @@ -124,7 +133,12 @@ class TestJWT: ) with pytest.raises(InvalidAudienceError) as context: - jwt.decode(example_jwt, secret, audience="my_audience") + jwt.decode( + example_jwt, + secret, + audience="my_audience", + algorithms=["HS256"], + ) exception = context.value assert str(exception) == "Invalid claim format in token" @@ -134,7 +148,10 @@ class TestJWT: types = ["string", tuple(), list(), 42, set()] for t in types: - pytest.raises(TypeError, lambda: jwt.encode(t, "secret")) + pytest.raises( + TypeError, + lambda: jwt.encode(t, "secret", algorithms=["HS256"]), + ) def test_decode_raises_exception_if_exp_is_not_int(self, jwt): # >>> jwt.encode({'exp': 'not-an-int'}, 'secret') @@ -145,7 +162,7 @@ class TestJWT: ) with pytest.raises(DecodeError) as exc: - jwt.decode(example_jwt, "secret") + jwt.decode(example_jwt, "secret", algorithms=["HS256"]) assert "exp" in str(exc.value) @@ -158,7 +175,7 @@ class TestJWT: ) with pytest.raises(InvalidIssuedAtError): - jwt.decode(example_jwt, "secret") + jwt.decode(example_jwt, "secret", algorithms=["HS256"]) def test_decode_raises_exception_if_nbf_is_not_int(self, jwt): # >>> jwt.encode({'nbf': 'not-an-int'}, 'secret') @@ -169,7 +186,7 @@ class TestJWT: ) with pytest.raises(DecodeError): - jwt.decode(example_jwt, "secret") + jwt.decode(example_jwt, "secret", algorithms=["HS256"]) def test_encode_datetime(self, jwt): secret = "secret" @@ -180,7 +197,9 @@ class TestJWT: "nbf": current_datetime, } jwt_message = jwt.encode(payload, secret) - decoded_payload = jwt.decode(jwt_message, secret, leeway=1) + decoded_payload = jwt.decode( + jwt_message, secret, leeway=1, algorithms=["HS256"] + ) assert decoded_payload["exp"] == timegm( current_datetime.utctimetuple() @@ -209,7 +228,9 @@ class TestJWT: b"d2SsX8hhlnWelQFmPFSf_JzC2EbLnar92t-bXsDovzxp25ExazrVHkfPkQ" ) - decoded_payload = jwt.decode(example_jwt, example_pubkey) + decoded_payload = jwt.decode( + example_jwt, example_pubkey, algorithms=["ES256"] + ) assert decoded_payload == example_payload # 'Control' RSA JWT created by another library. @@ -235,7 +256,9 @@ class TestJWT: b"uwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBr" b"qWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8A" ) - decoded_payload = jwt.decode(example_jwt, example_pubkey) + decoded_payload = jwt.decode( + example_jwt, example_pubkey, algorithms=["RS384"] + ) assert decoded_payload == example_payload @@ -245,7 +268,7 @@ class TestJWT: jwt_message = jwt.encode(payload, secret) with pytest.raises(ExpiredSignatureError): - jwt.decode(jwt_message, secret) + jwt.decode(jwt_message, secret, algorithms=["HS256"]) def test_decode_with_notbefore(self, jwt, payload): payload["nbf"] = utc_timestamp() + 10 @@ -253,21 +276,31 @@ class TestJWT: jwt_message = jwt.encode(payload, secret) with pytest.raises(ImmatureSignatureError): - jwt.decode(jwt_message, secret) + jwt.decode(jwt_message, secret, algorithms=["HS256"]) def test_decode_skip_expiration_verification(self, jwt, payload): payload["exp"] = time.time() - 1 secret = "secret" jwt_message = jwt.encode(payload, secret) - jwt.decode(jwt_message, secret, options={"verify_exp": False}) + jwt.decode( + jwt_message, + secret, + algorithms=["HS256"], + options={"verify_exp": False}, + ) def test_decode_skip_notbefore_verification(self, jwt, payload): payload["nbf"] = time.time() + 10 secret = "secret" jwt_message = jwt.encode(payload, secret) - jwt.decode(jwt_message, secret, options={"verify_nbf": False}) + jwt.decode( + jwt_message, + secret, + algorithms=["HS256"], + options={"verify_nbf": False}, + ) def test_decode_with_expiration_with_leeway(self, jwt, payload): payload["exp"] = utc_timestamp() - 2 @@ -278,12 +311,16 @@ class TestJWT: # With 3 seconds leeway, should be ok for leeway in (3, timedelta(seconds=3)): - jwt.decode(jwt_message, secret, leeway=leeway) + jwt.decode( + jwt_message, secret, leeway=leeway, algorithms=["HS256"] + ) # With 1 seconds, should fail for leeway in (1, timedelta(seconds=1)): with pytest.raises(ExpiredSignatureError): - jwt.decode(jwt_message, secret, leeway=leeway) + jwt.decode( + jwt_message, secret, leeway=leeway, algorithms=["HS256"] + ) def test_decode_with_notbefore_with_leeway(self, jwt, payload): payload["nbf"] = utc_timestamp() + 10 @@ -291,37 +328,47 @@ class TestJWT: jwt_message = jwt.encode(payload, secret) # With 13 seconds leeway, should be ok - jwt.decode(jwt_message, secret, leeway=13) + jwt.decode(jwt_message, secret, leeway=13, algorithms=["HS256"]) with pytest.raises(ImmatureSignatureError): - jwt.decode(jwt_message, secret, leeway=1) + jwt.decode(jwt_message, secret, leeway=1, algorithms=["HS256"]) def test_check_audience_when_valid(self, jwt): payload = {"some": "payload", "aud": "urn:me"} token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", audience="urn:me") + jwt.decode(token, "secret", audience="urn:me", algorithms=["HS256"]) def test_check_audience_list_when_valid(self, jwt): payload = {"some": "payload", "aud": "urn:me"} token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", audience=["urn:you", "urn:me"]) + jwt.decode( + token, + "secret", + audience=["urn:you", "urn:me"], + algorithms=["HS256"], + ) def test_check_audience_none_specified(self, jwt): payload = {"some": "payload", "aud": "urn:me"} token = jwt.encode(payload, "secret") with pytest.raises(InvalidAudienceError): - jwt.decode(token, "secret") + jwt.decode(token, "secret", algorithms=["HS256"]) def test_raise_exception_invalid_audience_list(self, jwt): payload = {"some": "payload", "aud": "urn:me"} token = jwt.encode(payload, "secret") with pytest.raises(InvalidAudienceError): - jwt.decode(token, "secret", audience=["urn:you", "urn:him"]) + jwt.decode( + token, + "secret", + audience=["urn:you", "urn:him"], + algorithms=["HS256"], + ) def test_check_audience_in_array_when_valid(self, jwt): payload = {"some": "payload", "aud": ["urn:me", "urn:someone-else"]} token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", audience="urn:me") + jwt.decode(token, "secret", audience="urn:me", algorithms=["HS256"]) def test_raise_exception_invalid_audience(self, jwt): payload = {"some": "payload", "aud": "urn:someone-else"} @@ -329,7 +376,9 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(InvalidAudienceError): - jwt.decode(token, "secret", audience="urn-me") + jwt.decode( + token, "secret", audience="urn-me", algorithms=["HS256"] + ) def test_raise_exception_invalid_audience_in_array(self, jwt): payload = { @@ -340,7 +389,9 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(InvalidAudienceError): - jwt.decode(token, "secret", audience="urn:me") + jwt.decode( + token, "secret", audience="urn:me", algorithms=["HS256"] + ) def test_raise_exception_token_without_issuer(self, jwt): issuer = "urn:wrong" @@ -350,7 +401,7 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(MissingRequiredClaimError) as exc: - jwt.decode(token, "secret", issuer=issuer) + jwt.decode(token, "secret", issuer=issuer, algorithms=["HS256"]) assert exc.value.claim == "iss" @@ -359,7 +410,9 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(MissingRequiredClaimError) as exc: - jwt.decode(token, "secret", audience="urn:me") + jwt.decode( + token, "secret", audience="urn:me", algorithms=["HS256"] + ) assert exc.value.claim == "aud" @@ -367,7 +420,7 @@ class TestJWT: issuer = "urn:foo" payload = {"some": "payload", "iss": "urn:foo"} token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", issuer=issuer) + jwt.decode(token, "secret", issuer=issuer, algorithms=["HS256"]) def test_raise_exception_invalid_issuer(self, jwt): issuer = "urn:wrong" @@ -377,12 +430,17 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(InvalidIssuerError): - jwt.decode(token, "secret", issuer=issuer) + jwt.decode(token, "secret", issuer=issuer, algorithms=["HS256"]) def test_skip_check_audience(self, jwt): payload = {"some": "payload", "aud": "urn:me"} token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", options={"verify_aud": False}) + jwt.decode( + token, + "secret", + options={"verify_aud": False}, + algorithms=["HS256"], + ) def test_skip_check_exp(self, jwt): payload = { @@ -390,7 +448,12 @@ class TestJWT: "exp": datetime.utcnow() - timedelta(days=1), } token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", options={"verify_exp": False}) + jwt.decode( + token, + "secret", + options={"verify_exp": False}, + algorithms=["HS256"], + ) def test_decode_should_raise_error_if_exp_required_but_not_present( self, jwt @@ -402,7 +465,12 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(MissingRequiredClaimError) as exc: - jwt.decode(token, "secret", options={"require_exp": True}) + jwt.decode( + token, + "secret", + options={"require_exp": True}, + algorithms=["HS256"], + ) assert exc.value.claim == "exp" @@ -416,7 +484,12 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(MissingRequiredClaimError) as exc: - jwt.decode(token, "secret", options={"require_iat": True}) + jwt.decode( + token, + "secret", + options={"require_iat": True}, + algorithms=["HS256"], + ) assert exc.value.claim == "iat" @@ -430,7 +503,12 @@ class TestJWT: token = jwt.encode(payload, "secret") with pytest.raises(MissingRequiredClaimError) as exc: - jwt.decode(token, "secret", options={"require_nbf": True}) + jwt.decode( + token, + "secret", + options={"require_nbf": True}, + algorithms=["HS256"], + ) assert exc.value.claim == "nbf" @@ -440,7 +518,12 @@ class TestJWT: ".eyJzb21lIjoicGF5bG9hZCJ9" ".4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZA" ) - jwt.decode(token, "secret", options={"verify_signature": False}) + jwt.decode( + token, + "secret", + options={"verify_signature": False}, + algorithms=["HS256"], + ) def test_skip_check_iat(self, jwt): payload = { @@ -448,7 +531,12 @@ class TestJWT: "iat": datetime.utcnow() + timedelta(days=1), } token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", options={"verify_iat": False}) + jwt.decode( + token, + "secret", + options={"verify_iat": False}, + algorithms=["HS256"], + ) def test_skip_check_nbf(self, jwt): payload = { @@ -456,7 +544,12 @@ class TestJWT: "nbf": datetime.utcnow() + timedelta(days=1), } token = jwt.encode(payload, "secret") - jwt.decode(token, "secret", options={"verify_nbf": False}) + jwt.decode( + token, + "secret", + options={"verify_nbf": False}, + algorithms=["HS256"], + ) def test_custom_json_encoder(self, jwt): class CustomJSONEncoder(json.JSONEncoder): @@ -468,42 +561,47 @@ class TestJWT: data = {"some_decimal": Decimal("2.2")} with pytest.raises(TypeError): - jwt.encode(data, "secret") + jwt.encode(data, "secret", algorithms=["HS256"]) token = jwt.encode(data, "secret", json_encoder=CustomJSONEncoder) - payload = jwt.decode(token, "secret") + payload = jwt.decode(token, "secret", algorithms=["HS256"]) assert payload == {"some_decimal": "it worked"} - def test_decode_with_verify_expiration_kwarg(self, jwt, payload): + def test_decode_with_verify_exp_option(self, jwt, payload): payload["exp"] = utc_timestamp() - 1 secret = "secret" jwt_message = jwt.encode(payload, secret) - pytest.deprecated_call( - jwt.decode, jwt_message, secret, verify_expiration=False + jwt.decode( + jwt_message, + secret, + algorithms=["HS256"], + options={"verify_exp": False}, ) with pytest.raises(ExpiredSignatureError): - pytest.deprecated_call( - jwt.decode, jwt_message, secret, verify_expiration=True + jwt.decode( + jwt_message, + secret, + algorithms=["HS256"], + options={"verify_exp": True}, ) def test_decode_with_optional_algorithms(self, jwt, payload): secret = "secret" jwt_message = jwt.encode(payload, secret) - pytest.deprecated_call(jwt.decode, jwt_message, secret) + with pytest.raises(DecodeError) as exc: + jwt.decode(jwt_message, secret) + + assert ( + 'It is required that you pass in a value for the "algorithms" argument when calling decode().' + in str(exc.value) + ) - def test_decode_no_algorithms_verify_false(self, jwt, payload): + def test_decode_no_algorithms_verify_signature_false(self, jwt, payload): secret = "secret" jwt_message = jwt.encode(payload, secret) - try: - pytest.deprecated_call( - jwt.decode, jwt_message, secret, verify=False - ) - except pytest.fail.Exception: - pass - else: - assert False, "Unexpected DeprecationWarning raised." + jwt.decode(jwt_message, secret, options={"verify_signature": False}) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index db96f46..126fc9b 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -13,7 +13,7 @@ def test_encode_decode(): payload = {"iss": "jeff", "exp": utc_timestamp() + 15, "claim": "insanity"} secret = "secret" - jwt_message = jwt.encode(payload, secret) - decoded_payload = jwt.decode(jwt_message, secret) + jwt_message = jwt.encode(payload, secret, algorithm="HS256") + decoded_payload = jwt.decode(jwt_message, secret, algorithms=["HS256"]) assert decoded_payload == payload |