diff options
Diffstat (limited to 'tests/test_algorithms.py')
-rw-r--r-- | tests/test_algorithms.py | 270 |
1 files changed, 245 insertions, 25 deletions
diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py index e3cf1d0..97fdc22 100644 --- a/tests/test_algorithms.py +++ b/tests/test_algorithms.py @@ -1,13 +1,14 @@ import base64 +import json from jwt.algorithms import Algorithm, HMACAlgorithm, NoneAlgorithm from jwt.exceptions import InvalidKeyError -from jwt.utils import base64url_decode +from jwt.utils import base64url_decode, force_bytes, force_unicode import pytest from .keys import load_hmac_key -from .utils import ensure_bytes, ensure_unicode, key_path +from .utils import key_path try: from jwt.algorithms import RSAAlgorithm, ECAlgorithm, RSAPSSAlgorithm @@ -36,6 +37,18 @@ class TestAlgorithms: with pytest.raises(NotImplementedError): algo.verify('message', 'key', 'signature') + def test_algorithm_should_throw_exception_if_to_jwk_not_impl(self): + algo = Algorithm() + + with pytest.raises(NotImplementedError): + algo.from_jwk('value') + + def test_algorithm_should_throw_exception_if_from_jwk_not_impl(self): + algo = Algorithm() + + with pytest.raises(NotImplementedError): + algo.to_jwk('value') + def test_none_algorithm_should_throw_exception_if_key_is_not_none(self): algo = NoneAlgorithm() @@ -49,12 +62,12 @@ class TestAlgorithms: algo.prepare_key(object()) exception = context.value - assert str(exception) == 'Expecting a string- or bytes-formatted key.' + assert str(exception) == 'Expected a string value' def test_hmac_should_accept_unicode_key(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) - algo.prepare_key(ensure_unicode('awesome')) + algo.prepare_key(force_unicode('awesome')) def test_hmac_should_throw_exception_if_key_is_pem_public_key(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) @@ -84,6 +97,28 @@ class TestAlgorithms: with open(key_path('testkey2_rsa.pub.pem'), 'r') as keyfile: algo.prepare_key(keyfile.read()) + def test_hmac_jwk_should_parse_and_verify(self): + algo = HMACAlgorithm(HMACAlgorithm.SHA256) + + with open(key_path('jwk_hmac.json'), 'r') as keyfile: + key = algo.from_jwk(keyfile.read()) + + signature = algo.sign(b'Hello World!', key) + assert algo.verify(b'Hello World!', key, signature) + + def test_hmac_to_jwk_returns_correct_values(self): + algo = HMACAlgorithm(HMACAlgorithm.SHA256) + key = algo.to_jwk('secret') + + assert json.loads(key) == {'kty': 'oct', 'k': 'c2VjcmV0'} + + def test_hmac_from_jwk_should_raise_exception_if_not_hmac_key(self): + algo = HMACAlgorithm(HMACAlgorithm.SHA256) + + with open(key_path('jwk_rsa_pub.json'), 'r') as keyfile: + with pytest.raises(InvalidKeyError): + algo.from_jwk(keyfile.read()) + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_should_parse_pem_public_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) @@ -103,7 +138,7 @@ class TestAlgorithms: algo = RSAAlgorithm(RSAAlgorithm.SHA256) with open(key_path('testkey_rsa'), 'r') as rsa_key: - algo.prepare_key(ensure_unicode(rsa_key.read())) + algo.prepare_key(force_unicode(rsa_key.read())) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_should_reject_non_string_key(self): @@ -116,9 +151,9 @@ class TestAlgorithms: def test_rsa_verify_should_return_false_if_signature_invalid(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) - message = ensure_bytes('Hello World!') + message = force_bytes('Hello World!') - sig = base64.b64decode(ensure_bytes( + sig = base64.b64decode(force_bytes( 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' @@ -126,7 +161,7 @@ class TestAlgorithms: 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) - sig += ensure_bytes('123') # Signature is now invalid + sig += force_bytes('123') # Signature is now invalid with open(key_path('testkey_rsa.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) @@ -135,6 +170,191 @@ class TestAlgorithms: assert not result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_jwk_public_and_private_keys_should_parse_and_verify(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('jwk_rsa_pub.json'), 'r') as keyfile: + pub_key = algo.from_jwk(keyfile.read()) + + with open(key_path('jwk_rsa_key.json'), 'r') as keyfile: + priv_key = algo.from_jwk(keyfile.read()) + + signature = algo.sign(force_bytes('Hello World!'), priv_key) + assert algo.verify(force_bytes('Hello World!'), pub_key, signature) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_private_key_to_jwk_works_with_from_jwk(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa'), 'r') as rsa_key: + orig_key = algo.prepare_key(force_unicode(rsa_key.read())) + + parsed_key = algo.from_jwk(algo.to_jwk(orig_key)) + assert parsed_key.private_numbers() == orig_key.private_numbers() + assert parsed_key.private_numbers().public_numbers == orig_key.private_numbers().public_numbers + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_public_key_to_jwk_works_with_from_jwk(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa.pub'), 'r') as rsa_key: + orig_key = algo.prepare_key(force_unicode(rsa_key.read())) + + parsed_key = algo.from_jwk(algo.to_jwk(orig_key)) + assert parsed_key.public_numbers() == orig_key.public_numbers() + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_jwk_private_key_with_other_primes_is_invalid(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('jwk_rsa_key.json'), 'r') as keyfile: + with pytest.raises(InvalidKeyError): + keydata = json.loads(keyfile.read()) + keydata['oth'] = [] + + algo.from_jwk(json.dumps(keydata)) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_jwk_private_key_with_missing_values_is_invalid(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('jwk_rsa_key.json'), 'r') as keyfile: + with pytest.raises(InvalidKeyError): + keydata = json.loads(keyfile.read()) + del keydata['p'] + + algo.from_jwk(json.dumps(keydata)) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_jwk_private_key_can_recover_prime_factors(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('jwk_rsa_key.json'), 'r') as keyfile: + keybytes = keyfile.read() + control_key = algo.from_jwk(keybytes).private_numbers() + + keydata = json.loads(keybytes) + delete_these = ['p', 'q', 'dp', 'dq', 'qi'] + for field in delete_these: + del keydata[field] + + parsed_key = algo.from_jwk(json.dumps(keydata)).private_numbers() + + assert control_key.d == parsed_key.d + assert control_key.p == parsed_key.p + assert control_key.q == parsed_key.q + assert control_key.dmp1 == parsed_key.dmp1 + assert control_key.dmq1 == parsed_key.dmq1 + assert control_key.iqmp == parsed_key.iqmp + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_jwk_private_key_with_missing_required_values_is_invalid(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('jwk_rsa_key.json'), 'r') as keyfile: + with pytest.raises(InvalidKeyError): + keydata = json.loads(keyfile.read()) + del keydata['p'] + + algo.from_jwk(json.dumps(keydata)) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_jwk_raises_exception_if_not_a_valid_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + # Invalid JSON + with pytest.raises(InvalidKeyError): + algo.from_jwk('{not-a-real-key') + + # Missing key parts + with pytest.raises(InvalidKeyError): + algo.from_jwk('{"kty": "RSA"}') + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_to_jwk_returns_correct_values_for_public_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa.pub'), 'r') as keyfile: + pub_key = algo.prepare_key(keyfile.read()) + + key = algo.to_jwk(pub_key) + + expected = { + 'e': 'AQAB', + 'key_ops': ['verify'], + 'kty': 'RSA', + 'n': ( + '1HgzBfJv2cOjQryCwe8NEelriOTNFWKZUivevUrRhlqcmZJdCvuCJRr-xCN-' + 'OmO8qwgJJR98feNujxVg-J9Ls3_UOA4HcF9nYH6aqVXELAE8Hk_ALvxi96ms' + '1DDuAvQGaYZ-lANxlvxeQFOZSbjkz_9mh8aLeGKwqJLp3p-OhUBQpwvAUAPg' + '82-OUtgTW3nSljjeFr14B8qAneGSc_wl0ni--1SRZUXFSovzcqQOkla3W27r' + 'rLfrD6LXgj_TsDs4vD1PnIm1zcVenKT7TfYI17bsG_O_Wecwz2Nl19pL7gDo' + 'sNruF3ogJWNq1Lyn_ijPQnkPLpZHyhvuiycYcI3DiQ' + ), + } + assert json.loads(key) == expected + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_to_jwk_returns_correct_values_for_private_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa'), 'r') as keyfile: + priv_key = algo.prepare_key(keyfile.read()) + + key = algo.to_jwk(priv_key) + + expected = { + 'key_ops': [u'sign'], + 'kty': 'RSA', + 'e': 'AQAB', + 'n': ( + '1HgzBfJv2cOjQryCwe8NEelriOTNFWKZUivevUrRhlqcmZJdCvuCJRr-xCN-' + 'OmO8qwgJJR98feNujxVg-J9Ls3_UOA4HcF9nYH6aqVXELAE8Hk_ALvxi96ms' + '1DDuAvQGaYZ-lANxlvxeQFOZSbjkz_9mh8aLeGKwqJLp3p-OhUBQpwvAUAPg' + '82-OUtgTW3nSljjeFr14B8qAneGSc_wl0ni--1SRZUXFSovzcqQOkla3W27r' + 'rLfrD6LXgj_TsDs4vD1PnIm1zcVenKT7TfYI17bsG_O_Wecwz2Nl19pL7gDo' + 'sNruF3ogJWNq1Lyn_ijPQnkPLpZHyhvuiycYcI3DiQ' + ), + 'd': ('rfbs8AWdB1RkLJRlC51LukrAvYl5UfU1TE6XRa4o-DTg2-03OXLNEMyVpMr' + 'a47weEnu14StypzC8qXL7vxXOyd30SSFTffLfleaTg-qxgMZSDw-Fb_M-pU' + 'HMPMEDYG-lgGma4l4fd1yTX2ATtoUo9BVOQgWS1LMZqi0ASEOkUfzlBgL04' + 'UoaLhPSuDdLygdlDzgruVPnec0t1uOEObmrcWIkhwU2CGQzeLtuzX6OVgPh' + 'k7xcnjbDurTTVpWH0R0gbZ5ukmQ2P-YuCX8T9iWNMGjPNSkb7h02s2Oe9ZR' + 'zP007xQ0VF-Z7xyLuxk6ASmoX1S39ujSbk2WF0eXNPRgFwQ'), + 'q': ('47hlW2f1ARuWYJf9Dl6MieXjdj2dGx9PL2UH0unVzJYInd56nqXNPrQrc5k' + 'ZU65KApC9n9oKUwIxuqwAAbh8oGNEQDqnuTj-powCkdC6bwA8KH1Y-wotpq' + '_GSjxkNzjWRm2GArJSzZc6Fb8EuObOrAavKJ285-zMPCEfus1WZG0'), + 'p': ('7tr0z929Lp4OHIRJjIKM_rDrWMPtRgnV-51pgWsN6qdpDzns_PgFwrHcoyY' + 'sWIO-4yCdVWPxFOgEZ8xXTM_uwOe4VEmdZhw55Tx7axYZtmZYZbO_RIP4CG' + 'mlJlOFTiYnxpr-2Cx6kIeQmd-hf7fA3tL018aEzwYMbFMcnAGnEg0'), + 'qi': ('djo95mB0LVYikNPa-NgyDwLotLqrueb9IviMmn6zKHCwiOXReqXDX9slB8' + 'RA15uv56bmN04O__NyVFcgJ2ef169GZHiRFIgIy0Pl8LYkMhCYKKhyqM7g' + 'xN-SqGqDTKDC22j00S7jcvCaa1qadn1qbdfukZ4NXv7E2d_LO0Y2Kkc'), + 'dp': ('tgZ2-tJpEdWxu1m1EzeKa644LHVjpTRptk7H0LDc8i6SieADEuWQvkb9df' + 'fpY6tDFaQNQr3fQ6dtdAztmsP7l1b_ynwvT1nDZUcqZvl4ruBgDWFmKbjI' + 'lOCt0v9jX6MEPP5xqBx9axdkw18BnGtUuHrbzHSlUX-yh_rumpVH1SE'), + 'dq': ('xxCIuhD0YlWFbUcwFgGdBWcLIm_WCMGj7SB6aGu1VDTLr4Wu10TFWM0TNu' + 'hc9YPker2gpj5qzAmdAzwcfWSSvXpJTYR43jfulBTMoj8-2o3wCM0anclW' + 'AuKhin-kc4mh9ssDXRQZwlMymZP0QtaxUDw_nlfVrUCZgO7L1_ZsUTk') + } + assert json.loads(key) == expected + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_to_jwk_raises_exception_on_invalid_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with pytest.raises(InvalidKeyError): + algo.to_jwk({'not': 'a valid key'}) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_from_jwk_raises_exception_on_invalid_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('jwk_hmac.json'), 'r') as keyfile: + with pytest.raises(InvalidKeyError): + algo.from_jwk(keyfile.read()) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_should_reject_non_string_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) @@ -146,7 +366,7 @@ class TestAlgorithms: algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path('testkey_ec'), 'r') as ec_key: - algo.prepare_key(ensure_unicode(ec_key.read())) + algo.prepare_key(force_unicode(ec_key.read())) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_should_accept_pem_private_key_bytes(self): @@ -159,10 +379,10 @@ class TestAlgorithms: def test_ec_verify_should_return_false_if_signature_invalid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) - message = ensure_bytes('Hello World!') + message = force_bytes('Hello World!') # Mess up the signature by replacing a known byte - sig = base64.b64decode(ensure_bytes( + sig = base64.b64decode(force_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65'.replace('r', 's'))) @@ -177,9 +397,9 @@ class TestAlgorithms: def test_ec_verify_should_return_false_if_signature_wrong_length(self): algo = ECAlgorithm(ECAlgorithm.SHA256) - message = ensure_bytes('Hello World!') + message = force_bytes('Hello World!') - sig = base64.b64decode(ensure_bytes('AC+m4Jf/xI3guAC6w0w3')) + sig = base64.b64decode(force_bytes('AC+m4Jf/xI3guAC6w0w3')) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) @@ -191,7 +411,7 @@ class TestAlgorithms: def test_rsa_pss_sign_then_verify_should_return_true(self): algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256) - message = ensure_bytes('Hello World!') + message = force_bytes('Hello World!') with open(key_path('testkey_rsa'), 'r') as keyfile: priv_key = algo.prepare_key(keyfile.read()) @@ -207,9 +427,9 @@ class TestAlgorithms: def test_rsa_pss_verify_should_return_false_if_signature_invalid(self): algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256) - jwt_message = ensure_bytes('Hello World!') + jwt_message = force_bytes('Hello World!') - jwt_sig = base64.b64decode(ensure_bytes( + jwt_sig = base64.b64decode(force_bytes( 'ywKAUGRIDC//6X+tjvZA96yEtMqpOrSppCNfYI7NKyon3P7doud5v65oWNu' 'vQsz0fzPGfF7mQFGo9Cm9Vn0nljm4G6PtqZRbz5fXNQBH9k10gq34AtM02c' '/cveqACQ8gF3zxWh6qr9jVqIpeMEaEBIkvqG954E0HT9s9ybHShgHX9mlWk' @@ -217,7 +437,7 @@ class TestAlgorithms: 'daOCWqbpZDuLb1imKpmm8Nsm56kAxijMLZnpCcnPgyb7CqG+B93W9GHglA5' 'drUeR1gRtO7vqbZMsCAQ4bpjXxwbYyjQlEVuMl73UL6sOWg==')) - jwt_sig += ensure_bytes('123') # Signature is now invalid + jwt_sig += force_bytes('123') # Signature is now invalid with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) @@ -239,7 +459,7 @@ class TestAlgorithmsRFC7520: Reference: https://tools.ietf.org/html/rfc7520#section-4.4 """ - signing_input = ensure_bytes( + signing_input = force_bytes( 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZ' 'jMxNGJjNzAzNyJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ' '29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIG' @@ -247,7 +467,7 @@ class TestAlgorithmsRFC7520: 'gd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) - signature = base64url_decode(ensure_bytes( + signature = base64url_decode(force_bytes( 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0' )) @@ -265,7 +485,7 @@ class TestAlgorithmsRFC7520: Reference: https://tools.ietf.org/html/rfc7520#section-4.1 """ - signing_input = ensure_bytes( + signing_input = force_bytes( 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' @@ -273,7 +493,7 @@ class TestAlgorithmsRFC7520: 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) - signature = base64url_decode(ensure_bytes( + signature = base64url_decode(force_bytes( 'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZop' 'dHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJ' 'K3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4' @@ -296,7 +516,7 @@ class TestAlgorithmsRFC7520: Reference: https://tools.ietf.org/html/rfc7520#section-4.2 """ - signing_input = ensure_bytes( + signing_input = force_bytes( 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' @@ -304,7 +524,7 @@ class TestAlgorithmsRFC7520: 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) - signature = base64url_decode(ensure_bytes( + signature = base64url_decode(force_bytes( 'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6' '-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXz' 'g-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p' @@ -327,7 +547,7 @@ class TestAlgorithmsRFC7520: Reference: https://tools.ietf.org/html/rfc7520#section-4.3 """ - signing_input = ensure_bytes( + signing_input = force_bytes( 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' @@ -335,7 +555,7 @@ class TestAlgorithmsRFC7520: 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) - signature = base64url_decode(ensure_bytes( + signature = base64url_decode(force_bytes( 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9P' 'lon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890j' 'l8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2' |