From 6761ac6d8af5fbf2a22574da228c5d62ddbcdf94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 28 May 2024 14:33:02 +0200 Subject: [PATCH 1/6] Use PyJWT instead of python-jose --- intuitlib/utils.py | 11 ++++------- requirements.txt | 2 +- setup.py | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 68dddac..7080d98 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -20,11 +20,10 @@ from datetime import datetime import random import string -from jose import jwk import requests from requests.sessions import Session import six -from requests_oauthlib import OAuth1 +from jwt import PyJWKSet from intuitlib.enums import Scopes @@ -165,9 +164,8 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): return False message = id_token_parts[0] + '.' + id_token_parts[1] - keys_dict = get_jwk(id_token_header['kid'], jwk_uri) + public_key = get_jwk(id_token_header['kid'], jwk_uri) - public_key = jwk.construct(keys_dict) is_signature_valid = public_key.verify(message.encode('utf-8'), id_token_signature) return is_signature_valid @@ -178,15 +176,14 @@ def get_jwk(kid, jwk_uri): :param jwk_uri: JWK URI :raises HTTPError: if response status != 200 - :return: dict containing keys + :return: Algorithm with the key loaded. """ response = requests.get(jwk_uri) if response.status_code != 200: raise AuthClientError(response) data = response.json() - keys = next(key for key in data["keys"] if key['kid'] == kid) - return keys + return PyJWKSet.from_dict(data)[kid] def _correct_padding(val): """Correct padding for JWT diff --git a/requirements.txt b/requirements.txt index e0f41ba..a5c2d2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -python_jose>=2.0.2 requests>=2.13.0 mock>=2.0.0 requests_oauthlib>=1.0.0 @@ -8,3 +7,4 @@ pytest>=3.8.0 pytest-cov==2.5.0 six>=1.10.0 enum-compat +pyjwt diff --git a/setup.py b/setup.py index 8d030be..19b0451 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ packages=find_packages(exclude=('tests*',)), namespace_packages=('intuitlib',), install_requires=[ - 'python_jose>=2.0.2', + 'pyjwt', 'requests>=2.13.0', 'requests_oauthlib>=1.0.0', 'six>=1.10.0', From 7f46c32b118047a01a7ad9bac43553295e9d2a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 9 Jul 2024 17:50:20 +0200 Subject: [PATCH 2/6] Add PyJWT minimum supported version --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index a5c2d2c..809712d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ pytest>=3.8.0 pytest-cov==2.5.0 six>=1.10.0 enum-compat -pyjwt +pyjwt>=2.0.0 diff --git a/setup.py b/setup.py index 19b0451..9595906 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ packages=find_packages(exclude=('tests*',)), namespace_packages=('intuitlib',), install_requires=[ - 'pyjwt', + 'pyjwt>=2.0.0', 'requests>=2.13.0', 'requests_oauthlib>=1.0.0', 'six>=1.10.0', From 703c3e8b4c723f29853e53df64bde72469ec145f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 9 Jul 2024 19:26:21 +0200 Subject: [PATCH 3/6] Add the Cryptography related algorithms --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 809712d..1e1db9d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ pytest>=3.8.0 pytest-cov==2.5.0 six>=1.10.0 enum-compat -pyjwt>=2.0.0 +pyjwt[crypto]>=2.0.0 diff --git a/setup.py b/setup.py index 9595906..b40522c 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ packages=find_packages(exclude=('tests*',)), namespace_packages=('intuitlib',), install_requires=[ - 'pyjwt>=2.0.0', + 'pyjwt[crypto]>=2.0.0', 'requests>=2.13.0', 'requests_oauthlib>=1.0.0', 'six>=1.10.0', From 96e4f37df79921964e83bbeaa55a6553e8e1ab33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sun, 21 Jul 2024 09:20:51 +0200 Subject: [PATCH 4/6] Update intuitlib/utils.py --- intuitlib/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 7080d98..af35143 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -164,7 +164,7 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): return False message = id_token_parts[0] + '.' + id_token_parts[1] - public_key = get_jwk(id_token_header['kid'], jwk_uri) + public_key = get_jwk(id_token_header['kid'], jwk_uri).key is_signature_valid = public_key.verify(message.encode('utf-8'), id_token_signature) return is_signature_valid From b67444fa0a341d42d42a9d1bf951289a6535a1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sun, 28 Jul 2024 19:25:23 +0200 Subject: [PATCH 5/6] Use jwt.decode public API --- intuitlib/utils.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index af35143..04e4c43 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -16,19 +16,19 @@ """ import json -from base64 import b64encode, b64decode, urlsafe_b64decode -from datetime import datetime import random -import string import requests -from requests.sessions import Session import six -from jwt import PyJWKSet - +import string +from base64 import b64encode, b64decode, urlsafe_b64decode +from datetime import datetime +from jwt import PyJWKSet, PyJWTError +from requests.sessions import Session +from intuitlib.config import DISCOVERY_URL, ACCEPT_HEADER from intuitlib.enums import Scopes from intuitlib.exceptions import AuthClientError -from intuitlib.config import DISCOVERY_URL, ACCEPT_HEADER + def get_discovery_doc(environment, session=None): """Gets discovery doc based on environment specified. @@ -165,9 +165,11 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): message = id_token_parts[0] + '.' + id_token_parts[1] public_key = get_jwk(id_token_header['kid'], jwk_uri).key - - is_signature_valid = public_key.verify(message.encode('utf-8'), id_token_signature) - return is_signature_valid + try: + jwt.decode(id_token, public_key, audience=client_id, algorithms=['RS256']) + return True + except PyJWTError: + return False def get_jwk(kid, jwk_uri): """Get JWK for public key information From 9cb5d8728dcab9184f3134b10fe8d17510a62457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 30 Jul 2024 07:00:55 +0200 Subject: [PATCH 6/6] Fix QA returns --- intuitlib/utils.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 04e4c43..4a9e34a 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -16,13 +16,13 @@ """ import json +import jwt import random import requests import six import string from base64 import b64encode, b64decode, urlsafe_b64decode from datetime import datetime -from jwt import PyJWKSet, PyJWTError from requests.sessions import Session from intuitlib.config import DISCOVERY_URL, ACCEPT_HEADER @@ -152,7 +152,6 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): id_token_header = json.loads(b64decode(_correct_padding(id_token_parts[0])).decode('ascii')) id_token_payload = json.loads(b64decode(_correct_padding(id_token_parts[1])).decode('ascii')) - id_token_signature = urlsafe_b64decode(((_correct_padding(id_token_parts[2])).encode('ascii'))) if id_token_payload['iss'] != intuit_issuer: return False @@ -163,12 +162,11 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): if id_token_payload['exp'] < current_time: return False - message = id_token_parts[0] + '.' + id_token_parts[1] public_key = get_jwk(id_token_header['kid'], jwk_uri).key try: jwt.decode(id_token, public_key, audience=client_id, algorithms=['RS256']) return True - except PyJWTError: + except jwt.PyJWTError: return False def get_jwk(kid, jwk_uri): @@ -185,7 +183,7 @@ def get_jwk(kid, jwk_uri): if response.status_code != 200: raise AuthClientError(response) data = response.json() - return PyJWKSet.from_dict(data)[kid] + return jwt.PyJWKSet.from_dict(data)[kid] def _correct_padding(val): """Correct padding for JWT