Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pcmxgti committed Oct 28, 2023
1 parent 2f3760c commit 08833cd
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 29 deletions.
61 changes: 58 additions & 3 deletions tests/unit/test_duo.py
Original file line number Diff line number Diff line change
@@ -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():
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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
55 changes: 29 additions & 26 deletions tokendito/duo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -265,18 +268,22 @@ 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.
:param mfa_option: selected factor
: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


Expand All @@ -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)
Expand All @@ -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)
Expand Down

0 comments on commit 08833cd

Please sign in to comment.