-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3879780
commit ce72cda
Showing
2 changed files
with
127 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
""" | ||
Example of creating an integration in a child account using parent account credentials | ||
The key to successfully interacting with child accounts via the parent account APIs is | ||
pairing the parent account API IKEY/SKEY combination with the api-host of the child account. | ||
Once that connection is established, the child account ID must be passed along with all API interactions. | ||
The duo_client SDK makes that easy by allowing the setting of the child account ID as an instance variable. | ||
""" | ||
|
||
import sys | ||
import getpass | ||
import duo_client | ||
|
||
# Create an interator to be used by the interactive terminal prompt | ||
argv_iter = iter(sys.argv[1:]) | ||
|
||
|
||
def _get_next_arg(prompt, secure=False): | ||
"""Read information from STDIN, using getpass when sensitive information should not be echoed to tty""" | ||
try: | ||
return next(argv_iter) | ||
except StopIteration: | ||
if secure is True: | ||
return getpass.getpass(prompt) | ||
else: | ||
return input(prompt) | ||
|
||
|
||
def prompt_for_credentials() -> dict: | ||
"""Collect required API credentials from command line prompts | ||
:return: dictionary containing Duo Accounts 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), | ||
'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: '), | ||
'app_type': _get_next_arg('New application type: ')} | ||
return answers | ||
|
||
|
||
def create_child_integration(inputs: dict): | ||
"""Create new application integration in child account via the parent account API""" | ||
|
||
# First create a duo_client.Admin instance using the parent account ikey/sky along with the child account api-host | ||
account_client = duo_client.Admin(ikey=inputs['ikey'], skey=inputs['skey'], host=inputs['host']) | ||
# Next assign the child account ID to the duo_client.Admin instance variable. | ||
account_client.account_id = inputs['account_id'] | ||
# Now all API calls made via this instance will contain all of the minimum requirements to interact with the | ||
# child account. | ||
|
||
# Here only the two required arguments (name and type) are passed. | ||
# Normally, much more information would be provided. The type of additional information | ||
# varies by the type of application integration. | ||
try: | ||
new_app = account_client.create_integration( | ||
name=inputs['app_name'], | ||
integration_type=inputs['app_type'], | ||
) | ||
print(f"New application {inputs['app_name']} (ID: {new_app['integration_key']}) was created successfully.") | ||
except RuntimeError as e_str: | ||
# Any failure of the API call results in a generic Runtime Error | ||
print(f"An error occurred while creating the new application: {e_str}") | ||
|
||
|
||
def main(): | ||
"""Main program entry point""" | ||
inputs = prompt_for_credentials() | ||
create_child_integration(inputs) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
53 changes: 53 additions & 0 deletions
53
examples/Accounts/retrieve_integrations_from_child_account.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
""" | ||
Example of creating an integration in a child account using parent account credentials | ||
""" | ||
|
||
import argparse | ||
import duo_client | ||
|
||
|
||
parser = argparse.ArgumentParser() | ||
duo_arg_group = parser.add_argument_group('Duo Accounts API Credentials') | ||
duo_arg_group.add_argument('--ikey', | ||
help='Duo Accounts API IKEY', | ||
required=True | ||
) | ||
duo_arg_group.add_argument('--skey', | ||
help='Duo Accounts API Secret Key', | ||
required=True, | ||
) | ||
duo_arg_group.add_argument('--host', | ||
help='Duo child account API apihost', | ||
required=True | ||
) | ||
parser.add_argument('--child_account_id', | ||
help='The Duo account ID of the child account to query.', | ||
required=True | ||
) | ||
args = parser.parse_args() | ||
|
||
# It is important to note that we are using the IKEY/SKEY combination for an Accounts 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, | ||
skey=args.skey, | ||
host=args.host, | ||
) | ||
|
||
# Once the duo_client.Admin instance is created, the child account_id is assigned. This is necessary to ensure | ||
# queries made with this Admin API instance are directed to the proper child account that matches the api-hostname | ||
# used to create the instance. | ||
account_client.account_id = args.child_account_id | ||
|
||
|
||
def main(): | ||
"""Main program entry point""" | ||
|
||
print(f"Retrieving integrations for child account {args.child_account_id}") | ||
child_account_integrations = account_client.get_integrations_generator() | ||
for integration in child_account_integrations: | ||
print(f"{integration['name']=}") | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |