Duo connector
The duo connector lets you manage Duo service accounts and synchronize accounts and groups between Duo and the IDM or Advanced Identity Cloud managed user repository.
This topic describes how to install and configure the Duo connector and how to perform basic tests to ensure that it’s running correctly.
Before you start
The instructions in this guide assume you have a Duo Administrator Account and you have created and authorized a Custom Application, as described in the Duo Documentation.
Before you configure the connector, log in to your administrator account and note the following information:
-
Navigate to
Applications
. -
Click
Protect an Application
. -
Locate the entry for
Admin API
in the applications list. -
Click
Protect
to the far-right to configure the application and make note of the following:-
Integration Key
-
Secret Key
-
API hostname
-
Install the Duo connector
If you are looking for the Advanced Identity Cloud application for this connector, refer to: |
You can download any connector from Backstage, but some are included in the default deployment for Advanced Identity Cloud, IDM, or RCS. When using an included connector, you can skip installing it and move directly to configuration.
Connector | IDM | RCS |
---|---|---|
No |
No |
Download the connector .jar file from Backstage.
-
If you are running the connector locally, place it in the
/path/to/openidm/connectors
directory, for example:mv ~/Downloads/duo-connector-1.5.20.26.jar /path/to/openidm/connectors/
-
If you are using a remote connector server (RCS), place it in the
/path/to/openicf/connectors
directory on the RCS.
Configure the Duo connector
Create a connector configuration using the IDM admin UI:
-
From the navigation bar, click Configure > Connectors.
-
On the Connectors page, click New Connector.
-
On the New Connector page, type a Connector Name.
-
From the Connector Type drop-down list, select Duo Connector - 1.5.20.26.
-
Complete the Base Connector Details.
For a list of all configuration properties, refer to Duo Connector Configuration -
Click Save.
When your connector is configured correctly, the connector displays as Active in the admin UI.
Refer to this procedure to create a connector configuration over REST.
The following excerpt shows sample configuration properties:
"configurationProperties": {
"host" : "_CHANGEME_",
"integrationKey" : "_CHANGEME_",
"secretKey" : "_CHANGEME_"
}
Integration Key
-
The Duo Application
Integration Key
. Secret Key
-
The Duo Application
Secret Key
. API hostname
-
The Duo API
hostname
.
Test the Duo connector
Test that the configuration is correct by running the following command:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --request POST \ 'http://localhost:8080/openidm/system/duo?_action=test' { "name": duo, "enabled": true, "config": "config/provisioner.openicf/Duo", "connectorRef": { "bundleVersion": "[1.5.0.0,1.6.0.0)", "bundleName": "org.forgerock.openicf.connectors.duo-connector", "connectorName": "org.forgerock.openicf.connectors.duo.DuoConnector" }, "displayName": "org.forgerock.openicf.connectors.duo.DuoConnector", "objectTypes": [ "__ACCOUNT__", "__ALL__", "__GROUP__" ], "ok": true }
If the command returns "ok": true
, your connector was configured correctly and can authenticate to the Duo server.
Duo remote connector
If you want to run this connector outside of PingOne Advanced Identity Cloud or IDM, you can configure the Duo connector as a remote connector. Java Connectors installed remotely on a Java Connector Server function identically to those bundled locally within PingOne Advanced Identity Cloud or installed locally on IDM.
You can download the Duo connector from here.
Refer to Remote connectors for configuring the Duo remote connector.
Use the Duo connector
You can use the duo connector to perform the following actions on a Duo account.
Accounts: User
Create a Duo user
This example creates a Duo user with the minimum required attributes.
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "userType": "user", "__NAME__": "Jhon Doe", "email": "jhon_doe@example.com", }' \ "http://localhost:8080/openidm/system/Duo/__ACCOUNT__?_action=create" { "_id": "DUAAA11BB1C1D1EE1UUU", "tokens": [], "phones": [], "notes": "", "email": "jhon_doe@example.com", "__GROUPS__": [], "__ENABLE__": True, "realname": "", "userType": "user", "__NAME__": "Jhon Doe", "alias1": null, "alias2": null, "alias3": null, "alias4": null, "last_login": null }
When you create a new user, you must specify at least the Valid |
Create a Duo full user
This example creates a Duo full user.
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Content-Type: application/json" \ --request POST \ --data '{ { "__GROUPS__": [ "DGAA00BB0C0D0EE0GGG" ], "tokens": [ "DHAAA00BB0C0D0EE0TTT" ], "phones": [ "+12125551212" ], "notes": "example", "email": "jane_doe@example.com", "__ENABLE__": True, "realname": "Jane Doe", "alias1": "Jane", "alias2": null, "alias3": "Doe", "alias4": null, "userType": "user", "__NAME__": "Jane Doe" }' \ "http://localhost:8080/openidm/system/Duo/__ACCOUNT__?_action=create" { "_id": "DUAAA00BB0C0D0EE0UUU", "realname": "Jane Doe", "userType": "user", "phones": [ "+12125551212" ], "__GROUPS__": [ "DGAA00BB0C0D0EE0GGG" ], "tokens": [ "DHAAA00BB0C0D0EE0TTT" ], "__NAME__": "Jane Doe", "notes": "example", "__ENABLE__": True, "email": "jane_doe@example.com", "alias1": "jane", "alias2": null, "alias3": "doe, "alias4": null, "last_login": null" }
Because phone numbers are automatically created before being assigned to a user, the connector deletes unused phone numbers when you perform a user update or delete. This prevents the accumulation of junk data.
Any attribute with a |
List all Duo users
This example queries all Duo users:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --request GET \ "http://localhost:8080/openidm/system/Duo/__ACCOUNT__?_queryFilter=true" { "result": [ { "_id": "DUAAA00BB0C0D0EE0UUU", "realname": "Jane Doe", "userType": "user", "phones": [ "+12125551212" ], "__GROUPS__": [], "tokens": [], "__NAME__": "jane doe", "notes": "example", "__ENABLE__": True, "email": "jane_doe@example.com", "last_login": null, "alias1": "jane", "alias2": null, "alias4": null, "alias3": "doe" }, ... { "_id": "DUAAA11BB1C1D1EE1UUU", "realname": "", "userType": "user", "phones": [], "__GROUPS__": [], "tokens": [], "notes": "", "__NAME__": "Jhon Doe", "__ENABLE__": True, "email": "jhon_doe@example.com", "last_login": null, "alias1": null, "alias2": null, "alias3": null, "alias4": null } ], "resultCount": 96, "pagedResultsCookie": null, "totalPagedResultsPolicy": "NONE", "totalPagedResults": -1, "remainingPagedResults": -1 }
Get Duo user
This example queries a specific Duo user by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --request GET \ 'http://localhost:8080/openidm/system/Duo/__ACCOUNT__/DUAAA11BB1C1D1EE1UUU' { "_id": "DUAAA11BB1C1D1EE1UUU", "realname": "", "userType": "user", "phones": [], "__GROUPS__": [], "tokens": [], "__NAME__": "Jhon Doe", "notes": "", "__ENABLE__": True, "email": "jhon_doe@example.com", "last_login": null, "alias1": null, "alias2": null, "alias3": null, "alias4": null }
Update a Duo user
This example updates a specific Duo user by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Content-Type: application/json" \ --header "If-Match: *" \ --request POST \ --data '{ "alias1": "Jhon", "alias4": "", "notes": "example note", "email": "jhon_doe@example.com", "__GROUPS__": [], "__ENABLE__": True, "realname": "Jhon Doe", "__NAME__": "Jhon Doe" }' \ 'http://localhost:8080/openidm/system/Duo/__ACCOUNT__/DUAAA11BB1C1D1EE1UUU' { "_id": "DUAAA11BB1C1D1EE1UUU", "tokens": [], "phones": [ "+12125551212" ], "notes": "example note", "email": "jhon_doe@example.com", "__GROUPS__": [], "__ENABLE__": True, "realname": "Jhon Doe", "userType": "user", "__NAME__": "Jhon Doe", "last_login": null, "alias1": "Jhon", "alias2": "Doe", "alias3": null, "alias4": null }
Delete a Duo user
This example deletes a Duo user:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --header "If-Match: *" \ --request DELETE \ 'http://localhost:8080/openidm/system/Duo/__ACCOUNT__/DUAAA11BB1C1D1EE1UUU' { "_id": "DUAAA11BB1C1D1EE1UUU", "realname": "Jhon Doe", "userType": "user", "phones": [ "+12125551212" ], "__GROUPS__": [], "tokens": [], "__NAME__": "Jhon Doe", "notes": "Tests note", "__ENABLE__": True, "email": "jhon_doe@example.com", "last_login": null, "alias1": "Jhon", "alias2": "Doe", "alias3": null, "alias4": null }
The response returns the account object before deletion. |
Accounts: Admin
Create a Duo admin
This example creates a Duo admin.
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "role": "Owner", "phones": [ "+12125551212" ], "email": "jhon_doe@example.com", "realname": "Jhon Doe", "userType": "admin", "__NAME__": "Jhon Doe", "restricted_by_admin_units": false }' \ "http://localhost:8080/openidm/system/Duo/__ACCOUNT__?_action=create" { "_id": "DEAAA11BB1C1D1EE1UUU", "phones": [ "+12125551212" ], "email": "jhon_doe@example.com", "__ENABLE__": False, "restricted_by_admin_units": "false", "userType": "admin", "__NAME__": "Jhon Doe", "last_login": null, "role": "Owner" }
When you create a new Admin, you must specify at least the __NAME__
and email
attributes.
role
value must be one of the following values:
-
Owner
-
Administrator
-
Application Manager
-
User Manager
-
Security Analyst
-
Help Desk
-
Billing
-
Phishing Manager
-
Read-only
The role names are case-sensitive. Defaults to "Owner" if not specified.
phones
: Phone number for the new administrator. Limited to one. It cannot be removed once assigned due to API limitations. Formatted in the E.164 standard (+17345551212
). If no leading plus sign is provided, then it is assumed to be a United States number and an implicit +1
country code is prepended. Dashes and spaces are ignored. If this parameter is specified, it cannot be empty.
restricted_by_admin_units
: Is this administrator restricted by an administrative unit assignment? Either true
or false
. Defaults to false
if not specified. Must be set to true
in order to add the admin to an administrative unit using the API. Note that attempting to set to true
for admins with the Owner
role results in a failure response.
send_email
: Optional. If set to 1
, the activation link and an introductory message will be emailed to the new administrator. If set to 0
, no email is sent, and the link is returned to the API method’s caller only. Defaults to 0
.
token_id
: Optional. The token_id
of the hardware token to associate with the administrator.
valid_days
: Optional. Number of days before the activation link expires. Defaults to 7
, the maximum allowed value is 31
.
__ENABLE__
will remain False
until the admin’s account is validated. In the meantime, __ENABLE__
cannot be changed by the connector.
Get Duo Admin
This example queries a specific Duo admin by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --request GET \ 'http://localhost:8080/openidm/system/Duo/__ACCOUNT__/DEAAA11BB1C1D1EE1UUU' { "_id": "DEAAA11BB1C1D1EE1UUU", "phones": [ "+12125551212" ], "email": "jhon_doe@example.com", "__ENABLE__": True, "restricted_by_admin_units": "false", "userType": "admin", "__NAME__": "Jhon Doe", "last_login": null, "role": "Owner" }
Update a Duo Admin
This example updates a specific Duo admin by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Content-Type: application/json" \ --header "If-Match: *" \ --request POST \ --data '{ "role": "Read-Only", "__ENABLE__": True, }' \ 'http://localhost:8080/openidm/system/Duo/__ACCOUNT__/DEAAA11BB1C1D1EE1UUU' { "_id": "DEAAA11BB1C1D1EE1UUU", "phones": [ "+12125551212" ], "email": "jhon_doe@example.com", "__ENABLE__": True, "restricted_by_admin_units": "false", "userType": "admin", "__NAME__": "Jhon Doe", "last_login": null, "role": "Read-Only" }
GROUPS
Create a Duo group
This example creates a Duo group:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Content-Type: application/json" \ --request POST \ --data '{ "desc": "Generic Description", "__ENABLE__": "True, "__NAME__": "Group 1" }' \ 'http://localhost:8080/openidm/system/Duo/__GROUP__' { "_id": "DGAA00BB0C0D0EE0GGG", "desc": "Generic Description", "__ENABLE__": True, "__NAME__": "Group 1" }
Query all Duo groups
This example queries all Duo groups:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --request GET \ 'http://localhost:8080/openidm/system/Duo/__GROUP__?_queryFilter=True' { "result": [ { "_id": "DGAA00BB0C0D0EE0GGG", "desc": "Generic Description", "__ENABLE__": True, "__NAME__": "Testing Group" }, ... { "_id": "DGAA11BB1C1D1EE1GGG", "desc": "Working Group", "__ENABLE__": True, "__NAME__": "Working Group" } ], "resultCount": 56, "pagedResultsCookie": null, "totalPagedResultsPolicy": "NONE", "totalPagedResults": -1, "remainingPagedResults": -1 }
The maximum number of records returned is 100 per page. |
Get a Duo group
This example gets a Duo group by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --request GET \ 'http://localhost:8080/openidm/system/Duo/__GROUP__/DGAA00BB0C0D0EE0GGG' { "_id": "DGAA00BB0C0D0EE0GGG", "desc": "Generic Description", "__ENABLE__": True, "__NAME__": "Group 1" }
Update a Duo group
This example updates a Duo group by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --header "If-Match: *" \ --request PUT \ --data '{ "desc": "New tests", "__NAME__": "New Group tests", }' \ 'http://localhost:8080/openidm/system/Duo/__GROUP__/DGAA00BB0C0D0EE0GGG' { "_id": "DGAA00BB0C0D0EE0GGG", "__NAME__": "New Group tests", "desc": "New tests", "__ENABLE__": True }
Delete a Duo group
This example deletes a Duo group by its ID:
curl \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header 'Content-Type: application/json' \ --request DELETE \ 'http://localhost:8080/openidm/system/Duo/__GROUP__/DGAA00BB0C0D0EE0GGG' { "_id": "DGAA00BB0C0D0EE0GGG", "__NAME__": "New Group tests", "desc": "New tests", "__ENABLE__": True }
The response returns the group object before deletion. |
Mapping
From Duo users to IDM or Advanced Identity Cloud users
Attributes Grid: Where the columns represent the attribute name mapped from source to target and the necessary data transformation to synchronize successfully.
SOURCE | TARGET | TRANSFORMATION SCRIPT |
---|---|---|
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
From IDM or Advanced Identity Cloud users to Duo users
Attributes Grid: Where the columns represent the attribute name mapped from source to target and the necessary data transformation to synchronize successfully.
SOURCE | TARGET | TRANSFORMATION SCRIPT |
---|---|---|
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
From Duo groups to IDM or Advanced Identity Cloud groups
Attributes Grid: Where the columns represent the attribute name mapped from source to target and the necessary data transformation to synchronize successfully.
SOURCE | TARGET | TRANSFORMATION SCRIPT |
---|---|---|
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
From IDM or Advanced Identity Cloud groups to Duo groups
Attributes Grid: Where the columns represent the attribute name mapped from source to target and the necessary data transformation to synchronize successfully.
SOURCE | TARGET | TRANSFORMATION SCRIPT |
---|---|---|
|
|
N/A |
|
|
N/A |
|
|
N/A |
|
|
N/A |
OpenICF Interfaces Implemented by the Duo Connector
The Duo Connector implements the following OpenICF interfaces. For additional details, see ICF interfaces:
- Create
-
Creates an object and its
uid
. - Delete
-
Deletes an object, referenced by its
uid
. - Schema
-
Describes the object types, operations, and options that the connector supports.
- Script on Connector
-
Enables an application to run a script in the context of the connector.
Any script that runs on the connector has the following characteristics:
-
The script runs in the same execution environment as the connector and has access to all the classes to which the connector has access.
-
The script has access to a
connector
variable that is equivalent to an initialized instance of the connector. At a minimum, the script can access the connector configuration. -
The script has access to any script arguments passed in by the application.
-
- Search
-
Searches the target resource for all objects that match the specified object class and filter.
- Test
-
Tests the connector configuration.
Testing a configuration checks all elements of the environment that are referred to by the configuration are available. For example, the connector might make a physical connection to a host that is specified in the configuration to verify that it exists and that the credentials that are specified in the configuration are valid.
This operation might need to connect to a resource, and, as such, might take some time. Do not invoke this operation too often, such as before every provisioning operation. The test operation is not intended to check that the connector is alive (that is, that its physical connection to the resource has not timed out).
You can invoke the test operation before a connector configuration has been validated.
- Update
-
Updates (modifies or replaces) objects on a target resource.
Duo Connector Configuration
The Duo Connector has the following configurable properties:
Basic Configuration Properties
Property | Type | Default | Encrypted(1) | Required(2) |
---|---|---|---|---|
|
|
|
|
Yes |
URL API Host (api-xxxxxx.duosecurity.com) |
||||
|
|
|
|
Yes |
App Integration Key |
||||
|
|
|
Yes |
No |
App Secret Key |
(1) Whether the property value is considered confidential, and is therefore encrypted in IDM.
(2) A list of operations in this column indicates that the property is required for those operations.