Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions duo_client/accounts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Duo Security Accounts API reference client implementation.
Duo Security Admin API subaccount management reference client implementation.

<http://www.duosecurity.com/docs/accountsapi>
<https://duo.com/docs/adminapi#subaccounts>
"""
from . import client

Expand Down
177 changes: 174 additions & 3 deletions duo_client/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,21 @@
'adminapi_read_resource': <bool:read resource permission (0|1)>,
'adminapi_settings': <bool:settings permission (0|1)>,
'adminapi_write_resource': <bool:write resource permission (0|1)>,
'adminapi_subaccount_accounts': <bool:subaccount accounts permission (0|1)>,
'adminapi_subaccount_accounts_read': <bool:subaccount accounts read permission (0|1)>,
'adminapi_subaccount_admins': <bool:subaccount admins permission (0|1)>,
'adminapi_subaccount_admins_read': <bool:subaccount admins read permission (0|1)>,
'adminapi_subaccount_info': <bool:subaccount info permission (0|1)>,
'adminapi_subaccount_integrations': <bool:subaccount integrations permission (0|1)>,
'adminapi_subaccount_integrations_read': <bool:subaccount integrations read permission (0|1)>,
'adminapi_subaccount_settings': <bool:subaccount settings permission (0|1)>,
'adminapi_subaccount_settings_read': <bool:subaccount settings read permission (0|1)>,
'adminapi_subaccount_read_log': <bool:subaccount read log permission (0|1)>,
'adminapi_subaccount_read_resource': <bool:subaccount read resource permission (0|1)>,
'adminapi_subaccount_write_resource': <bool:subaccount write resource permission (0|1)>,
'adminapi_subaccount_allow_to_set_permissions': <bool:subaccount set permissions permission (0|1)>,
'adminapi_subaccount_user_limits': <bool:subaccount user limits permission (0|1)>,
'adminapi_subaccount_user_limits_read': <bool:subaccount user limits read permission (0|1)>,
'self_service_allowed': <bool:self service permission (0|1)>,
'enroll_policy': <str:enroll policy (enroll|allow|deny)>,
'username_normalization_policy': <str:normalization policy (simple|none)>,
Expand Down Expand Up @@ -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)
Expand All @@ -2659,12 +2689,30 @@ def create_integration(self,
adminapi_read_resource - <bool: read resource permission>|None
adminapi_settings - <bool: settings permission>|None
adminapi_write_resource - <bool:write resource permission>|None
adminapi_subaccount_accounts - <bool:subaccount accounts permission>|None
adminapi_subaccount_accounts_read - <bool:subaccount accounts read permission>|None
adminapi_subaccount_admins - <bool:subaccount admins permission>|None
adminapi_subaccount_admins_read - <bool:subaccount admins read permission>|None
adminapi_subaccount_info - <bool:subaccount info permission>|None
adminapi_subaccount_integrations - <bool:subaccount integrations permission>|None
adminapi_subaccount_integrations_read - <bool:subaccount integrations read permission>|None
adminapi_subaccount_settings - <bool:subaccount settings permission>|None
adminapi_subaccount_settings_read - <bool:subaccount settings read permission>|None
adminapi_subaccount_read_log - <bool:subaccount read log permission>|None
adminapi_subaccount_read_resource - <bool:subaccount read resource permission>|None
adminapi_subaccount_write_resource - <bool:subaccount write resource permission>|None
adminapi_subaccount_allow_to_set_permissions - <bool:subaccount set permissions permission>|None
adminapi_subaccount_user_limits - <bool:subaccount user limits permission>|None
adminapi_subaccount_user_limits_read - <bool:subaccount user limits read permission>|None
groups_allowed - <str: CSV list of gkeys of groups allowed to auth>
self_service_allowed - <bool: self service permission>|None
sso - <dict: parameters for generic single sign-on> (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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.

Expand All @@ -2862,13 +2970,31 @@ 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 - <any value>|None
groups_allowed - <str: CSV list of gkeys of groups allowed to auth>
self_service_allowed - True|False|None
sso - <dict: parameters for generic single sign-on> (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.

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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions examples/Accounts/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
10 changes: 5 additions & 5 deletions examples/Accounts/create_child_account.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Example of Duo Accounts API child account creation
Example of Duo Admin API child account creation
"""

import duo_client
Expand Down Expand Up @@ -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}
Expand Down
6 changes: 3 additions & 3 deletions examples/Accounts/create_integration_in_child_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -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: '),
Expand Down
10 changes: 5 additions & 5 deletions examples/Accounts/delete_child_account.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Example of Duo Accounts API child account deletiom
Example of Duo Admin API child account deletion
"""

import duo_client
Expand All @@ -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}
Expand Down
Loading