From ec4ad9964b88ec4268c6d1ce2f29bc49ab229cbc Mon Sep 17 00:00:00 2001 From: Stepan Henek Date: Wed, 30 May 2018 12:24:31 +0200 Subject: [PATCH] check presence among claims --- CHANGELOG.rst | 2 ++ jose/jwt.py | 24 ++++++++++++++++++++++++ tests/test_jwt.py | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b58692b4..2916cf9b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,8 @@ Changelog Major """"" +* Require claim options added. + `#98 `_ * Isolate and flesh out cryptographic backends to enable independent operation. `#114 `_ `#129 `_ diff --git a/jose/jwt.py b/jose/jwt.py index 12373c12..84ff3c8c 100644 --- a/jose/jwt.py +++ b/jose/jwt.py @@ -97,6 +97,14 @@ def decode(token, key, algorithms=None, options=None, audience=None, 'verify_sub': True, 'verify_jti': True, 'verify_at_hash': True, + 'require_aud': False, + 'require_iat': False, + 'require_exp': False, + 'require_nbf': False, + 'require_iss': False, + 'require_sub': False, + 'require_jti': False, + 'require_at_hash': False, 'leeway': 0, } @@ -126,6 +134,14 @@ def decode(token, key, algorithms=None, options=None, audience=None, 'verify_sub': True, 'verify_jti': True, 'verify_at_hash': True, + 'require_aud': False, + 'require_iat': False, + 'require_exp': False, + 'require_nbf': False, + 'require_iss': False, + 'require_sub': False, + 'require_jti': False, + 'require_at_hash': False, 'leeway': 0, } @@ -455,6 +471,14 @@ def _validate_claims(claims, audience=None, issuer=None, subject=None, if isinstance(leeway, timedelta): leeway = timedelta_total_seconds(leeway) + for require_claim in [ + e[len("require_"):] for e in options.keys() if e.startswith("require_") and options[e] + ]: + if require_claim not in claims: + raise JWTError('missing required key "%s" among claims' % require_claim) + else: + options['verify_' + require_claim] = True # override verify when required + if not isinstance(audience, (string_types, type(None))): raise JWTError('audience must be a string or None') diff --git a/tests/test_jwt.py b/tests/test_jwt.py index 9ceb2391..eb2ac597 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -579,3 +579,26 @@ def test_unverified_claims_list(self): def test_unverified_claims_object(self, claims, key): token = jwt.encode(claims, key) assert jwt.get_unverified_claims(token) == claims + + @pytest.mark.parametrize( + "claim,value", [ + ("aud", "aud"), + ("ait", "ait"), + ("exp", datetime.utcnow() + timedelta(seconds=5)), + ("nbf", datetime.utcnow() - timedelta(seconds=5)), + ("iss", "iss"), + ("sub", "sub"), + ("jti", "jti"), + ] + ) + def test_require(self, claims, key, claim, value): + options = {"require_" + claim: True, "verify_" + claim: False} + + token = jwt.encode(claims, key) + with pytest.raises(JWTError): + jwt.decode(token, key, options=options, audience=str(value)) + + new_claims = dict(claims) + new_claims[claim] = value + token = jwt.encode(new_claims, key) + jwt.decode(token, key, options=options, audience=str(value))