Skip to content

Commit abde747

Browse files
refactor: organize examples into client specific folders. add new examples for Accounts and Auth APIs
1 parent 6294f16 commit abde747

15 files changed

Lines changed: 580 additions & 42 deletions

examples/Accounts API/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Duo Accounts API Examples Overview
2+
3+
4+
## Examples
5+
6+
This folder contains various examples to illustrate the usage of the `Accounts` module within the
7+
`duo_client_python` library. The Duo Accounts API is primarily intended for use by Managed Service
8+
Partners (MSP) to assist in the automation of managing their child (customer) Duo accounts.
9+
10+
Use of the Duo Accounts API requires special access to be enabled. Please see the
11+
[online documentation](https://www.duosecurity.com/docs/accountsapi) for more information.
12+
13+
# Using
14+
15+
To run an example query, execute a command like the following from the repo root:
16+
```python
17+
$ python3 examples/Auth/get_billing_and_telephony_credits.py
18+
```
19+
20+
Or, from within this folder:
21+
```python
22+
$ python3 ./get_billing_and_telephony_credits.py
23+
```
24+
25+
# Tested Against Python Versions
26+
* 3.7
27+
* 3.8
28+
* 3.9
29+
* 3.10
30+
* 3.11

examples/Accounts API/create_child_account.py

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,24 @@
33
"""
44

55
import duo_client
6-
import os
7-
import sys
86
import getpass
97

10-
from pprint import pprint
118

12-
13-
argv_iter = iter(sys.argv[1:])
14-
15-
16-
def _get_next_arg(prompt, secure=False):
9+
def _get_user_input(prompt, secure=False):
1710
"""Read information from STDIN, using getpass when sensitive information should not be echoed to tty"""
18-
try:
19-
return next(argv_iter)
20-
except StopIteration:
21-
if secure is True:
22-
return getpass.getpass(prompt)
23-
else:
24-
return input(prompt)
11+
if secure is True:
12+
return getpass.getpass(prompt)
13+
else:
14+
return input(prompt)
2515

2616

2717
def prompt_for_credentials() -> dict:
28-
"""Collect required API credentials from command line prompts
29-
30-
:return: dictionary containing Duo Accounts API ikey, skey and hostname strings
31-
"""
18+
"""Collect required API credentials from command line prompts"""
3219

33-
ikey = _get_next_arg('Duo Accounts API integration key ("DI..."): ')
34-
skey = _get_next_arg('Duo Accounts API integration secret key: ', secure=True)
35-
host = _get_next_arg('Duo Accounts API hostname ("api-....duosecurity.com"): ')
36-
account_name = _get_next_arg('Name for new child account: ')
20+
ikey = _get_user_input('Duo Accounts API integration key ("DI..."): ')
21+
skey = _get_user_input('Duo Accounts API integration secret key: ', secure=True)
22+
host = _get_user_input('Duo Accounts API hostname ("api-....duosecurity.com"): ')
23+
account_name = _get_user_input('Name for new child account: ')
3724

3825
return {"IKEY": ikey, "SKEY": skey, "APIHOST": host, "ACCOUNT_NAME": account_name}
3926

@@ -49,11 +36,12 @@ def main():
4936
host=inputs['APIHOST']
5037
)
5138

52-
print(f"Creating child account with name [{inputs['ACCOUNT_NAME']}]")
39+
print(f"Creating child account with worker_name [{inputs['ACCOUNT_NAME']}]")
5340
child_account = account_client.create_account(inputs['ACCOUNT_NAME'])
5441

5542
if 'account_id' in child_account:
5643
print(f"Child account for [{inputs['ACCOUNT_NAME']}] created successfully.")
44+
set_edition_result = account_client.e
5745
else:
5846
print(f"An unexpected error occurred while creating child account for {inputs['ACCOUNT_NAME']}")
5947
print(child_account)

examples/Accounts API/delete_child_account.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ def main():
5353
child_account_list = account_client.get_child_accounts()
5454
for account in child_account_list:
5555
if account['account_id'] == inputs['ACCOUNT_ID']:
56-
account_name = account['name']
56+
account_name = account['worker_name']
5757
if account_name is None:
5858
print(f"Unable to find account with ID [{inputs['ACCOUNT_ID']}]")
5959
sys.exit()
6060

61-
print(f"Deleting child account with name [{account_name}]")
61+
print(f"Deleting child account with worker_name [{account_name}]")
6262
deleted_account = account_client.delete_account(inputs['ACCOUNT_ID'])
6363
if deleted_account == '':
6464
print(f"Account {inputs['ACCOUNT_ID']} was deleted successfully.")
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Example of Duo Accounts API get child account edition
3+
"""
4+
5+
import duo_client
6+
import getpass
7+
8+
DUO_EDITIONS = {
9+
"ENTERPRISE": "Duo Essentials",
10+
"PLATFORM": "Duo Advantage",
11+
"BEYOND": "Duo Premier",
12+
"PERSONAL": "Duo Free"
13+
}
14+
15+
def _get_user_input(prompt, secure=False):
16+
"""Read information from STDIN, using getpass when sensitive information should not be echoed to tty"""
17+
if secure is True:
18+
return getpass.getpass(prompt)
19+
else:
20+
return input(prompt)
21+
22+
23+
def prompt_for_credentials() -> dict:
24+
"""Collect required API credentials from command line prompts"""
25+
26+
ikey = _get_user_input('Duo Accounts API integration key ("DI..."): ')
27+
skey = _get_user_input('Duo Accounts API integration secret key: ', secure=True)
28+
host = _get_user_input('Duo Accounts API hostname ("api-....duosecurity.com"): ')
29+
account_id = _get_user_input('Child account ID: ')
30+
31+
return {
32+
"ikey": ikey,
33+
"skey": skey,
34+
"host": host,
35+
"account_id": account_id,
36+
}
37+
38+
39+
def main():
40+
"""Main program entry point"""
41+
42+
inputs = prompt_for_credentials()
43+
44+
account_admin_api = duo_client.admin.AccountAdmin(**inputs)
45+
46+
print(f"Getting edition for account ID {inputs['account_id']}...")
47+
result = account_admin_api.get_edition()
48+
if 'edition' not in result:
49+
print(f"An error occurred while getting edition for account {inputs['account_id']}")
50+
print(f"Error message: {result}")
51+
else:
52+
print(f"The current Duo Edition for account {inputs['account_id']} is '{result['edition']}' " +
53+
f"[{DUO_EDITIONS[result['edition']]}]")
54+
55+
56+
if __name__ == '__main__':
57+
main()

examples/Admin API/get_billing_and_telephony_credits.py renamed to examples/Accounts API/get_billing_and_telephony_credits.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
#!/usr/bin/env python
22
from __future__ import absolute_import
33
from __future__ import print_function
4-
import csv
54
import sys
65

76
import duo_client
87
from six.moves import input
98

10-
argv_iter = iter(sys.argv[1:])
11-
def get_next_arg(prompt):
9+
EDITIONS = {
10+
"ENTERPRISE": "Duo Essentials",
11+
"PLATFORM": "Duo Advantage",
12+
"BEYOND": "Duo Premier",
13+
"PERSONAL": "Duo Free"
14+
}
15+
16+
def get_next_input(prompt):
1217
try:
13-
return next(argv_iter)
18+
return next(iter(sys.argv[1:]))
1419
except StopIteration:
1520
return input(prompt)
1621

17-
ikey=get_next_arg('Accounts API integration key ("DI..."): ')
18-
skey=get_next_arg('Accounts API integration secret key: ')
19-
host=get_next_arg('Accounts API hostname ("api-....duosecurity.com"): ')
22+
ikey=get_next_input('Accounts API integration key ("DI..."): ')
23+
skey=get_next_input('Accounts API integration secret key: ')
24+
host=get_next_input('Accounts API hostname ("api-....duosecurity.com"): ')
2025

2126
# Configuration and information about objects to create.
2227
accounts_api = duo_client.Accounts(
@@ -46,7 +51,7 @@ def get_next_arg(prompt):
4651
child_account_edition = account_admin_api.get_edition()
4752
print("Edition for child account {name}: {edition}".format(
4853
name=child_account['name'],
49-
edition=child_account_edition['edition'])
54+
edition=EDITIONS[child_account_edition['edition']])
5055
)
5156
except RuntimeError as err:
5257
# The account might not have access to get billing information
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""
2+
Example of Duo Accounts API set child account edition
3+
"""
4+
5+
import duo_client
6+
import getpass
7+
8+
ALLOWED_DUO_EDITIONS = ("PERSONAL", "ENTERPRISE", "PLATFORM", "BEYOND")
9+
10+
def _get_user_input(prompt, secure=False):
11+
"""Read information from STDIN, using getpass when sensitive information should not be echoed to tty"""
12+
if secure is True:
13+
return getpass.getpass(prompt)
14+
else:
15+
return input(prompt)
16+
17+
18+
def prompt_for_credentials() -> dict:
19+
"""Collect required API credentials from command line prompts"""
20+
21+
ikey = _get_user_input('Duo Accounts API integration key ("DI..."): ')
22+
skey = _get_user_input('Duo Accounts API integration secret key: ', secure=True)
23+
host = _get_user_input('Duo Accounts API hostname ("api-....duosecurity.com"): ')
24+
account_id = _get_user_input('Child account ID: ')
25+
account_apihost = _get_user_input('Child account api_hostname: ')
26+
account_edition = _get_user_input('Child account edition: ')
27+
while account_edition.upper() not in ALLOWED_DUO_EDITIONS:
28+
print(f"Invalid account edition. Please select one of {ALLOWED_DUO_EDITIONS}")
29+
account_edition = _get_user_input('Child account edition: ')
30+
31+
return {
32+
"ikey": ikey,
33+
"skey": skey,
34+
"host": host,
35+
"account_id": account_id,
36+
"child_api_host": account_apihost,
37+
"account_edition": account_edition,
38+
}
39+
40+
41+
def main():
42+
"""Main program entry point"""
43+
44+
inputs = prompt_for_credentials()
45+
edition = inputs.pop('account_edition')
46+
edition = edition.upper()
47+
48+
account_admin_api = duo_client.admin.AccountAdmin(**inputs)
49+
50+
print(f"Setting edition for account ID {inputs['account_id']} to {edition}")
51+
result = account_admin_api.set_edition(edition)
52+
if result != "":
53+
print(f"An error occurred while setting edition for account {inputs['account_id']}")
54+
print(f"Error message: {result}")
55+
else:
56+
print(f"Edition [{edition}] successfully set for account ID {inputs['account_id']}")
57+
58+
59+
if __name__ == '__main__':
60+
main()

examples/Admin API/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Duo Admin API Examples Overview
2+
3+
4+
## Examples
5+
6+
This folder contains various examples to illustrate the usage of the `Admin` module within the
7+
`duo_client_python` library. The Duo Admin API is primarily intended for automating the management
8+
account level elements within a customer configuration such as:
9+
10+
- Users
11+
- Groups
12+
- Phones/Tablets
13+
- Tokens
14+
- Application integrations
15+
- Policies
16+
- Logs
17+
18+
# Using
19+
20+
To run an example query, execute a command like the following from the repo root:
21+
```python
22+
$ python3 examples/Admin/report_users_and_phones.py
23+
```
24+
25+
Or, from within this folder:
26+
```python
27+
$ python3 ./report_users_and_phones.py
28+
```
29+
30+
# Tested Against Python Versions
31+
* 3.7
32+
* 3.8
33+
* 3.9
34+
* 3.10
35+
* 3.11

examples/Admin API/create_integration_sso_generic.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
import duo_client
88
from six.moves import input
99

10-
argv_iter = iter(sys.argv[1:])
1110
def get_next_arg(prompt):
1211
try:
13-
return next(argv_iter)
12+
return next(iter(sys.argv[1:]))
1413
except StopIteration:
1514
return input(prompt)
1615

examples/Admin API/create_user_and_phone.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ def get_next_arg(prompt):
2121
host=get_next_arg('API hostname ("api-....duosecurity.com"): '),
2222
)
2323

24-
USERNAME = get_next_arg('user login name: ')
25-
REALNAME = get_next_arg('user full name: ')
24+
USERNAME = get_next_arg('user login worker_name: ')
25+
REALNAME = get_next_arg('user full worker_name: ')
2626

2727
# Refer to http://www.duosecurity.com/docs/adminapi for more
2828
# information about phone types and platforms.

examples/Admin API/log_examples.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ def get_next_arg(prompt, default=None):
7070
activity = log["activity_id"]
7171
ts = log["ts"]
7272
action = log["action"]
73-
actor_name = log.get("actor", {}).get("name", None)
74-
target_name = log.get("target", {}).get("name", None)
75-
application = log.get("application", {}).get("name", None)
73+
actor_name = log.get("actor", {}).get("worker_name", None)
74+
target_name = log.get("target", {}).get("worker_name", None)
75+
application = log.get("application", {}).get("worker_name", None)
7676
reporter.writerow(
7777
[
7878
activity,

0 commit comments

Comments
 (0)