From 083254f7dca63aac5cd36d848af4fc9266199ac2 Mon Sep 17 00:00:00 2001 From: Mickael Viey Date: Fri, 9 Feb 2018 13:54:38 +0100 Subject: [PATCH 1/5] OrderedDict for headers Construct headers from an ordered dictionary instead a standard dict. This makes it possible not to send the headers in the token and rebuild them on the server side when it is used by client. Indeed, for this the json must be predictable. What do not allow std python dictionaries. --- jose/jws.py | 10 +++++----- jose/jwt.py | 26 +++++++++++++------------- requirements-dev.txt | 2 ++ tests/test_jwt.py | 16 +++++++++++++++- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/jose/jws.py b/jose/jws.py index 119d9663..2f72299c 100644 --- a/jose/jws.py +++ b/jose/jws.py @@ -3,7 +3,7 @@ import json import six -from collections import Mapping, Iterable +from collections import Mapping, Iterable, OrderedDict from jose import jwk from jose.constants import ALGORITHMS @@ -128,10 +128,10 @@ def get_unverified_claims(token): def _encode_header(algorithm, additional_headers=None): - header = { - "typ": "JWT", - "alg": algorithm - } + header = OrderedDict(( + ("typ", "JWT"), + ("alg", algorithm) + )) if additional_headers: header.update(additional_headers) diff --git a/jose/jwt.py b/jose/jwt.py index 2da511fd..bf4bdbcf 100644 --- a/jose/jwt.py +++ b/jose/jwt.py @@ -3,7 +3,7 @@ import json from calendar import timegm -from collections import Mapping +from collections import Mapping, OrderedDict from datetime import datetime from datetime import timedelta from six import string_types @@ -112,18 +112,18 @@ def decode(token, key, algorithms=None, options=None, audience=None, """ - defaults = { - 'verify_signature': True, - 'verify_aud': True, - 'verify_iat': True, - 'verify_exp': True, - 'verify_nbf': True, - 'verify_iss': True, - 'verify_sub': True, - 'verify_jti': True, - 'verify_at_hash': True, - 'leeway': 0, - } + defaults = OrderedDict(( + ('verify_signature', True), + ('verify_aud', True), + ('verify_iat', True), + ('verify_exp', True), + ('verify_nbf', True), + ('verify_iss', True), + ('verify_sub', True), + ('verify_jti', True), + ('verify_at_hash', True), + ('leeway', 0), + )) if options: defaults.update(options) diff --git a/requirements-dev.txt b/requirements-dev.txt index 9a7399c8..28054fde 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -9,6 +9,8 @@ pytest==2.7.0 pytest-cov==1.8.1 ecdsa==0.13 wsgiref==0.1.2 +cryptography==2.1.4 + -r requirements.txt -r requirements-rtd.txt diff --git a/tests/test_jwt.py b/tests/test_jwt.py index 485fff52..66543f34 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -2,6 +2,9 @@ from jose import jwt from jose.exceptions import JWTError +from base64 import b64decode, b64encode +from json import dumps +from collections import OrderedDict from datetime import datetime from datetime import timedelta @@ -24,7 +27,7 @@ def key(): @pytest.fixture def headers(): headers = { - 'kid': 'my-key-id', + 'kid': 'my-key-id' } return headers @@ -49,6 +52,17 @@ def test_non_default_headers(self, claims, key, headers): for k, v in headers.items(): assert all_headers[k] == v + def test_ordered_json(self, claims, key): + headers = OrderedDict(( + ('typ', 'JWT'), + ('alg', 'HS256'), + ('kid', 'my-key-id'), + ('a', '123'), + )) + encoded = jwt.encode(claims, key, headers=headers) + assert encoded.split('.')[0] == b64encode( + dumps(headers).replace(' ', '')).replace('==', '') + def test_encode(self, claims, key): expected = ( From b3cae6ca61d4512e1ea73f848eb25034912b04f4 Mon Sep 17 00:00:00 2001 From: Mickael Viey Date: Fri, 9 Feb 2018 14:17:06 +0100 Subject: [PATCH 2/5] python3 compatibility --- tests/test_jwt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index 66543f34..fe78f84f 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -61,7 +61,9 @@ def test_ordered_json(self, claims, key): )) encoded = jwt.encode(claims, key, headers=headers) assert encoded.split('.')[0] == b64encode( - dumps(headers).replace(' ', '')).replace('==', '') + dumps(headers) + .replace(b' ', b'') + .encode('iso8859')).replace(b'==', b'') def test_encode(self, claims, key): From 0097afed743f291c8e67c3eb95b7f134d1a9dc4d Mon Sep 17 00:00:00 2001 From: Mickael Viey Date: Fri, 9 Feb 2018 14:21:45 +0100 Subject: [PATCH 3/5] python3 compatibility --- tests/test_jwt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index fe78f84f..e52dcf4f 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -63,7 +63,7 @@ def test_ordered_json(self, claims, key): assert encoded.split('.')[0] == b64encode( dumps(headers) .replace(b' ', b'') - .encode('iso8859')).replace(b'==', b'') + .encode('iso8859')).replace('==', '') def test_encode(self, claims, key): From 9e55cd571560e6b91c4d2d668ea272e01c4defb4 Mon Sep 17 00:00:00 2001 From: Mickael Viey Date: Fri, 9 Feb 2018 14:36:16 +0100 Subject: [PATCH 4/5] python3 compatibility --- tests/test_jwt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index e52dcf4f..3d236283 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -62,8 +62,8 @@ def test_ordered_json(self, claims, key): encoded = jwt.encode(claims, key, headers=headers) assert encoded.split('.')[0] == b64encode( dumps(headers) - .replace(b' ', b'') - .encode('iso8859')).replace('==', '') + .replace(' ', '') + .encode('iso8859')).replace(b'==', b'') def test_encode(self, claims, key): From cb784b8015d6b9e4347e73896e7f322d13c679e3 Mon Sep 17 00:00:00 2001 From: Mickael Viey Date: Fri, 9 Feb 2018 14:41:56 +0100 Subject: [PATCH 5/5] python3 compatibility --- tests/test_jwt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index 3d236283..89443548 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -60,7 +60,7 @@ def test_ordered_json(self, claims, key): ('a', '123'), )) encoded = jwt.encode(claims, key, headers=headers) - assert encoded.split('.')[0] == b64encode( + assert encoded.split('.')[0].encode('iso8859') == b64encode( dumps(headers) .replace(' ', '') .encode('iso8859')).replace(b'==', b'')