Skip to content
This repository was archived by the owner on May 26, 2020. It is now read-only.

Commit 2488ddb

Browse files
committed
[refresh-token] rewrite refresh token tests without utcnow patching
[refresh-token] cleanup
1 parent 76cf670 commit 2488ddb

File tree

4 files changed

+36
-116
lines changed

4 files changed

+36
-116
lines changed

rest_framework_jwt/serializers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import jwt
44

55
from django.contrib.auth import authenticate, get_user_model
6-
from rest_framework import serializers, exceptions
6+
from rest_framework import serializers
77

88
from rest_framework_jwt.settings import api_settings
99

@@ -103,7 +103,8 @@ def validate(self, attrs):
103103
# Verify expiration
104104
renewal_limit = api_settings.JWT_TOKEN_RENEWAL_LIMIT
105105
if isinstance(renewal_limit, timedelta):
106-
renewal_limit = renewal_limit.days * 24 * 3600 + renewal_limit.seconds
106+
renewal_limit = (renewal_limit.days * 24 * 3600 +
107+
renewal_limit.seconds)
107108
expiration_timestamp = (
108109
orig_iat +
109110
int(renewal_limit)

rest_framework_jwt/tests/simtime.py

Lines changed: 0 additions & 48 deletions
This file was deleted.

rest_framework_jwt/tests/test_views.py

Lines changed: 32 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
from calendar import timegm
22
from datetime import datetime, timedelta
3+
import time
34

45
from django.test import TestCase
56
from django.conf import settings
67
from django.contrib.auth.models import User
7-
import jwt
8+
89
from rest_framework import status
910
from rest_framework.compat import patterns
1011
from rest_framework.test import APIClient
1112

12-
import rest_framework_jwt.serializers
1313
from rest_framework_jwt import utils
1414
from rest_framework_jwt.runtests.models import CustomUser
1515
from rest_framework_jwt.settings import api_settings, DEFAULTS
16-
from rest_framework_jwt.tests import simtime
17-
from rest_framework_jwt.tests.simtime import SimulationDatetime
1816

1917
urlpatterns = patterns(
2018
'',
@@ -168,36 +166,39 @@ def setUp(self):
168166
super(RefreshJSONWebTokenTests, self).setUp()
169167
api_settings.JWT_ALLOW_TOKEN_RENEWAL = True
170168

171-
# monkey patch datetime objects in places that use datetime.utcnow()
172-
jwt.datetime = SimulationDatetime
173-
rest_framework_jwt.serializers.datetime = SimulationDatetime
174-
utils.datetime = SimulationDatetime
175-
176169
def get_token(self):
177170
client = APIClient(enforce_csrf_checks=True)
178171
response = client.post('/auth-token/', self.data, format='json')
179172
return response.data['token']
180173

174+
def create_token(self, user, exp=None, orig_iat=None):
175+
payload = utils.jwt_payload_handler(self.user)
176+
if exp:
177+
payload['exp'] = exp
178+
179+
if orig_iat:
180+
payload['orig_iat'] = timegm(orig_iat.utctimetuple())
181+
182+
token = utils.jwt_encode_handler(payload)
183+
return token
184+
181185
def test_refresh_jwt(self):
182186
"""
183187
Test getting a refreshed token from original token works
184188
"""
185189
client = APIClient(enforce_csrf_checks=True)
186190

187-
# Set simulation time to now
188-
currtime = datetime.utcnow()
189-
simtime.set_simtime(currtime)
190-
191191
orig_token = self.get_token()
192192
orig_token_decoded = utils.jwt_decode_handler(orig_token)
193193

194-
# Make sure 'orig_iat' exists and is the current time
194+
expected_orig_iat = timegm(datetime.utcnow().utctimetuple())
195+
196+
# Make sure 'orig_iat' exists and is the current time (give some slack)
195197
orig_iat = orig_token_decoded['orig_iat']
196-
self.assertEquals(orig_iat, timegm(currtime.utctimetuple()))
198+
self.assertLessEqual(orig_iat - expected_orig_iat, 1)
197199

198-
# Fast-forward to later time (but before first token expires)
199-
currtime += api_settings.JWT_EXPIRATION_DELTA - timedelta(seconds=30)
200-
simtime.set_simtime(currtime)
200+
# wait a few seconds, so new token will have different exp
201+
time.sleep(2)
201202

202203
# Now try to get a refreshed token
203204
response = client.post('/auth-token-refresh/', {'token': orig_token},
@@ -207,7 +208,7 @@ def test_refresh_jwt(self):
207208
new_token = response.data['token']
208209
new_token_decoded = utils.jwt_decode_handler(new_token)
209210

210-
# Make sure 'orig_iat' on the new token is same as origina
211+
# Make sure 'orig_iat' on the new token is same as original
211212
self.assertEquals(new_token_decoded['orig_iat'], orig_iat)
212213
self.assertGreater(new_token_decoded['exp'], orig_token_decoded['exp'])
213214

@@ -216,14 +217,13 @@ def test_refresh_jwt_fails_with_expired_token(self):
216217
Test that using an expired token to refresh won't work
217218
"""
218219
client = APIClient(enforce_csrf_checks=True)
219-
token = self.get_token()
220220

221-
# Fast-forward to after token expires
222-
after_expire = (
223-
datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA +
224-
timedelta(seconds=10)
221+
# Make an expired token..
222+
token = self.create_token(
223+
self.user,
224+
exp=datetime.utcnow() - timedelta(seconds=5),
225+
orig_iat=datetime.utcnow() - timedelta(hours=1)
225226
)
226-
simtime.set_simtime(after_expire)
227227

228228
response = client.post('/auth-token-refresh/', {'token': token},
229229
format='json')
@@ -235,36 +235,17 @@ def test_refresh_jwt_after_renewal_expiration(self):
235235
"""
236236
Test that token can't be refreshed after token renewal limit
237237
"""
238-
# For simpler test, make the RENEWAL_LIMIT just a bit larger than
239-
# EXPIRATION_DELTA
240-
api_settings.JWT_TOKEN_RENEWAL_LIMIT = (
241-
api_settings.JWT_EXPIRATION_DELTA +
242-
api_settings.JWT_EXPIRATION_DELTA / 2
243-
)
244-
245238
client = APIClient(enforce_csrf_checks=True)
246239

247-
initial_time = datetime.utcnow()
248-
249-
token1 = self.get_token()
250-
251-
# Token1 refresh to Token2, just before it expires
252-
currtime = (initial_time + api_settings.JWT_EXPIRATION_DELTA -
240+
orig_iat = (datetime.utcnow() - api_settings.JWT_TOKEN_RENEWAL_LIMIT -
253241
timedelta(seconds=5))
242+
token = self.create_token(
243+
self.user,
244+
exp=datetime.utcnow() + timedelta(hours=1),
245+
orig_iat=orig_iat
246+
)
254247

255-
simtime.set_simtime(currtime)
256-
257-
response = client.post('/auth-token-refresh/', {'token': token1},
258-
format='json')
259-
token2 = response.data['token']
260-
261-
# Fast-forward to after token renewal expiration
262-
# Token2 hasn't expired yet, but it can't be used to renew anymore!
263-
currtime = (initial_time + api_settings.JWT_TOKEN_RENEWAL_LIMIT +
264-
timedelta(minutes=1))
265-
simtime.set_simtime(currtime)
266-
267-
response = client.post('/auth-token-refresh/', {'token': token2},
248+
response = client.post('/auth-token-refresh/', {'token': token},
268249
format='json')
269250
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
270251
self.assertEqual(response.data['non_field_errors'][0],
@@ -274,13 +255,3 @@ def tearDown(self):
274255
# Restore original settings
275256
api_settings.JWT_ALLOW_TOKEN_RENEWAL = \
276257
DEFAULTS['JWT_ALLOW_TOKEN_RENEWAL']
277-
278-
api_settings.JWT_TOKEN_RENEWAL_LIMIT = \
279-
DEFAULTS['JWT_TOKEN_RENEWAL_LIMIT']
280-
281-
# Undo datetime monkeypatching
282-
jwt.datetime = orig_datetime
283-
rest_framework_jwt.serializers.datetime = orig_datetime
284-
utils.datetime = orig_datetime
285-
286-
simtime.clear_simtime()

rest_framework_jwt/utils.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,11 @@
55

66

77
def jwt_payload_handler(user):
8-
delta_timestamp = (datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA) - datetime(1970,1,1)
9-
# total seconds
10-
exp = delta_timestamp.seconds + delta_timestamp.days * 24 * 3600
11-
128
return {
139
'user_id': user.pk,
1410
'email': user.email,
1511
'username': user.get_username(),
16-
'exp': exp
12+
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
1713
}
1814

1915

0 commit comments

Comments
 (0)