From 82cef7dbd3dda3c898985c56f33c58a089de26e8 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Mon, 21 Oct 2024 16:41:33 -0400 Subject: [PATCH 1/9] Nonce stuff added. Signed-off-by: Cliff Hill --- app/main/views/register.py | 10 ++++++ app/main/views/sign_in.py | 42 +++++--------------------- app/notify_client/invite_api_client.py | 17 +++++++++++ app/utils/login.py | 35 ++++++++++++++++++++- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/app/main/views/register.py b/app/main/views/register.py index 19187a47c..a8de8d1e8 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -26,6 +26,7 @@ from app.main.views import sign_in from app.main.views.verify import activate_user from app.models.user import InvitedOrgUser, InvitedUser, User from app.utils import hide_from_search_engines, hilite +from app.utils.login import get_id_token from app.utils.user import is_gov_user @@ -165,6 +166,15 @@ def set_up_your_profile(): if redis_client.get(f"invitedata-{state}") is None: access_token = sign_in._get_access_token(code, state) + + request_json = request.json() + id_token = get_id_token(request_json) + nonce = id_token["nonce"] + stored_nonce = redis_client.get(f"invitenonce-{state}") + if nonce != stored_nonce: + current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") + abort(403) + debug_msg("Got the access token for login.gov") user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token) debug_msg( diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index a4026b485..700b01a02 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -1,4 +1,3 @@ -# import json import os import secrets import time @@ -25,7 +24,7 @@ from app.main.views.index import error from app.main.views.verify import activate_user from app.models.user import User from app.utils import hide_from_search_engines -from app.utils.login import is_safe_redirect_url +from app.utils.login import get_id_token, is_safe_redirect_url from app.utils.time import is_less_than_days_ago from app.utils.user import is_gov_user from notifications_utils.url_safe_token import generate_token @@ -43,7 +42,6 @@ def _reformat_keystring(orig): # pragma: no cover def _get_access_token(code, state): # pragma: no cover client_id = os.getenv("LOGIN_DOT_GOV_CLIENT_ID") access_token_url = os.getenv("LOGIN_DOT_GOV_ACCESS_TOKEN_URL") - # certs_url = os.getenv("LOGIN_DOT_GOV_CERTS_URL") keystring = os.getenv("LOGIN_PEM") if " " in keystring: keystring = _reformat_keystring(keystring) @@ -66,38 +64,12 @@ def _get_access_token(code, state): # pragma: no cover response = requests.post(url, headers=headers) response_json = response.json() - - # TODO nonce check intermittently fails, investifix - # Presumably the nonce is not yet in the session when there - # is an invite involved? - - # try: - # encoded_id_token = response_json["id_token"] - # except KeyError as e: - # current_app.logger.exception(f"Error when getting id token {response_json}") - # raise KeyError(f"'access_token' {response.json()}") from e - - # Getting Login.gov signing keys for unpacking the id_token correctly. - # jwks = requests.get(certs_url).json() - # public_keys = { - # jwk["kid"]: { - # "key": jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk)), - # "algo": jwk["alg"], - # } - # for jwk in jwks["keys"] - # } - # kid = jwt.get_unverified_header(encoded_id_token)["kid"] - # pub_key = public_keys[kid]["key"] - # algo = public_keys[kid]["algo"] - # id_token = jwt.decode( - # encoded_id_token, pub_key, audience=client_id, algorithms=[algo] - # ) - # nonce = id_token["nonce"] - - # saved_nonce = session.pop("nonce") - # if nonce != saved_nonce: - # current_app.logger.error(f"Nonce Error: {nonce} != {saved_nonce}") - # abort(403) + id_token = get_id_token(response_json) + nonce = id_token["nonce"] + stored_nonce = session.pop("nonce") + if nonce != stored_nonce: + current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") + abort(403) try: access_token = response_json["access_token"] diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index d410ceec5..25a69967b 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -1,3 +1,8 @@ +import base64 +import json +import secrets + +from app import redis_client from app.notify_client import NotifyAdminAPIClient, _attach_current_user, cache from app.utils.user_permissions import ( all_ui_permissions, @@ -32,6 +37,18 @@ class InviteApiClient(NotifyAdminAPIClient): "folder_permissions": folder_permissions, } data = _attach_current_user(data) + + # make the state variable to properly store the nonce. + # this matches the api code in app.service_invite.rest.get_user_data_url_safe() + state_data = json.dumps(data) + state_data = base64.b64encode(state_data.encode("utf8")) + state = state_data.decode("utf8") + + # make and store the nonce + nonce = secrets.token_urlsafe() + redis_client.set(f"invitenonce-{state}", nonce) # save the nonce to redis. + data["nonce"] = nonce # This is passed to api for the invite url. + resp = self.post(url=f"/service/{service_id}/invite", data=data) return resp["data"] diff --git a/app/utils/login.py b/app/utils/login.py index 2d060ac86..2c3dec108 100644 --- a/app/utils/login.py +++ b/app/utils/login.py @@ -1,6 +1,10 @@ +import json +import os from functools import wraps -from flask import redirect, request, session, url_for +import jwt +import requests +from flask import current_app, redirect, request, session, url_for from app.models.user import User from app.utils.time import is_less_than_days_ago @@ -57,3 +61,32 @@ def is_safe_redirect_url(target): redirect_url.scheme in ("http", "https") and host_url.netloc == redirect_url.netloc ) + + +def get_id_token(json_data): + """Decode and return the id_token.""" + client_id = os.getenv("LOGIN_DOT_GOV_CLIENT_ID") + certs_url = os.getenv("LOGIN_DOT_GOV_CERTS_URL") + + try: + encoded_id_token = json_data["id_token"] + except KeyError as e: + current_app.logger.exception(f"Error when getting id token {json_data}") + raise KeyError(f"'access_token' {request.json()}") from e + + # Getting Login.gov signing keys for unpacking the id_token correctly. + jwks = requests.get(certs_url, timeout=5).json() + public_keys = { + jwk["kid"]: { + "key": jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk)), + "algo": jwk["alg"], + } + for jwk in jwks["keys"] + } + kid = jwt.get_unverified_header(encoded_id_token)["kid"] + pub_key = public_keys[kid]["key"] + algo = public_keys[kid]["algo"] + id_token = jwt.decode( + encoded_id_token, pub_key, audience=client_id, algorithms=[algo] + ) + return id_token From d0cda995cf23bef9153c6224490b70f38995de6d Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Tue, 15 Oct 2024 09:27:34 -0400 Subject: [PATCH 2/9] Standardising nonce storage/retrieval through redis for both login and invite. Signed-off-by: Cliff Hill --- app/main/views/index.py | 6 +++--- app/main/views/register.py | 2 +- app/main/views/sign_in.py | 8 ++++---- app/notify_client/invite_api_client.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/main/views/index.py b/app/main/views/index.py index 012383f84..6dd528e9a 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -7,12 +7,11 @@ from flask import ( redirect, render_template, request, - session, url_for, ) from flask_login import current_user -from app import status_api_client +from app import status_api_client, redis_client from app.formatters import apply_html_class, convert_markdown_template from app.main import main from app.main.views.pricing import CURRENT_SMS_RATE @@ -34,7 +33,8 @@ def index(): # handle unit tests nonce = secrets.token_urlsafe() - session["nonce"] = nonce + + redis_client.set(f"login-nonce-{token}", nonce) if url is not None: url = url.replace("NONCE", nonce) diff --git a/app/main/views/register.py b/app/main/views/register.py index a8de8d1e8..5b69a7f84 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -170,7 +170,7 @@ def set_up_your_profile(): request_json = request.json() id_token = get_id_token(request_json) nonce = id_token["nonce"] - stored_nonce = redis_client.get(f"invitenonce-{state}") + stored_nonce = redis_client.get(f"login-nonce-{state}") if nonce != stored_nonce: current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") abort(403) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 700b01a02..a2dc36a2a 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -13,12 +13,11 @@ from flask import ( redirect, render_template, request, - session, url_for, ) from flask_login import current_user -from app import login_manager, user_api_client +from app import login_manager, user_api_client, redis_client from app.main import main from app.main.views.index import error from app.main.views.verify import activate_user @@ -66,7 +65,8 @@ def _get_access_token(code, state): # pragma: no cover response_json = response.json() id_token = get_id_token(response_json) nonce = id_token["nonce"] - stored_nonce = session.pop("nonce") + stored_nonce = redis_client.get(f"login-nonce-{state}") + if nonce != stored_nonce: current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") abort(403) @@ -209,7 +209,7 @@ def sign_in(): # pragma: no cover url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") nonce = secrets.token_urlsafe() - session["nonce"] = nonce + redis_client.set(f"login-nonce-{token}", nonce) # handle unit tests if url is not None: diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 25a69967b..9bff63f22 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -46,7 +46,7 @@ class InviteApiClient(NotifyAdminAPIClient): # make and store the nonce nonce = secrets.token_urlsafe() - redis_client.set(f"invitenonce-{state}", nonce) # save the nonce to redis. + redis_client.set(f"login-nonce-{state}", nonce) # save the nonce to redis. data["nonce"] = nonce # This is passed to api for the invite url. resp = self.post(url=f"/service/{service_id}/invite", data=data) From da6882774beeafb0b98c1b5b71aae23801329597 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Tue, 15 Oct 2024 10:44:03 -0400 Subject: [PATCH 3/9] Getting the redis stuff configured correctly. Signed-off-by: Cliff Hill --- app/main/views/index.py | 15 +++++---------- app/main/views/register.py | 2 +- app/main/views/sign_in.py | 12 +++++++++--- app/notify_client/invite_api_client.py | 3 ++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/app/main/views/index.py b/app/main/views/index.py index 6dd528e9a..e7226ad7d 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -1,17 +1,11 @@ import os import secrets +from urllib.parse import unquote -from flask import ( - abort, - current_app, - redirect, - render_template, - request, - url_for, -) +from flask import abort, current_app, redirect, render_template, request, url_for from flask_login import current_user -from app import status_api_client, redis_client +from app import redis_client, status_api_client from app.formatters import apply_html_class, convert_markdown_template from app.main import main from app.main.views.pricing import CURRENT_SMS_RATE @@ -34,7 +28,8 @@ def index(): nonce = secrets.token_urlsafe() - redis_client.set(f"login-nonce-{token}", nonce) + redis_key = f"login-nonce-{unquote(token)}" + redis_client.set(redis_key, nonce) if url is not None: url = url.replace("NONCE", nonce) diff --git a/app/main/views/register.py b/app/main/views/register.py index 5b69a7f84..475fa4578 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -170,7 +170,7 @@ def set_up_your_profile(): request_json = request.json() id_token = get_id_token(request_json) nonce = id_token["nonce"] - stored_nonce = redis_client.get(f"login-nonce-{state}") + stored_nonce = redis_client.get(f"login-nonce-{state}").decode("utf8") if nonce != stored_nonce: current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") abort(403) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index a2dc36a2a..8cbc16aff 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -2,6 +2,7 @@ import os import secrets import time import uuid +from urllib.parse import unquote import jwt import requests @@ -17,7 +18,7 @@ from flask import ( ) from flask_login import current_user -from app import login_manager, user_api_client, redis_client +from app import login_manager, redis_client, user_api_client from app.main import main from app.main.views.index import error from app.main.views.verify import activate_user @@ -65,7 +66,11 @@ def _get_access_token(code, state): # pragma: no cover response_json = response.json() id_token = get_id_token(response_json) nonce = id_token["nonce"] - stored_nonce = redis_client.get(f"login-nonce-{state}") + redis_key = f"login-nonce-{state}" + stored_nonce = redis_client.get(redis_key).decode("utf8") + + # 'login-nonce-IjEyNy4wLjAuMSI%2EZw51tw%2EWIkNwqJKjDsd_mAGc2Jgh39KnS4' + # 'login-nonce-IjEyNy4wLjAuMSI.Zw51tw.WIkNwqJKjDsd_mAGc2Jgh39KnS4' if nonce != stored_nonce: current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") @@ -209,7 +214,8 @@ def sign_in(): # pragma: no cover url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") nonce = secrets.token_urlsafe() - redis_client.set(f"login-nonce-{token}", nonce) + redis_key = f"login-nonce-{unquote(token)}" + redis_client.set(redis_key, nonce) # handle unit tests if url is not None: diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 9bff63f22..328a87e58 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -46,7 +46,8 @@ class InviteApiClient(NotifyAdminAPIClient): # make and store the nonce nonce = secrets.token_urlsafe() - redis_client.set(f"login-nonce-{state}", nonce) # save the nonce to redis. + redis_key = f"login-nonce-{state}" + redis_client.set(f"{redis_key}", nonce) # save the nonce to redis. data["nonce"] = nonce # This is passed to api for the invite url. resp = self.post(url=f"/service/{service_id}/invite", data=data) From 8c405383344da8263147e525d2a721cfdc73f473 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Tue, 15 Oct 2024 16:52:29 -0400 Subject: [PATCH 4/9] Nonce is working now for invites. Signed-off-by: Cliff Hill --- app/main/views/index.py | 5 ++++- app/main/views/register.py | 9 +-------- app/main/views/sign_in.py | 8 +++----- app/notify_client/invite_api_client.py | 5 ++++- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/app/main/views/index.py b/app/main/views/index.py index e7226ad7d..4b0b57783 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -18,6 +18,7 @@ from notifications_utils.url_safe_token import generate_token def index(): if current_user and current_user.is_authenticated: return redirect(url_for("main.choose_account")) + token = generate_token( str(request.remote_addr), current_app.config["SECRET_KEY"], @@ -26,9 +27,11 @@ def index(): url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") # handle unit tests + current_app.logger.warning(f"############### {str(request.remote_addr)}") + nonce = secrets.token_urlsafe() - redis_key = f"login-nonce-{unquote(token)}" + redis_key = f"login-nonce-{unquote(nonce)}" redis_client.set(redis_key, nonce) if url is not None: diff --git a/app/main/views/register.py b/app/main/views/register.py index 475fa4578..3222944fd 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -1,5 +1,6 @@ import base64 import json +from urllib.parse import unquote import uuid from datetime import datetime, timedelta @@ -167,14 +168,6 @@ def set_up_your_profile(): if redis_client.get(f"invitedata-{state}") is None: access_token = sign_in._get_access_token(code, state) - request_json = request.json() - id_token = get_id_token(request_json) - nonce = id_token["nonce"] - stored_nonce = redis_client.get(f"login-nonce-{state}").decode("utf8") - if nonce != stored_nonce: - current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") - abort(403) - debug_msg("Got the access token for login.gov") user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token) debug_msg( diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 8cbc16aff..dc08a93cc 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -66,12 +66,9 @@ def _get_access_token(code, state): # pragma: no cover response_json = response.json() id_token = get_id_token(response_json) nonce = id_token["nonce"] - redis_key = f"login-nonce-{state}" + redis_key = f"login-nonce-{unquote(nonce)}" stored_nonce = redis_client.get(redis_key).decode("utf8") - # 'login-nonce-IjEyNy4wLjAuMSI%2EZw51tw%2EWIkNwqJKjDsd_mAGc2Jgh39KnS4' - # 'login-nonce-IjEyNy4wLjAuMSI.Zw51tw.WIkNwqJKjDsd_mAGc2Jgh39KnS4' - if nonce != stored_nonce: current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}") abort(403) @@ -214,7 +211,8 @@ def sign_in(): # pragma: no cover url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") nonce = secrets.token_urlsafe() - redis_key = f"login-nonce-{unquote(token)}" + redis_key = f"-{unquote(nonce)}" + current_app.logger.info(f"<<<<<<<<<<<<<<<<<<<<<<<< redis key: {redis_key}") redis_client.set(redis_key, nonce) # handle unit tests diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 328a87e58..8e063f777 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -1,6 +1,9 @@ import base64 import json import secrets +from urllib.parse import unquote + +from flask import current_app, request from app import redis_client from app.notify_client import NotifyAdminAPIClient, _attach_current_user, cache @@ -46,7 +49,7 @@ class InviteApiClient(NotifyAdminAPIClient): # make and store the nonce nonce = secrets.token_urlsafe() - redis_key = f"login-nonce-{state}" + redis_key = f"login-nonce-{unquote(nonce)}" redis_client.set(f"{redis_key}", nonce) # save the nonce to redis. data["nonce"] = nonce # This is passed to api for the invite url. From 7275dac6a09501c3f51399084f6e6a5d9611d40d Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Tue, 15 Oct 2024 16:55:25 -0400 Subject: [PATCH 5/9] black, isort, and flake8. Signed-off-by: Cliff Hill --- app/main/views/register.py | 2 -- app/notify_client/invite_api_client.py | 8 -------- 2 files changed, 10 deletions(-) diff --git a/app/main/views/register.py b/app/main/views/register.py index 3222944fd..cc6850055 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -1,6 +1,5 @@ import base64 import json -from urllib.parse import unquote import uuid from datetime import datetime, timedelta @@ -27,7 +26,6 @@ from app.main.views import sign_in from app.main.views.verify import activate_user from app.models.user import InvitedOrgUser, InvitedUser, User from app.utils import hide_from_search_engines, hilite -from app.utils.login import get_id_token from app.utils.user import is_gov_user diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 8e063f777..8619322ab 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -3,8 +3,6 @@ import json import secrets from urllib.parse import unquote -from flask import current_app, request - from app import redis_client from app.notify_client import NotifyAdminAPIClient, _attach_current_user, cache from app.utils.user_permissions import ( @@ -41,12 +39,6 @@ class InviteApiClient(NotifyAdminAPIClient): } data = _attach_current_user(data) - # make the state variable to properly store the nonce. - # this matches the api code in app.service_invite.rest.get_user_data_url_safe() - state_data = json.dumps(data) - state_data = base64.b64encode(state_data.encode("utf8")) - state = state_data.decode("utf8") - # make and store the nonce nonce = secrets.token_urlsafe() redis_key = f"login-nonce-{unquote(nonce)}" From 579a65c92d71436045b9e89920d34fc57be11164 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Tue, 15 Oct 2024 17:04:02 -0400 Subject: [PATCH 6/9] Removed defunct imports. Signed-off-by: Cliff Hill --- app/notify_client/invite_api_client.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 8619322ab..711cc1f55 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -1,5 +1,3 @@ -import base64 -import json import secrets from urllib.parse import unquote From 866a4ad7bd2bc22e69efbf72e5e0edee65ec7f92 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Mon, 21 Oct 2024 12:48:22 -0400 Subject: [PATCH 7/9] Got the unit test to be fixed, still figuring out a new test for the new function. Signed-off-by: Cliff Hill --- tests/app/notify_client/test_invite_client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/app/notify_client/test_invite_client.py b/tests/app/notify_client/test_invite_client.py index d12832c2f..a251d5367 100644 --- a/tests/app/notify_client/test_invite_client.py +++ b/tests/app/notify_client/test_invite_client.py @@ -25,11 +25,16 @@ def test_client_creates_invite( "created_at", "auth_type", "folder_permissions", + "nonce", } ) }, ) + mock_token_urlsafe = mocker.patch("secrets.token_urlsafe") + fake_nonce = "1234567890" + mock_token_urlsafe.return_value = fake_nonce + invite_api_client.create_invite( "12345", "67890", "test@example.com", {"send_messages"}, "sms_auth", [fake_uuid] ) @@ -45,6 +50,7 @@ def test_client_creates_invite( "permissions": "send_emails,send_texts", "invite_link_host": "http://localhost:6012", "folder_permissions": [fake_uuid], + "nonce": fake_nonce, }, ) From e04adba4fd6c2b43a3b92cef1e1713625805bd0e Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Mon, 21 Oct 2024 13:18:20 -0400 Subject: [PATCH 8/9] Test written for get_id_token. Signed-off-by: Cliff Hill --- tests/app/utils/test_login.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/app/utils/test_login.py b/tests/app/utils/test_login.py index 7e1dc2468..30ed18140 100644 --- a/tests/app/utils/test_login.py +++ b/tests/app/utils/test_login.py @@ -20,3 +20,23 @@ def test_email_needs_revalidating( ): api_user_active["email_access_validated_at"] = email_access_validated_at assert email_needs_revalidating(User(api_user_active)) == expected_result + + +def test_get_id_token(mocker): + mock_request_get = mocker.patch("requests.get") + fake_kid = "fake" + mock_request_get.return_value.json.return_value = { + "keys": [{"kid": fake_kid, "alg": "whatever"}] + } + mock_dumps = mocker.patch("json.dumps") + mock_dumps.return_value = "Not really JSON" + mock_from_jwk = mocker.patch("jwt.algorithms.RSAAlgorithm.from_jwk") + mock_from_jwk.return_value = "Fake fake fake" + mock_get_unverified_header = mocker.patch("jwt.get_unverified_header") + mock_get_unverified_header.return_value.__getitem__.return_value = fake_kid + mock_decode = mocker.patch("jwt.decode") + from app.utils import login + + login.get_id_token({"id_token": "Not a token"}) + + assert mock_decode.called From 341e5d4cb2a16f36a67dee2dd82909d72ed3b433 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Tue, 22 Oct 2024 14:51:09 -0400 Subject: [PATCH 9/9] Removed logging. Signed-off-by: Cliff Hill --- app/main/views/sign_in.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index dc08a93cc..a326202f3 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -212,7 +212,6 @@ def sign_in(): # pragma: no cover nonce = secrets.token_urlsafe() redis_key = f"-{unquote(nonce)}" - current_app.logger.info(f"<<<<<<<<<<<<<<<<<<<<<<<< redis key: {redis_key}") redis_client.set(redis_key, nonce) # handle unit tests