From 975eb0163fce63d47f4556accc4f0e6ba79b9811 Mon Sep 17 00:00:00 2001 From: Brice Gelineau Date: Wed, 30 Nov 2016 15:22:58 +0100 Subject: [PATCH] Fix timestamps computing in tokens The timestamp of timezone-aware datetimes was offset by the value of their timezone. --- oidc_provider/lib/utils/common.py | 20 ++++++++++++++++++++ oidc_provider/lib/utils/token.py | 9 ++++----- oidc_provider/tests/test_utils.py | 18 ++++++++++++++++-- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/oidc_provider/lib/utils/common.py b/oidc_provider/lib/utils/common.py index b7a6676..16673de 100644 --- a/oidc_provider/lib/utils/common.py +++ b/oidc_provider/lib/utils/common.py @@ -1,5 +1,9 @@ +import datetime +import time + from django.core.urlresolvers import reverse from django.http import HttpResponse +from django.utils import timezone from oidc_provider import settings @@ -98,3 +102,19 @@ def default_idtoken_processing_hook(id_token, user): :rtype dict """ return id_token + +def to_timestamp(dt): + """ + Convert a datetime to an integer timestamp. + + Inspired from Py3 code, can be replaced by ``int(dt.timestamp())`` + when Py2 is not supported anymore. + + Note: we assume the timezone of naive datetimes is the one of the + system, not settings.TIME_ZONE as this setting may not have been + set by the user. + """ + if timezone.is_aware(dt): + return int((dt - datetime.datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()) + else: + return int(time.mktime(dt.timetuple())) diff --git a/oidc_provider/lib/utils/token.py b/oidc_provider/lib/utils/token.py index 7c06c00..df3befa 100644 --- a/oidc_provider/lib/utils/token.py +++ b/oidc_provider/lib/utils/token.py @@ -1,5 +1,4 @@ from datetime import timedelta -import time import uuid from Cryptodome.PublicKey.RSA import importKey @@ -9,7 +8,7 @@ from jwkest.jwk import SYMKey from jwkest.jws import JWS from jwkest.jwt import JWT -from oidc_provider.lib.utils.common import get_issuer +from oidc_provider.lib.utils.common import get_issuer, to_timestamp from oidc_provider.models import ( Code, RSAKey, @@ -30,10 +29,10 @@ def create_id_token(user, aud, nonce='', at_hash='', request=None, scope=[]): # Convert datetimes into timestamps. now = timezone.now() - iat_time = int(time.mktime(now.timetuple())) - exp_time = int(time.mktime((now + timedelta(seconds=expires_in)).timetuple())) + iat_time = to_timestamp(now) + exp_time = to_timestamp(now + timedelta(seconds=expires_in)) user_auth_time = user.last_login or user.date_joined - auth_time = int(time.mktime(user_auth_time.timetuple())) + auth_time = to_timestamp(user_auth_time) dic = { 'iss': get_issuer(request=request), diff --git a/oidc_provider/tests/test_utils.py b/oidc_provider/tests/test_utils.py index 32bdf8d..dea523a 100644 --- a/oidc_provider/tests/test_utils.py +++ b/oidc_provider/tests/test_utils.py @@ -1,6 +1,10 @@ -from django.test import TestCase +import datetime -from oidc_provider.lib.utils.common import get_issuer +from django.test import TestCase +from django.utils import timezone +from django.utils import six + +from oidc_provider.lib.utils.common import get_issuer, to_timestamp class Request(object): @@ -42,3 +46,13 @@ class CommonTest(TestCase): self.assertEqual(get_issuer(site_url='http://127.0.0.1:9000', request=request), 'http://127.0.0.1:9000/openid') + + def test_to_timestamp(self): + if not six.PY2: + naive_dt = datetime.datetime.now() + self.assertEqual(to_timestamp(naive_dt), int(naive_dt.timestamp())) + + aware_dt = datetime.datetime(2016, 3, 2, 14, 2, 6, 123, timezone.utc) + self.assertEqual(to_timestamp(aware_dt), 1456927326) + if not six.PY2: + self.assertEqual(to_timestamp(aware_dt), int(aware_dt.timestamp()))