Skip to content

Commit

Permalink
#444 leeway implementation (#445)
Browse files Browse the repository at this point in the history
* implement leeway

* Update CHANGELOG.md for 4.8.0

Co-authored-by: Andrew Chen Wang <60190294+Andrew-Chen-Wang@users.noreply.github.com>
  • Loading branch information
domdinicola and Andrew-Chen-Wang committed Aug 19, 2021
1 parent e74f4eb commit 4d7c764
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 1 deletion.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
## Unreleased

## Version 4.7.3
## Version 4.8.0

* Add integration instructions for drf-yasg ([#145](https://github.com/jazzband/djangorestframework-simplejwt/pull/145))
* Verify Serializer Should Honour Blacklist ([#239](https://github.com/jazzband/djangorestframework-simplejwt/pull/239))
* Added missing import in getting_started docs ([#431](https://github.com/jazzband/djangorestframework-simplejwt/pull/431))
* Use import_string for token_backend ([#435](https://github.com/jazzband/djangorestframework-simplejwt/pull/435))
* Add JWKS support ([#437](https://github.com/jazzband/djangorestframework-simplejwt/pull/435))
* Use pathlib instead of open in setup.py ([#339](https://github.com/jazzband/djangorestframework-simplejwt/pull/339))
* Optimize default_user_authentication_rule ([#441](https://github.com/jazzband/djangorestframework-simplejwt/pull/441))
* Add Leeway option to decode ([#445](https://github.com/jazzband/djangorestframework-simplejwt/pull/445))

## Version 4.7.2

Expand Down
10 changes: 10 additions & 0 deletions docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Some of Simple JWT's behavior can be customized through settings variables in
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
Expand Down Expand Up @@ -156,6 +157,15 @@ signing of tokens. When using Auth0 for example you might set this to
this field is excluded from the token backend and is not used during
validation.

``LEEWAY``
----------

Leeway is used to give some margin to the expiration time. This can be an
integer for seconds or a ``datetime.timedelta``. Please reference
https://pyjwt.readthedocs.io/en/latest/usage.html#expiration-time-claim-exp
for more information.


``AUTH_HEADER_TYPES``
---------------------

Expand Down
3 changes: 3 additions & 0 deletions rest_framework_simplejwt/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def __init__(
audience=None,
issuer=None,
jwk_url: str = None,
leeway=0,
):
self._validate_algorithm(algorithm)

Expand All @@ -33,6 +34,7 @@ def __init__(
self.issuer = issuer

self.jwks_client = PyJWKClient(jwk_url) if jwk_url else None
self.leeway = leeway

if algorithm.startswith("HS"):
self.verifying_key = signing_key
Expand Down Expand Up @@ -92,6 +94,7 @@ def decode(self, token, verify=True):
verify=verify,
audience=self.audience,
issuer=self.issuer,
leeway=self.leeway,
options={
'verify_aud': self.audience is not None,
'verify_signature': verify,
Expand Down
1 change: 1 addition & 0 deletions rest_framework_simplejwt/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,

'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
Expand Down
1 change: 1 addition & 0 deletions rest_framework_simplejwt/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
api_settings.AUDIENCE,
api_settings.ISSUER,
api_settings.JWK_URL,
api_settings.LEEWAY,
)
20 changes: 20 additions & 0 deletions tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@

JWK_URL = 'https://randomstring.auth0.com/.well-known/jwks.json'

LEEWAY = 100

class TestTokenBackend(TestCase):
def setUp(self):
self.hmac_token_backend = TokenBackend('HS256', SECRET)
self.hmac_leeway_token_backend = TokenBackend('HS256', SECRET, leeway=LEEWAY)
self.rsa_token_backend = TokenBackend('RS256', PRIVATE_KEY, PUBLIC_KEY)
self.aud_iss_token_backend = TokenBackend('RS256', PRIVATE_KEY, PUBLIC_KEY, AUDIENCE, ISSUER)
self.payload = {'foo': 'bar'}
Expand Down Expand Up @@ -283,3 +285,21 @@ def test_decode_when_token_algorithm_does_not_match(self):

with self.assertRaisesRegex(TokenBackendError, 'Invalid algorithm specified'):
self.hmac_token_backend.decode(token)

def test_decode_leeway_hmac_fail(self):
self.payload["exp"] = datetime_to_epoch(aware_utcnow() - timedelta(seconds=LEEWAY * 2))

expired_token = jwt.encode(self.payload, SECRET, algorithm='HS256')

with self.assertRaises(TokenBackendError):
self.hmac_leeway_token_backend.decode(expired_token)

def test_decode_leeway_hmac_success(self):
self.payload["exp"] = datetime_to_epoch(aware_utcnow() - timedelta(seconds=LEEWAY / 2))

expired_token = jwt.encode(self.payload, SECRET, algorithm='HS256')

self.assertEqual(
self.hmac_leeway_token_backend.decode(expired_token),
self.payload,
)

0 comments on commit 4d7c764

Please sign in to comment.