From a1a3062a6fa476d3e93a41d234a4b25a54c27780 Mon Sep 17 00:00:00 2001
From: Balthazar Rouberol
Date: Wed, 1 Nov 2023 16:39:59 +0100
Subject: [PATCH 1/2] Resolve deprecation warnings related to datetime.utcnow
in python 3.12
---
jose/jwt.py | 6 +++---
jose/utils.py | 13 +++++++++++++
tests/test_jwt.py | 23 ++++++++++++-----------
3 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/jose/jwt.py b/jose/jwt.py
index b364b4ba..8972711f 100644
--- a/jose/jwt.py
+++ b/jose/jwt.py
@@ -11,7 +11,7 @@
from .constants import ALGORITHMS
from .exceptions import ExpiredSignatureError, JWSError, JWTClaimsError, JWTError
-from .utils import calculate_at_hash, timedelta_total_seconds
+from .utils import calculate_at_hash, timedelta_total_seconds, utcnow
def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None):
@@ -281,7 +281,7 @@ def _validate_nbf(claims, leeway=0):
except ValueError:
raise JWTClaimsError("Not Before claim (nbf) must be an integer.")
- now = timegm(datetime.utcnow().utctimetuple())
+ now = timegm(utcnow().utctimetuple())
if nbf > (now + leeway):
raise JWTClaimsError("The token is not yet valid (nbf)")
@@ -311,7 +311,7 @@ def _validate_exp(claims, leeway=0):
except ValueError:
raise JWTClaimsError("Expiration Time claim (exp) must be an integer.")
- now = timegm(datetime.utcnow().utctimetuple())
+ now = timegm(utcnow().utctimetuple())
if exp < (now - leeway):
raise ExpiredSignatureError("Signature has expired.")
diff --git a/jose/utils.py b/jose/utils.py
index d04c4ac0..e93d49ea 100644
--- a/jose/utils.py
+++ b/jose/utils.py
@@ -1,4 +1,5 @@
import base64
+import datetime
import struct
# Piggyback of the backends implementation of the function that converts a long
@@ -105,3 +106,15 @@ def ensure_binary(s):
if isinstance(s, str):
return s.encode("utf-8", "strict")
raise TypeError(f"not expecting type '{type(s)}'")
+
+
+
+def utcnow():
+ try:
+ from datetime import UTC
+ except ImportError:
+ # datetime.datetime.utcnow was deprecated in favor of
+ # datetime.datetime.now(datetime.UTC) in python 3.12
+ return datetime.datetime.utcnow()
+ else:
+ return datetime.datetime.now(datetime.UTC)
diff --git a/tests/test_jwt.py b/tests/test_jwt.py
index 8c2e262f..9c010cbe 100644
--- a/tests/test_jwt.py
+++ b/tests/test_jwt.py
@@ -6,6 +6,7 @@
from jose import jws, jwt
from jose.exceptions import JWTError
+from jose.utils import utcnow
@pytest.fixture
@@ -180,7 +181,7 @@ def test_leeway_is_int(self):
pass
def test_leeway_is_timedelta(self, claims, key):
- nbf = datetime.utcnow() + timedelta(seconds=5)
+ nbf = utcnow() + timedelta(seconds=5)
leeway = timedelta(seconds=10)
claims = {
@@ -209,7 +210,7 @@ def test_nbf_not_int(self, key):
jwt.decode(token, key)
def test_nbf_datetime(self, key):
- nbf = datetime.utcnow() - timedelta(seconds=5)
+ nbf = utcnow() - timedelta(seconds=5)
claims = {"nbf": nbf}
@@ -217,7 +218,7 @@ def test_nbf_datetime(self, key):
jwt.decode(token, key)
def test_nbf_with_leeway(self, key):
- nbf = datetime.utcnow() + timedelta(seconds=5)
+ nbf = utcnow() + timedelta(seconds=5)
claims = {
"nbf": nbf,
@@ -229,7 +230,7 @@ def test_nbf_with_leeway(self, key):
jwt.decode(token, key, options=options)
def test_nbf_in_future(self, key):
- nbf = datetime.utcnow() + timedelta(seconds=5)
+ nbf = utcnow() + timedelta(seconds=5)
claims = {"nbf": nbf}
@@ -239,7 +240,7 @@ def test_nbf_in_future(self, key):
jwt.decode(token, key)
def test_nbf_skip(self, key):
- nbf = datetime.utcnow() + timedelta(seconds=5)
+ nbf = utcnow() + timedelta(seconds=5)
claims = {"nbf": nbf}
@@ -261,7 +262,7 @@ def test_exp_not_int(self, key):
jwt.decode(token, key)
def test_exp_datetime(self, key):
- exp = datetime.utcnow() + timedelta(seconds=5)
+ exp = utcnow() + timedelta(seconds=5)
claims = {"exp": exp}
@@ -269,7 +270,7 @@ def test_exp_datetime(self, key):
jwt.decode(token, key)
def test_exp_with_leeway(self, key):
- exp = datetime.utcnow() - timedelta(seconds=5)
+ exp = utcnow() - timedelta(seconds=5)
claims = {
"exp": exp,
@@ -281,7 +282,7 @@ def test_exp_with_leeway(self, key):
jwt.decode(token, key, options=options)
def test_exp_in_past(self, key):
- exp = datetime.utcnow() - timedelta(seconds=5)
+ exp = utcnow() - timedelta(seconds=5)
claims = {"exp": exp}
@@ -291,7 +292,7 @@ def test_exp_in_past(self, key):
jwt.decode(token, key)
def test_exp_skip(self, key):
- exp = datetime.utcnow() - timedelta(seconds=5)
+ exp = utcnow() - timedelta(seconds=5)
claims = {"exp": exp}
@@ -504,8 +505,8 @@ def test_unverified_claims_object(self, claims, key):
[
("aud", "aud"),
("ait", "ait"),
- ("exp", datetime.utcnow() + timedelta(seconds=3600)),
- ("nbf", datetime.utcnow() - timedelta(seconds=5)),
+ ("exp", utcnow() + timedelta(seconds=3600)),
+ ("nbf", utcnow() - timedelta(seconds=5)),
("iss", "iss"),
("sub", "sub"),
("jti", "jti"),
From f29f15080f9fee453a559f1b9d18dbff8715dc66 Mon Sep 17 00:00:00 2001
From: Balthazar Rouberol
Date: Wed, 27 Dec 2023 13:43:58 +0100
Subject: [PATCH 2/2] Apply suggestions from code review
Co-authored-by: Aliaksei Urbanski
---
jose/utils.py | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/jose/utils.py b/jose/utils.py
index e93d49ea..03f96f6b 100644
--- a/jose/utils.py
+++ b/jose/utils.py
@@ -1,6 +1,6 @@
import base64
-import datetime
import struct
+from datetime import datetime, timezone
# Piggyback of the backends implementation of the function that converts a long
# to a bytes stream. Some plumbing is necessary to have the signatures match.
@@ -108,13 +108,6 @@ def ensure_binary(s):
raise TypeError(f"not expecting type '{type(s)}'")
-
def utcnow():
- try:
- from datetime import UTC
- except ImportError:
- # datetime.datetime.utcnow was deprecated in favor of
- # datetime.datetime.now(datetime.UTC) in python 3.12
- return datetime.datetime.utcnow()
- else:
- return datetime.datetime.now(datetime.UTC)
+ # datetime.utcnow() is deprecated since Python 3.12
+ return datetime.now(timezone.utc)