From d4eb9c6d0bfdf507f7e7a2ce816524d0cf237732 Mon Sep 17 00:00:00 2001 From: Vasyl Smoliak Date: Tue, 1 Sep 2026 12:34:10 +0200 Subject: [PATCH] Add subaccount permissions to integration create and update --- README.md | 2 +- duo_client/accounts.py | 4 +- duo_client/admin.py | 177 +++++++++++++++++- examples/Accounts/README.md | 8 +- examples/Accounts/create_child_account.py | 10 +- .../create_integration_in_child_account.py | 6 +- examples/Accounts/delete_child_account.py | 10 +- examples/Accounts/get_account_edition.py | 8 +- .../get_billing_and_telephony_credits.py | 6 +- examples/Accounts/retrieve_account_list.py | 8 +- ...etrieve_integrations_from_child_account.py | 8 +- examples/Accounts/set_account_edition.py | 8 +- examples/README.md | 11 +- tests/admin/test_integration.py | 51 +++++ 14 files changed, 269 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index d096467..5c921c2 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ **Admin** - https://www.duosecurity.com/docs/adminapi -**Accounts** - https://www.duosecurity.com/docs/accountsapi + - **Subaccount access** - https://duo.com/docs/adminapi#subaccounts **Activity** - The activity endpoint is in public preview and subject to change diff --git a/duo_client/accounts.py b/duo_client/accounts.py index 555dcfa..3191503 100644 --- a/duo_client/accounts.py +++ b/duo_client/accounts.py @@ -1,7 +1,7 @@ """ -Duo Security Accounts API reference client implementation. +Duo Security Admin API subaccount management reference client implementation. - + """ from . import client diff --git a/duo_client/admin.py b/duo_client/admin.py index 5413923..075bc50 100644 --- a/duo_client/admin.py +++ b/duo_client/admin.py @@ -130,6 +130,21 @@ 'adminapi_read_resource': , 'adminapi_settings': , 'adminapi_write_resource': , + 'adminapi_subaccount_accounts': , + 'adminapi_subaccount_accounts_read': , + 'adminapi_subaccount_admins': , + 'adminapi_subaccount_admins_read': , + 'adminapi_subaccount_info': , + 'adminapi_subaccount_integrations': , + 'adminapi_subaccount_integrations_read': , + 'adminapi_subaccount_settings': , + 'adminapi_subaccount_settings_read': , + 'adminapi_subaccount_read_log': , + 'adminapi_subaccount_read_resource': , + 'adminapi_subaccount_write_resource': , + 'adminapi_subaccount_allow_to_set_permissions': , + 'adminapi_subaccount_user_limits': , + 'adminapi_subaccount_user_limits_read': , 'self_service_allowed': , 'enroll_policy': , 'username_normalization_policy': , @@ -2636,7 +2651,22 @@ def create_integration(self, groups_allowed=None, self_service_allowed=None, sso=None, - user_access=None): + user_access=None, + adminapi_subaccount_accounts=None, + adminapi_subaccount_accounts_read=None, + adminapi_subaccount_admins=None, + adminapi_subaccount_admins_read=None, + adminapi_subaccount_info=None, + adminapi_subaccount_integrations=None, + adminapi_subaccount_integrations_read=None, + adminapi_subaccount_settings=None, + adminapi_subaccount_settings_read=None, + adminapi_subaccount_read_log=None, + adminapi_subaccount_read_resource=None, + adminapi_subaccount_write_resource=None, + adminapi_subaccount_allow_to_set_permissions=None, + adminapi_subaccount_user_limits=None, + adminapi_subaccount_user_limits_read=None): """Creates a new integration. name - The name of the integration (required) @@ -2659,12 +2689,30 @@ def create_integration(self, adminapi_read_resource - |None adminapi_settings - |None adminapi_write_resource - |None + adminapi_subaccount_accounts - |None + adminapi_subaccount_accounts_read - |None + adminapi_subaccount_admins - |None + adminapi_subaccount_admins_read - |None + adminapi_subaccount_info - |None + adminapi_subaccount_integrations - |None + adminapi_subaccount_integrations_read - |None + adminapi_subaccount_settings - |None + adminapi_subaccount_settings_read - |None + adminapi_subaccount_read_log - |None + adminapi_subaccount_read_resource - |None + adminapi_subaccount_write_resource - |None + adminapi_subaccount_allow_to_set_permissions - |None + adminapi_subaccount_user_limits - |None + adminapi_subaccount_user_limits_read - |None groups_allowed - self_service_allowed - |None sso - (optional) New argument for unreleased feature. Will return an error if used. Client will be updated again in the future when feature is released. + The adminapi_subaccount_* permissions apply only to 'adminapi' + integrations and are ignored for other integration types. + Returns the created integration. Raises RuntimeError on error. @@ -2707,6 +2755,51 @@ def create_integration(self, if adminapi_write_resource is not None: params['adminapi_write_resource'] = ( '1' if adminapi_write_resource else '0') + if adminapi_subaccount_accounts is not None: + params['adminapi_subaccount_accounts'] = ( + '1' if adminapi_subaccount_accounts else '0') + if adminapi_subaccount_accounts_read is not None: + params['adminapi_subaccount_accounts_read'] = ( + '1' if adminapi_subaccount_accounts_read else '0') + if adminapi_subaccount_admins is not None: + params['adminapi_subaccount_admins'] = ( + '1' if adminapi_subaccount_admins else '0') + if adminapi_subaccount_admins_read is not None: + params['adminapi_subaccount_admins_read'] = ( + '1' if adminapi_subaccount_admins_read else '0') + if adminapi_subaccount_info is not None: + params['adminapi_subaccount_info'] = ( + '1' if adminapi_subaccount_info else '0') + if adminapi_subaccount_integrations is not None: + params['adminapi_subaccount_integrations'] = ( + '1' if adminapi_subaccount_integrations else '0') + if adminapi_subaccount_integrations_read is not None: + params['adminapi_subaccount_integrations_read'] = ( + '1' if adminapi_subaccount_integrations_read else '0') + if adminapi_subaccount_settings is not None: + params['adminapi_subaccount_settings'] = ( + '1' if adminapi_subaccount_settings else '0') + if adminapi_subaccount_settings_read is not None: + params['adminapi_subaccount_settings_read'] = ( + '1' if adminapi_subaccount_settings_read else '0') + if adminapi_subaccount_read_log is not None: + params['adminapi_subaccount_read_log'] = ( + '1' if adminapi_subaccount_read_log else '0') + if adminapi_subaccount_read_resource is not None: + params['adminapi_subaccount_read_resource'] = ( + '1' if adminapi_subaccount_read_resource else '0') + if adminapi_subaccount_write_resource is not None: + params['adminapi_subaccount_write_resource'] = ( + '1' if adminapi_subaccount_write_resource else '0') + if adminapi_subaccount_allow_to_set_permissions is not None: + params['adminapi_subaccount_allow_to_set_permissions'] = ( + '1' if adminapi_subaccount_allow_to_set_permissions else '0') + if adminapi_subaccount_user_limits is not None: + params['adminapi_subaccount_user_limits'] = ( + '1' if adminapi_subaccount_user_limits else '0') + if adminapi_subaccount_user_limits_read is not None: + params['adminapi_subaccount_user_limits_read'] = ( + '1' if adminapi_subaccount_user_limits_read else '0') if groups_allowed is not None: params['groups_allowed'] = groups_allowed if self_service_allowed is not None: @@ -2840,7 +2933,22 @@ def update_integration(self, groups_allowed=None, self_service_allowed=None, sso=None, - user_access=None + user_access=None, + adminapi_subaccount_accounts=None, + adminapi_subaccount_accounts_read=None, + adminapi_subaccount_admins=None, + adminapi_subaccount_admins_read=None, + adminapi_subaccount_info=None, + adminapi_subaccount_integrations=None, + adminapi_subaccount_integrations_read=None, + adminapi_subaccount_settings=None, + adminapi_subaccount_settings_read=None, + adminapi_subaccount_read_log=None, + adminapi_subaccount_read_resource=None, + adminapi_subaccount_write_resource=None, + adminapi_subaccount_allow_to_set_permissions=None, + adminapi_subaccount_user_limits=None, + adminapi_subaccount_user_limits_read=None ): """Updates an integration. @@ -2862,6 +2970,21 @@ def update_integration(self, adminapi_read_resource - True|False|None adminapi_settings - True|False|None adminapi_write_resource - True|False|None + adminapi_subaccount_accounts - True|False|None + adminapi_subaccount_accounts_read - True|False|None + adminapi_subaccount_admins - True|False|None + adminapi_subaccount_admins_read - True|False|None + adminapi_subaccount_info - True|False|None + adminapi_subaccount_integrations - True|False|None + adminapi_subaccount_integrations_read - True|False|None + adminapi_subaccount_settings - True|False|None + adminapi_subaccount_settings_read - True|False|None + adminapi_subaccount_read_log - True|False|None + adminapi_subaccount_read_resource - True|False|None + adminapi_subaccount_write_resource - True|False|None + adminapi_subaccount_allow_to_set_permissions - True|False|None + adminapi_subaccount_user_limits - True|False|None + adminapi_subaccount_user_limits_read - True|False|None reset_secret_key - |None groups_allowed - self_service_allowed - True|False|None @@ -2869,6 +2992,9 @@ def update_integration(self, New argument for unreleased feature. Will return an error if used. Client will be updated again in the future when feature is released. + The adminapi_subaccount_* permissions apply only to 'adminapi' + integrations and are ignored for other integration types. + If any value other than None is provided for 'reset_secret_key' (for example, 1), then a new secret key will be generated for the integration. @@ -2915,6 +3041,51 @@ def update_integration(self, if adminapi_write_resource is not None: params['adminapi_write_resource'] = ( '1' if adminapi_write_resource else '0') + if adminapi_subaccount_accounts is not None: + params['adminapi_subaccount_accounts'] = ( + '1' if adminapi_subaccount_accounts else '0') + if adminapi_subaccount_accounts_read is not None: + params['adminapi_subaccount_accounts_read'] = ( + '1' if adminapi_subaccount_accounts_read else '0') + if adminapi_subaccount_admins is not None: + params['adminapi_subaccount_admins'] = ( + '1' if adminapi_subaccount_admins else '0') + if adminapi_subaccount_admins_read is not None: + params['adminapi_subaccount_admins_read'] = ( + '1' if adminapi_subaccount_admins_read else '0') + if adminapi_subaccount_info is not None: + params['adminapi_subaccount_info'] = ( + '1' if adminapi_subaccount_info else '0') + if adminapi_subaccount_integrations is not None: + params['adminapi_subaccount_integrations'] = ( + '1' if adminapi_subaccount_integrations else '0') + if adminapi_subaccount_integrations_read is not None: + params['adminapi_subaccount_integrations_read'] = ( + '1' if adminapi_subaccount_integrations_read else '0') + if adminapi_subaccount_settings is not None: + params['adminapi_subaccount_settings'] = ( + '1' if adminapi_subaccount_settings else '0') + if adminapi_subaccount_settings_read is not None: + params['adminapi_subaccount_settings_read'] = ( + '1' if adminapi_subaccount_settings_read else '0') + if adminapi_subaccount_read_log is not None: + params['adminapi_subaccount_read_log'] = ( + '1' if adminapi_subaccount_read_log else '0') + if adminapi_subaccount_read_resource is not None: + params['adminapi_subaccount_read_resource'] = ( + '1' if adminapi_subaccount_read_resource else '0') + if adminapi_subaccount_write_resource is not None: + params['adminapi_subaccount_write_resource'] = ( + '1' if adminapi_subaccount_write_resource else '0') + if adminapi_subaccount_allow_to_set_permissions is not None: + params['adminapi_subaccount_allow_to_set_permissions'] = ( + '1' if adminapi_subaccount_allow_to_set_permissions else '0') + if adminapi_subaccount_user_limits is not None: + params['adminapi_subaccount_user_limits'] = ( + '1' if adminapi_subaccount_user_limits else '0') + if adminapi_subaccount_user_limits_read is not None: + params['adminapi_subaccount_user_limits_read'] = ( + '1' if adminapi_subaccount_user_limits_read else '0') if reset_secret_key is not None: params['reset_secret_key'] = '1' if groups_allowed is not None: @@ -3806,7 +3977,7 @@ def get_idv_status(self, user_id): class AccountAdmin(Admin): - """AccountAdmin manages a child account using an Accounts API integration.""" + """AccountAdmin manages a child account using an Admin API integration.""" def __init__(self, account_id, child_api_host=None, **kwargs): """Initializes an AccountAdmin for administering a child account. diff --git a/examples/Accounts/README.md b/examples/Accounts/README.md index ba663de..e6bbe30 100644 --- a/examples/Accounts/README.md +++ b/examples/Accounts/README.md @@ -1,14 +1,14 @@ -# Duo Accounts API Examples Overview +# Subaccount Management Examples Overview ## Examples This folder contains various examples to illustrate the usage of the `Accounts` module within the -`duo_client_python` library. The Duo Accounts API is primarily intended for use by Managed Service +`duo_client_python` library. Subaccount management in Admin API is primarily intended for use by Managed Service Partners (MSP) to assist in the automation of managing their child (customer) Duo accounts. -Use of the Duo Accounts API requires special access to be enabled. Please see the -[online documentation](https://www.duosecurity.com/docs/accountsapi) for more information. +Subaccount management in Admin API requires special access to be enabled. Please see the +[online documentation](https://duo.com/docs/adminapi#subaccounts) for more information. # Using diff --git a/examples/Accounts/create_child_account.py b/examples/Accounts/create_child_account.py index e66f552..a42eeac 100644 --- a/examples/Accounts/create_child_account.py +++ b/examples/Accounts/create_child_account.py @@ -1,5 +1,5 @@ """ -Example of Duo Accounts API child account creation +Example of Duo Admin API child account creation """ import duo_client @@ -27,12 +27,12 @@ def _get_next_arg(prompt, secure=False): def prompt_for_credentials() -> dict: """Collect required API credentials from command line prompts - :return: dictionary containing Duo Accounts API ikey, skey and hostname strings + :return: dictionary containing Duo Admin API ikey, skey and hostname strings """ - ikey = _get_next_arg('Duo Accounts API integration key ("DI..."): ') - skey = _get_next_arg('Duo Accounts API integration secret key: ', secure=True) - host = _get_next_arg('Duo Accounts API hostname ("api-....duosecurity.com"): ') + ikey = _get_next_arg('Duo Admin API integration key ("DI..."): ') + skey = _get_next_arg('Duo Admin API integration secret key: ', secure=True) + host = _get_next_arg('Duo Admin API hostname ("api-....duosecurity.com"): ') account_name = _get_next_arg('Name for new child account: ') return {"IKEY": ikey, "SKEY": skey, "APIHOST": host, "ACCOUNT_NAME": account_name} diff --git a/examples/Accounts/create_integration_in_child_account.py b/examples/Accounts/create_integration_in_child_account.py index ab397d2..ada15a7 100644 --- a/examples/Accounts/create_integration_in_child_account.py +++ b/examples/Accounts/create_integration_in_child_account.py @@ -29,10 +29,10 @@ def _get_next_arg(prompt, secure=False): def prompt_for_credentials() -> dict: """Collect required API credentials from command line prompts - :return: dictionary containing Duo Accounts API ikey, skey and hostname strings + :return: dictionary containing Duo Admin API ikey, skey and hostname strings """ - answers = {'ikey': _get_next_arg('Duo Accounts API integration key ("DI..."): '), - 'skey': _get_next_arg('Duo Accounts API integration secret key: ', secure=True), + answers = {'ikey': _get_next_arg('Duo Admin API integration key ("DI..."): '), + 'skey': _get_next_arg('Duo Admin API integration secret key: ', secure=True), 'host': _get_next_arg('Duo API hostname of child account ("api-....duosecurity.com"): '), 'account_id': _get_next_arg('Child account ID: '), 'app_name': _get_next_arg('New application name: '), diff --git a/examples/Accounts/delete_child_account.py b/examples/Accounts/delete_child_account.py index 16f3416..15585bb 100644 --- a/examples/Accounts/delete_child_account.py +++ b/examples/Accounts/delete_child_account.py @@ -1,5 +1,5 @@ """ -Example of Duo Accounts API child account deletiom +Example of Duo Admin API child account deletion """ import duo_client @@ -26,12 +26,12 @@ def _get_next_arg(prompt, secure=False): def prompt_for_credentials() -> dict: """Collect required API credentials from command line prompts - :return: dictionary containing Duo Accounts API ikey, skey and hostname strings + :return: dictionary containing Duo Admin API ikey, skey and hostname strings """ - ikey = _get_next_arg('Duo Accounts API integration key ("DI..."): ') - skey = _get_next_arg('Duo Accounts API integration secret key: ', secure=True) - host = _get_next_arg('Duo Accounts API hostname ("api-....duosecurity.com"): ') + ikey = _get_next_arg('Duo Admin API integration key ("DI..."): ') + skey = _get_next_arg('Duo Admin API integration secret key: ', secure=True) + host = _get_next_arg('Duo Admin API hostname ("api-....duosecurity.com"): ') account_id = _get_next_arg('ID of child account to delete: ') return {"IKEY": ikey, "SKEY": skey, "APIHOST": host, "ACCOUNT_ID": account_id} diff --git a/examples/Accounts/get_account_edition.py b/examples/Accounts/get_account_edition.py index 7452b4a..75369fe 100644 --- a/examples/Accounts/get_account_edition.py +++ b/examples/Accounts/get_account_edition.py @@ -1,5 +1,5 @@ """ -Example of Duo Accounts API get child account edition +Example of Duo Admin API get child account edition """ import duo_client @@ -23,9 +23,9 @@ def _get_user_input(prompt, secure=False): def prompt_for_credentials() -> dict: """Collect required API credentials from command line prompts""" - ikey = _get_user_input('Duo Accounts API integration key ("DI..."): ') - skey = _get_user_input('Duo Accounts API integration secret key: ', secure=True) - host = _get_user_input('Duo Accounts API hostname ("api-....duosecurity.com"): ') + ikey = _get_user_input('Duo Admin API integration key ("DI..."): ') + skey = _get_user_input('Duo Admin API integration secret key: ', secure=True) + host = _get_user_input('Duo Admin API hostname ("api-....duosecurity.com"): ') account_id = _get_user_input('Child account ID: ') return { diff --git a/examples/Accounts/get_billing_and_telephony_credits.py b/examples/Accounts/get_billing_and_telephony_credits.py index 35f09f8..0af89ab 100644 --- a/examples/Accounts/get_billing_and_telephony_credits.py +++ b/examples/Accounts/get_billing_and_telephony_credits.py @@ -19,9 +19,9 @@ def get_next_input(prompt): def main(): """Program entry point""" - ikey=get_next_input('Accounts API integration key ("DI..."): ') - skey=get_next_input('Accounts API integration secret key: ') - host=get_next_input('Accounts API hostname ("api-....duosecurity.com"): ') + ikey=get_next_input('Admin API integration key ("DI..."): ') + skey=get_next_input('Admin API integration secret key: ') + host=get_next_input('Admin API hostname ("api-....duosecurity.com"): ') # Configuration and information about objects to create. accounts_api = duo_client.Accounts( diff --git a/examples/Accounts/retrieve_account_list.py b/examples/Accounts/retrieve_account_list.py index 7118b8d..2b07555 100644 --- a/examples/Accounts/retrieve_account_list.py +++ b/examples/Accounts/retrieve_account_list.py @@ -26,12 +26,12 @@ def _get_next_arg(prompt, secure=False): def prompt_for_credentials() -> dict: """Collect required API credentials from command line prompts - :return: dictionary containing Duo Accounts API ikey, skey and hostname strings + :return: dictionary containing Duo Admin API ikey, skey and hostname strings """ - ikey = _get_next_arg('Duo Accounts API integration key ("DI..."): ') - skey = _get_next_arg('Duo Accounts API integration secret key: ', secure=True) - host = _get_next_arg('Duo Accounts API hostname ("api-....duosecurity.com"): ') + ikey = _get_next_arg('Duo Admin API integration key ("DI..."): ') + skey = _get_next_arg('Duo Admin API integration secret key: ', secure=True) + host = _get_next_arg('Duo Admin API hostname ("api-....duosecurity.com"): ') return {"IKEY": ikey, "SKEY": skey, "APIHOST": host} diff --git a/examples/Accounts/retrieve_integrations_from_child_account.py b/examples/Accounts/retrieve_integrations_from_child_account.py index 82d7f9c..0cc67ef 100644 --- a/examples/Accounts/retrieve_integrations_from_child_account.py +++ b/examples/Accounts/retrieve_integrations_from_child_account.py @@ -7,13 +7,13 @@ parser = argparse.ArgumentParser() -duo_arg_group = parser.add_argument_group('Duo Accounts API Credentials') +duo_arg_group = parser.add_argument_group('Duo Admin API Credentials') duo_arg_group.add_argument('--ikey', - help='Duo Accounts API IKEY', + help='Duo Admin API IKEY', required=True ) duo_arg_group.add_argument('--skey', - help='Duo Accounts API Secret Key', + help='Duo Admin API Secret Key', required=True, ) duo_arg_group.add_argument('--host', @@ -26,7 +26,7 @@ ) args = parser.parse_args() -# It is important to note that we are using the IKEY/SKEY combination for an Accounts API integration in the +# It is important to note that we are using the IKEY/SKEY combination for an Admin API integration in the # parent account along with the api-hostname of a child account to create a new duo_client.Admin instance account_client = duo_client.Admin( ikey=args.ikey, diff --git a/examples/Accounts/set_account_edition.py b/examples/Accounts/set_account_edition.py index ea97701..e657e7b 100644 --- a/examples/Accounts/set_account_edition.py +++ b/examples/Accounts/set_account_edition.py @@ -1,5 +1,5 @@ """ -Example of Duo Accounts API set child account edition +Example of Duo Admin API set child account edition """ import duo_client @@ -18,9 +18,9 @@ def _get_user_input(prompt, secure=False): def prompt_for_credentials() -> dict: """Collect required API credentials from command line prompts""" - ikey = _get_user_input('Duo Accounts API integration key ("DI..."): ') - skey = _get_user_input('Duo Accounts API integration secret key: ', secure=True) - host = _get_user_input('Duo Accounts API hostname ("api-....duosecurity.com"): ') + ikey = _get_user_input('Duo Admin API integration key ("DI..."): ') + skey = _get_user_input('Duo Admin API integration secret key: ', secure=True) + host = _get_user_input('Duo Admin API hostname ("api-....duosecurity.com"): ') account_id = _get_user_input('Child account ID: ') account_apihost = _get_user_input('Child account api_hostname: ') account_edition = _get_user_input('Child account edition: ') diff --git a/examples/README.md b/examples/README.md index 803bd09..afe1433 100644 --- a/examples/README.md +++ b/examples/README.md @@ -15,13 +15,12 @@ The Duo Admin API provides access to endpoints that are primarily focused on Duo - Integration management - Policy management - Log extractions +- Subaccount management + +Subaccount management is primarily intended for use by Duo Managed Service Provider (MSP) partners. +See the `Accounts` folder for examples. ------- ### Auth API The Duo Auth API provides access to user enrollment and authentication services and is primarily intended for use by -application developers that want to integration Duo MFA functionality into their applications. - -------- -### Accounts API -The Duo Accounts API provides access to Duo account management functionality and is primarily intended for use by -Duo Managed Service Provider (MSP) partners. \ No newline at end of file +application developers that want to integration Duo MFA functionality into their applications. \ No newline at end of file diff --git a/tests/admin/test_integration.py b/tests/admin/test_integration.py index 4f1aca5..cea38bd 100644 --- a/tests/admin/test_integration.py +++ b/tests/admin/test_integration.py @@ -5,6 +5,24 @@ import duo_client.admin from .base import TestAdmin +SUBACCOUNT_PERMISSIONS = [ + 'adminapi_subaccount_accounts', + 'adminapi_subaccount_accounts_read', + 'adminapi_subaccount_admins', + 'adminapi_subaccount_admins_read', + 'adminapi_subaccount_info', + 'adminapi_subaccount_integrations', + 'adminapi_subaccount_integrations_read', + 'adminapi_subaccount_settings', + 'adminapi_subaccount_settings_read', + 'adminapi_subaccount_read_log', + 'adminapi_subaccount_read_resource', + 'adminapi_subaccount_write_resource', + 'adminapi_subaccount_allow_to_set_permissions', + 'adminapi_subaccount_user_limits', + 'adminapi_subaccount_user_limits_read', +] + class TestIntegration(TestAdmin): def setUp(self): @@ -51,6 +69,39 @@ def test_create_integration(self): } ) + def test_create_integration_subaccount_permissions(self): + response = self.client.create_integration( + name="Subaccount integration", + integration_type="adminapi", + **{perm: True for perm in SUBACCOUNT_PERMISSIONS} + ) + + expected = { + "account_id": self.client.account_id, + "name": "Subaccount integration", + "type": "adminapi", + } + expected.update({perm: "1" for perm in SUBACCOUNT_PERMISSIONS}) + + self.assertEqual(response['method'], 'POST') + self.assertEqual(response['uri'], '/admin/v3/integrations') + self.assertEqual(json.loads(response['body']), expected) + + def test_update_integration_subaccount_permissions(self): + response = self.client.update_integration( + self.integration_key, + **{perm: False for perm in SUBACCOUNT_PERMISSIONS} + ) + + expected = {"account_id": self.client.account_id} + expected.update({perm: "0" for perm in SUBACCOUNT_PERMISSIONS}) + + self.assertEqual(response['method'], 'POST') + self.assertEqual( + response['uri'], + '/admin/v3/integrations/{}'.format(self.integration_key)) + self.assertEqual(json.loads(response['body']), expected) + def test_update_integration_success(self): response = self.client.update_integration( self.integration_key,