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..89443548 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,19 @@ 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].encode('iso8859') == b64encode( + dumps(headers) + .replace(' ', '') + .encode('iso8859')).replace(b'==', b'') + def test_encode(self, claims, key): expected = (