11"""Basic JSON Web Token implementation."""
22import json
33import logging
4+ import time
45import uuid
5- from datetime import datetime
6- from datetime import timezone
76from json import JSONDecodeError
87
98from .exception import HeaderError
@@ -28,9 +27,7 @@ def utc_time_sans_frac():
2827
2928 :return: A number of seconds
3029 """
31-
32- now_timestampt = int (datetime .now (timezone .utc ).timestamp ())
33- return now_timestampt
30+ return int (time .time ())
3431
3532
3633def pick_key (keys , use , alg = "" , key_type = "" , kid = "" ):
@@ -95,6 +92,7 @@ def __init__(
9592 allowed_sign_algs = None ,
9693 allowed_enc_algs = None ,
9794 allowed_enc_encs = None ,
95+ allowed_max_lifetime = None ,
9896 zip = "" ,
9997 ):
10098 self .key_jar = key_jar # KeyJar instance
@@ -115,6 +113,7 @@ def __init__(
115113 self .allowed_sign_algs = allowed_sign_algs
116114 self .allowed_enc_algs = allowed_enc_algs
117115 self .allowed_enc_encs = allowed_enc_encs
116+ self .allowed_max_lifetime = allowed_max_lifetime
118117 self .zip = zip
119118
120119 def receiver_keys (self , recv , use ):
@@ -176,13 +175,13 @@ def put_together_aud(recv, aud=None):
176175
177176 return _aud
178177
179- def pack_init (self , recv , aud ):
178+ def pack_init (self , recv , aud , iat = None ):
180179 """
181180 Gather initial information for the payload.
182181
183182 :return: A dictionary with claims and values
184183 """
185- argv = {"iss" : self .iss , "iat" : utc_time_sans_frac ()}
184+ argv = {"iss" : self .iss , "iat" : iat or utc_time_sans_frac ()}
186185 if self .lifetime :
187186 argv ["exp" ] = argv ["iat" ] + self .lifetime
188187
@@ -207,7 +206,7 @@ def pack_key(self, issuer_id="", kid=""):
207206
208207 return keys [0 ] # Might be more then one if kid == ''
209208
210- def pack (self , payload = None , kid = "" , issuer_id = "" , recv = "" , aud = None , ** kwargs ):
209+ def pack (self , payload = None , kid = "" , issuer_id = "" , recv = "" , aud = None , iat = None , ** kwargs ):
211210 """
212211
213212 :param payload: Information to be carried as payload in the JWT
@@ -216,13 +215,14 @@ def pack(self, payload=None, kid="", issuer_id="", recv="", aud=None, **kwargs):
216215 :param recv: The intended immediate receiver
217216 :param aud: Intended audience for this JWS/JWE, not expected to
218217 contain the recipient.
218+ :param iat: Override issued at (default current timestamp)
219219 :param kwargs: Extra keyword arguments
220220 :return: A signed or signed and encrypted Json Web Token
221221 """
222222 _args = {}
223223 if payload is not None :
224224 _args .update (payload )
225- _args .update (self .pack_init (recv , aud ))
225+ _args .update (self .pack_init (recv , aud , iat ))
226226
227227 try :
228228 _encrypt = kwargs ["encrypt" ]
@@ -304,11 +304,12 @@ def verify_profile(msg_cls, info, **kwargs):
304304 raise VerificationError ()
305305 return _msg
306306
307- def unpack (self , token ):
307+ def unpack (self , token , timestamp = None ):
308308 """
309309 Unpack a received signed or signed and encrypted Json Web Token
310310
311311 :param token: The Json Web Token
312+ :param timestamp: Time for evaluation (default now)
312313 :return: If decryption and signature verification work the payload
313314 will be returned as a Message instance if possible.
314315 """
@@ -378,6 +379,26 @@ def unpack(self, token):
378379 except KeyError :
379380 _msg_cls = None
380381
382+ timestamp = timestamp or utc_time_sans_frac ()
383+
384+ if "nbf" in _info :
385+ nbf = int (_info ["nbf" ])
386+ if timestamp < nbf - self .skew :
387+ raise VerificationError ("Token not yet valid" )
388+
389+ if "exp" in _info :
390+ exp = int (_info ["exp" ])
391+ if timestamp >= exp + self .skew :
392+ raise VerificationError ("Token expired" )
393+ else :
394+ exp = None
395+
396+ if "iat" in _info :
397+ iat = int (_info ["iat" ])
398+ if self .allowed_max_lifetime and exp :
399+ if abs (exp - iat ) > self .allowed_max_lifetime :
400+ raise VerificationError ("Token lifetime exceeded" )
401+
381402 if _msg_cls :
382403 vp_args = {"skew" : self .skew }
383404 if self .iss :
0 commit comments