From 09366a77d9600f9925bac1d40adab4cc8e073ac2 Mon Sep 17 00:00:00 2001 From: Mark Tripod <66480604+MarkTripod-Duo@users.noreply.github.com> Date: Fri, 25 Jul 2025 14:48:21 -0400 Subject: [PATCH] feat: add identity verification methods to admin.py --- duo_client/admin.py | 48 +++++++++++++++++++++++++++++++++++++++-- tests/admin/test_idv.py | 26 ++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/admin/test_idv.py diff --git a/duo_client/admin.py b/duo_client/admin.py index 9b7657d..5413923 100644 --- a/duo_client/admin.py +++ b/duo_client/admin.py @@ -178,10 +178,11 @@ import time import urllib.parse import warnings -from typing import List, Optional from datetime import datetime, timedelta, timezone +from typing import List, Optional from . import Accounts, client + USER_STATUS_ACTIVE = "active" USER_STATUS_BYPASS = "bypass" USER_STATUS_DISABLED = "disabled" @@ -3760,6 +3761,49 @@ def update_passport_config(self, enabled_status, enabled_groups: Optional[List[s ) return response + def start_idv(self, user_id): + """ + Start identity verification process + + Args: + user_id (str) - The ID of the Duo user (required) + + Returns (dict) - Dictionary containing details of IDV process + """ + path = f"/admin/v2/identity_verification/{user_id}/start" + return self.json_api_call( + "POST", + path, + {} + ) + + def cancel_idv(self, user_id, inquiry_id): + """ + Cancel identity verification process + + Args: + user_id (str) - The ID of the Duo user (required) + inquiry_id (str) - The inquiry_id of the request to cancel (required) + """ + path = f"/admin/v2/identity_verification/{user_id}/cancel" + return self.json_api_call( + "POST", + path, + {"inquiry_id": inquiry_id} + ) + + def get_idv_status(self, user_id): + """ + Get the status of a identity verification process + + Args: + user_id (str) - The ID of the Duo user (required) + + Returns (dict) - Dictionary containing details of the identity verification process status + """ + path = f"/admin/v2/identity_verification/{user_id}/status" + return self.json_api_call("GET", path, {}) + class AccountAdmin(Admin): """AccountAdmin manages a child account using an Accounts API integration.""" @@ -3849,4 +3893,4 @@ def set_telephony_credits(self, credits): } return self.json_api_call('POST', '/admin/v1/billing/telephony_credits', - params) \ No newline at end of file + params) diff --git a/tests/admin/test_idv.py b/tests/admin/test_idv.py new file mode 100644 index 0000000..a1bd291 --- /dev/null +++ b/tests/admin/test_idv.py @@ -0,0 +1,26 @@ +import json + +from .base import TestAdmin + + +class TestIDV(TestAdmin): + def test_start_idv(self): + """ Test start identity verification process + """ + response = self.client.start_idv('DU012345678901234567') + self.assertEqual(response['uri'], '/admin/v2/identity_verification/DU012345678901234567/start') + + def test_get_idv_status(self): + """ Test get identity verification process status + """ + response = self.client.get_idv_status('DU012345678901234567') + (uri, args) = response['uri'].split('?') + self.assertEqual(uri, '/admin/v2/identity_verification/DU012345678901234567/status') + + def test_cancel_idv(self): + """ Test cancel identity verification process + """ + response = self.client.cancel_idv('DU012345678901234567', 'inq_PY3skN8RKxPKBPdpbpdtZfHy6rwJ') + body = json.loads(response["body"]) + self.assertEqual(response['uri'], '/admin/v2/identity_verification/DU012345678901234567/cancel') + self.assertEqual(body['inquiry_id'], 'inq_PY3skN8RKxPKBPdpbpdtZfHy6rwJ')