From 08833cdd92b0475719b48f7367b794fad2970252 Mon Sep 17 00:00:00 2001 From: pcmxgti <16561338+pcmxgti@users.noreply.github.com> Date: Sat, 28 Oct 2023 15:02:28 -0400 Subject: [PATCH] add more tests --- tests/unit/test_duo.py | 61 +++++++++++++++++++++++++++++++++++++++--- tokendito/duo.py | 55 +++++++++++++++++++------------------ 2 files changed, 87 insertions(+), 29 deletions(-) diff --git a/tests/unit/test_duo.py b/tests/unit/test_duo.py index 1226272e..f2f0c238 100644 --- a/tests/unit/test_duo.py +++ b/tests/unit/test_duo.py @@ -1,19 +1,21 @@ # vim: set filetype=python ts=4 sw=4 # -*- coding: utf-8 -*- """Unit tests, and local fixtures for DUO module.""" -# from multiprocessing import Value from unittest.mock import Mock import pytest -def test_set_passcode(mocker): +def test_get_passcode(mocker): """Check if numerical passcode can handle leading zero values.""" from tokendito import duo mocker.patch("tokendito.user.tty_assertion", return_value=True) mocker.patch("tokendito.user.input", return_value="0123456") - assert duo.set_passcode({"factor": "passcode"}) == "0123456" + assert duo.get_passcode({"factor": "passcode"}) == "0123456" + assert duo.get_passcode({"factor": "PassCode"}) == "0123456" + assert duo.get_passcode({"factor": "push"}) is None + assert duo.get_passcode("pytest") is None def test_prepare_duo_info(): @@ -54,6 +56,10 @@ def test_prepare_duo_info(): } assert prepare_duo_info(selected_okta_factor) == expected_duo_info + with pytest.raises(SystemExit) as err: + prepare_duo_info({"badresponse": "FAIL"}) + assert err.value.code == 1 + def test_get_duo_sid(mocker): """Check if got sid correct.""" @@ -101,3 +107,52 @@ def test_get_mfa_response(): with pytest.raises(SystemExit) as err: get_mfa_response(Mock(return_value="FAIL")) assert err.value.code == 1 + + +def test_duo_api_post(mocker): + """Test if duo api post correctly.""" + from tokendito.duo import duo_api_post + + mock_post = mocker.patch("requests.Session.post") + mock_resp = mocker.Mock() + mock_resp.status_code = 201 + mock_resp.json.return_value = {"status": "pytest"} + mock_post.return_value = mock_resp + + response = duo_api_post("https://pytest/") + assert response == {"status": "pytest"} + + +def test_get_duo_devices(): + """TODO: Implement test.""" + pass + + +def test_parse_duo_mfa_challenge(): + """TODO: Implement test.""" + pass + + +def test_get_duo_mfa_challenge(): + """TODO: Implement test.""" + pass + + +def test_parse_challenge(): + """TODO: Implement test.""" + pass + + +def test_mfa_verify(): + """TODO: Implement test.""" + pass + + +def test_duo_factor_callback(): + """TODO: Implement test.""" + pass + + +def test_authenticate_duo(): + """TODO: Implement test.""" + pass diff --git a/tokendito/duo.py b/tokendito/duo.py index f583a9b7..b5c6d13a 100644 --- a/tokendito/duo.py +++ b/tokendito/duo.py @@ -23,21 +23,24 @@ def prepare_duo_info(selected_okta_factor): :return duo_info: dict of parameters for Duo """ duo_info = {} - okta_factor = selected_okta_factor["_embedded"]["factor"]["_embedded"]["verification"] - duo_info["okta_factor"] = okta_factor - duo_info["factor_id"] = selected_okta_factor["_embedded"]["factor"]["id"] - - duo_info["state_token"] = selected_okta_factor["stateToken"] - duo_info["okta_callback_url"] = okta_factor["_links"]["complete"]["href"] - duo_info["tx"] = okta_factor["signature"].split(":")[0] - duo_info["tile_sig"] = okta_factor["signature"].split(":")[1] - duo_info["parent"] = f"{config.okta['org']}/signin/verify/duo/web" - duo_info["host"] = okta_factor["host"] - duo_info["sid"] = "" - - version = okta_factor["_links"]["script"]["href"].split("-v")[1] - duo_info["version"] = version.strip(".js") - + try: + okta_factor = selected_okta_factor["_embedded"]["factor"]["_embedded"]["verification"] + duo_info["okta_factor"] = okta_factor + duo_info["factor_id"] = selected_okta_factor["_embedded"]["factor"]["id"] + + duo_info["state_token"] = selected_okta_factor["stateToken"] + duo_info["okta_callback_url"] = okta_factor["_links"]["complete"]["href"] + duo_info["tx"] = okta_factor["signature"].split(":")[0] + duo_info["tile_sig"] = okta_factor["signature"].split(":")[1] + duo_info["parent"] = f"{config.okta['org']}/signin/verify/duo/web" + duo_info["host"] = okta_factor["host"] + duo_info["sid"] = "" + + version = okta_factor["_links"]["script"]["href"].split("-v")[1] + duo_info["version"] = version.strip(".js") + except KeyError as missing_key: + logger.error(f"There was an issue parsing the Okta factor. Please try again: {missing_key}") + sys.exit(1) return duo_info @@ -265,8 +268,8 @@ def duo_factor_callback(duo_info, verify_mfa): return sig_response -def set_passcode(mfa_option): - """Set totp passcode. +def get_passcode(mfa_option): + """Get totp passcode. If the user has selected the passcode option, collect their TOTP. @@ -274,9 +277,13 @@ def set_passcode(mfa_option): :return passcode: passcode value from user """ passcode = None - if mfa_option["factor"].lower() == "passcode": - user.print("Type your TOTP and press Enter:") - passcode = user.get_input() + + try: + if mfa_option["factor"].lower() == "passcode": + user.print("Type your TOTP and press Enter:") + passcode = user.get_input() + except (TypeError, KeyError): + pass return passcode @@ -291,11 +298,7 @@ def authenticate_duo(selected_okta_factor): :return payload: required payload for Okta callback :return headers: required headers for Okta callback """ - try: - duo_info = prepare_duo_info(selected_okta_factor) - except KeyError as missing_key: - logger.error(f"There was an issue parsing the Okta factor. Please try again: {missing_key}") - sys.exit(1) + duo_info = prepare_duo_info(selected_okta_factor) # Collect devices, factors, auth params for Duo duo_info, duo_auth_response = get_duo_sid(duo_info) factor_options = get_duo_devices(duo_auth_response) @@ -305,7 +308,7 @@ def authenticate_duo(selected_okta_factor): mfa_option = factor_options[mfa_index] logger.debug(f"Selected MFA is [{mfa_option}]") - passcode = set_passcode(mfa_option) + passcode = get_passcode(mfa_option) txid = duo_mfa_challenge(duo_info, mfa_option, passcode) verify_mfa = duo_mfa_verify(duo_info, txid)