Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion atlassian_jwt_auth/key.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import base64
import logging
import os
import posixpath
import re
from collections.abc import Generator, Iterable
from email.message import EmailMessage
Expand Down Expand Up @@ -43,7 +44,7 @@ def validate_key_identifier(identifier: str) -> str:
raise KeyIdentifierException(_error_msg)
if not regex.match(identifier):
raise KeyIdentifierException(_error_msg)
normalised = os.path.normpath(identifier)
normalised = posixpath.normpath(identifier)
if normalised != identifier:
raise KeyIdentifierException(_error_msg)
if normalised.startswith("/"):
Expand Down
5 changes: 4 additions & 1 deletion atlassian_jwt_auth/signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ def _generate_claims(
"iat": now,
"aud": audience,
"jti": "%s:%s"
% (now.strftime("%s"), random.SystemRandom().getrandbits(32)),
% (
calendar.timegm(now.utctimetuple()),
random.SystemRandom().getrandbits(32),
),
"nbf": now,
"sub": self.subject or self.issuer,
}
Expand Down
15 changes: 15 additions & 0 deletions atlassian_jwt_auth/tests/test_key.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import ntpath
import unittest
from unittest.mock import patch

import atlassian_jwt_auth
from atlassian_jwt_auth import key as key_module


class TestKeyModule(unittest.TestCase):
Expand All @@ -22,6 +25,10 @@ def test_key_identifier_with_invalid_keys(self) -> None:
"a/#a",
"a/a?x",
"a/a;",
"a//b",
"a/./b",
"a/../b",
"a/b/",
]
for key in keys:
with self.assertRaises(ValueError):
Expand All @@ -32,3 +39,11 @@ def test_key_identifier_with_valid_keys(self) -> None:
for key in ["oa.oo/a", "oo.sasdf.asdf/yes", "oo/o"]:
key_id = atlassian_jwt_auth.KeyIdentifier(identifier=key)
self.assertEqual(key_id.key_id, key)

def test_key_identifier_is_independent_of_windows_paths(self) -> None:
with patch.object(key_module, "os") as windows_os:
windows_os.path = ntpath
identifier = "issuer.example/signing-key"
self.assertEqual(
atlassian_jwt_auth.KeyIdentifier(identifier).key_id, identifier
)
17 changes: 15 additions & 2 deletions atlassian_jwt_auth/tests/test_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,21 @@ def test_jti_changes(self):
first = jwt_auth_signer._generate_claims(aud)["jti"]
second = jwt_auth_signer._generate_claims(aud)["jti"]
self.assertNotEqual(first, second)
self.assertTrue(str(expected_now.strftime("%s")) in first)
self.assertTrue(str(expected_now.strftime("%s")) in second)
self.assertTrue(first.startswith("978307200:"))
self.assertTrue(second.startswith("978307200:"))

def test_generate_claims_without_platform_strftime_extensions(self):
class PortableDatetime(datetime.datetime):
def strftime(self, fmt):
if "%s" in fmt:
raise ValueError("Invalid format string")
return super().strftime(fmt)

signer = utils.get_example_jwt_auth_signer(
algorithm=self.algorithm, private_key_pem=self._private_key_pem
)
signer._now = lambda: PortableDatetime(2001, 1, 1, tzinfo=datetime.timezone.utc)
self.assertTrue(signer._generate_claims("aud")["jti"].startswith("978307200:"))

@mock.patch("jwt.encode")
def test_generate_jwt(self, m_jwt_encode):
Expand Down