Skip to content

Commit

Permalink
SPR1-2674 Fix token tests for PyJWT >= 2.2.0
Browse files Browse the repository at this point in the history
In order to avoid a test dependency on the cryptography package, I had
a sneaky way to encode tokens with the "none" algorithm, even though
the header requested "ES256" like a real MeerKAT token. I took the
resultant unsecured JWS and then tacked on a dummy signature of the
expected length of 86 characters, since that is all that matters to
katdal.

Sadly this trick stopped working in PyJWT >= 2.2.0, thanks to
[jpadilla/pyjwt#673](jpadilla/pyjwt#673).
The latest PyJWT prefers the algorithm in the header and won't let
it be overridden by the `algorithm` parameter to `jwt.encode()`.

Instead of inventing more tricks, take the hit and add cryptography to
the test requirements. Use the example private key found in the PyJWT
unit tests. There is no need for the corresponding public key, since
katdal only checks some basic aspects of the token without verifying
the signature.
  • Loading branch information
ludwigschwardt committed Nov 24, 2022
1 parent eb8db22 commit b00f9b3
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 8 deletions.
18 changes: 11 additions & 7 deletions katdal/test/test_chunkstore_s3.py
Expand Up @@ -76,6 +76,14 @@
raise_on_status=False, status_forcelist=_DEFAULT_SERVER_GLITCHES)
SUGGESTED_STATUS_DELAY = 0.1
READ_PAUSE = 0.1
# Dummy private key for ES256 algorithm (taken from PyJWT unit tests)
JWT_PRIVATE_KEY = """
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2nninfu2jMHDwAbn
9oERUhRADS6duQaJEadybLaa0YShRANCAAQfMBxRZKUYEdy5/fLdGI2tYj6kTr50
PZPt8jOD23rAR7dhtNpG1ojqopmH0AH5wEXadgk8nLCT4cAPK59Qp9Ek
-----END PRIVATE KEY-----
"""


@contextlib.contextmanager
Expand Down Expand Up @@ -154,13 +162,9 @@ def testShort(self):
self._truncate_and_fail_to_read(-1, 2)


def encode_jwt(header, payload, signature=86 * 'x'):
"""Generate JWT token with encoded signature (dummy ES256 one by default)."""
# Don't specify algorithm='ES256' here since that needs cryptography package
# This generates an Unsecured JWS without a signature: '<header>.<payload>.'
header_payload = jwt.encode(payload, '', algorithm='none', headers=header)
# Now tack on a signature that nominally matches the header
return header_payload + signature
def encode_jwt(header, payload):
"""Generate JWT token with encoded signature (expects ES256 algorithm)."""
return jwt.encode(payload, JWT_PRIVATE_KEY, headers=header)


class TestTokenUtils:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -61,4 +61,4 @@
's3': [],
's3credentials': ['botocore']
},
tests_require=['nose'])
tests_require=['nose', 'cryptography'])
3 changes: 3 additions & 0 deletions test-requirements.txt
@@ -1,4 +1,7 @@
-c https://raw.githubusercontent.com/ska-sa/katsdpdockerbase/master/docker-base-build/base-requirements.txt

cffi==1.15.1 # via cryptography
coverage
cryptography==38.0.3
nose
pycparser==2.21 # via cffi

0 comments on commit b00f9b3

Please sign in to comment.