Synchronize Passwords With ForgeRock Directory Services (DS)
The DS password synchronization plugin intercepts passwords that are changed natively in the DS server and propagates these password changes to IDM. The password synchronization plugin captures password changes in clear text, encrypts them, and transmits them to IDM. If IDM is unavailable when a password change occurs, the password change is queued for subsequent retry.
The password synchronization plugin requires keys to encrypt changed passwords and certificates to secure communication between DS and IDM. The examples that follow use the keys generated when you set up the DS and IDM servers.
Setting Up IDM and DS to Demonstrate Password Synchronization
The following examples prepare a demonstration of password synchronization from DS to IDM. After this preparation:
DS and IDM are installed and running on your computer, with default security settings.
In particular, both servers have key pairs used later in the demonstration:
DS has a generated TLS key pair (alias:
ssl-key-pair
and certificate subject DN:CN=DS, O=ForgeRock.com
) signed by the DS deployment key-based CA (certificate subject DN:CN=Deployment key, O=ForgeRock.com
).DS uses the certificate to set up TLS connections, and to authenticate to IDM.
IDM has a generated key pair, alias
openidm-localhost
. The certificate is self-signed, and has certificate subject DNCN=openidm-localhost, O=OpenIDM Self-Signed Certificate, OU=None, L=None, ST=None, C=None
.DS uses the public key certificate to encrypt passwords before sending them to IDM.
IDM does not otherwise synchronize DS data with its own.
This lets you confirm that DS, not synchronization, provides the updated password to IDM.
DS and IDM both have a user account for Barbara Jensen.
After you have configured password synchronization, when Barbara Jensen's password changes in DS, DS sends the change to IDM.
Update your hosts file.
The IDM self-signed certificate uses the domain alias
openidm-localhost
. When testing the DS plugin on your computer, add the alias to your/etc/hosts
file:127.0.0.1 localhost openidm-localhost
Unzip IDM.
Start IDM:
/path/to/openidm/startup.sh
Add Barbara Jensen's account to IDM:
curl \ --request PUT \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --header "Accept: application/json" \ --header "If-None-Match: *" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --data '{"userName":"bjensen","password":"Password1","mail":"bjensen@example.com","sn":"Jensen","givenName":"Barbara"}' \ "http://localhost:8080/openidm/managed/user/bjensen"
{ "_id": "bjensen", "_rev": "revision", "userName": "bjensen", "mail": "bjensen@example.com", "sn": "Jensen", "givenName": "Barbara", "accountStatus": "active", "effectiveAssignments": [], "effectiveRoles": [] }
Download the DS 7.1 .zip distribution from the ForgeRock BackStage download site.
Unzip DS:
unzip -q ~/Downloads/DS-7.1.zip -d /path/to
Generate a DS deployment key that you use for DS setup and managing keys:
/path/to/opendj/bin/dskeymgr create-deployment-key --deploymentKeyPassword password
your-deployment-key
Set up and start DS with data from an IDM example that includes Barbara Jensen's entry:
/path/to/opendj/setup \ --serverId evaluation-only \ --deploymentKey your-deployment-key \ --deploymentKeyPassword password \ --rootUserDn uid=admin \ --rootUserPassword password \ --hostname localhost \ --adminConnectorPort 4444 \ --ldapsPort 1636 \ --profile ds-user-data \ --set ds-user-data/baseDn:dc=com \ --set ds-user-data/ldifFile:/path/to/openidm/samples/sync-with-ldap/data/Example.ldif \ --start \ --acceptLicense
The sample data includes an entry for Barbara Jensen. The rest of the sample configuration is not used here.
Check that the directory superuser can read Barbara Jensen's entry in the directory:
/path/to/opendj/bin/ldapsearch \ --port 1636 \ --useSSL \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --hostname localhost \ --bindDn uid=admin \ --bindPassword password \ --baseDn dc=com \ "(uid=bjensen)"
dn: uid=bjensen,ou=People,dc=example,dc=com objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson objectClass: top cn: Barbara Jensen description: Created for OpenIDM givenName: Barbara mail: bjensen@example.com sn: Jensen telephoneNumber: 1-360-229-7105 uid: bjensen userPassword: {PBKDF2-HMAC-SHA256}10:hash
Notice that this entry differs from the account you added to IDM. However, the user identifier is
bjensen
in both cases. This will let IDM identify Barbara Jensen's account as the one whose password has changed when it receives the notification from DS.
Establishing Secure Communication Between IDM and DS
The password synchronization plugin encrypts passwords using IDM's public key. IDM then uses its private key to decrypt the password.
This section describes how to export IDM's certificate, containing its public key, to DS so that the password synchronization plugin can use the public key to encrypt the password. The same certificate is used by the plugin to trust the SSL certificate that is provided by IDM.
There are four possible modes of communication between the DS password synchronization plugin and IDM:
- SSL Authentication
For this communication mode, you must import IDM's certificate into the DS truststore (either the self-signed certificate that is generated the first time IDM starts, or a CA-signed certificate).
- Mutual SSL Authentication
Note
Mutual SSL authentication is the default configuration of the password synchronization plugin.
For this communication mode, you must:
Add the DS certificate subject DN as a value of the
allowedAuthenticationIdPatterns
property in your project'sconf/authentication.json
file.
- AM Bearer Tokens
When you use IDM and AM together as a platform, configure the password synchronization plugin to use AM bearer tokens for authentication.
For this communication mode, you must:
- HTTP Basic Authentication
Warning
IDM supports basic authentication for testing purposes only. Do not use basic authentication in production.
For this mode, the connection is secured using a username and password, rather than any exchange of certificates. Because the password sync plugin requires the IDM certificate to encrypt/decrypt passwords, you must import the IDM certificate into the DS truststore.
For this communication mode, you must:
Set the following properties in the plugin configuration:
openidm-url
openidm-username
openidm-password
Enable DS to Trust the IDM Certificate
The first time IDM starts, it generates a self-signed certificate. This procedure uses the self-signed certificate to demonstrate how to get the password synchronization plugin up and running. In a production environment, use a certificate that has been signed by a Certificate Authority (CA).
The default Java truststore contains signing certificates from well-known CAs. If your CA certificate is not in the default truststore, or if you are using a self-signed certificate, import it into the DS keystore, as described here.
Export the IDM self-signed certificate to a file, as follows:
keytool \ -export \ -alias openidm-localhost \ -file openidm-localhost.crt \ -keystore /path/to/openidm/security/keystore.jceks \ -storetype jceks \ -storepass changeit
Certificate stored in file <openidm-localhost.crt>
The default IDM keystore password is
changeit
.Import the self-signed certificate into the DS keystore:
keytool \ -import \ -alias openidm-localhost \ -file openidm-localhost.crt \ -keystore /path/to/opendj/config/keystore \ -storepass:file /path/to/opendj/config/keystore.pin \ -storetype PKCS12 \ -noprompt
Certificate was added to keystore
(Optional) Check that the IDM certificate is in the DS keystore:
keytool \ -list \ -keystore /path/to/opendj/config/keystore \ -storepass:file /path/to/opendj/config/keystore.pin
... openidm-localhost, date, trustedCertEntry, Certificate fingerprint (SHA-256): fingerprint ...
Enable IDM to Trust DS Certificates
For mutual SSL authentication, you must also import a trusted DS certificate into the IDM truststore, either a trusted CA certificate, or the CA certificate that is generated by the DS deployment key and password. For more information, see Deployment Keys in the DS Security Guide. This procedure uses the CA certificate generated by the DS deployment key and password.
Run the following command on your DS server to export the CA certificate to a file. Substitute the values for
--deploymentKey
and--deploymentKeyPassword
with the deployment key and password that you used when you set up the DS server:/path/to/opendj/bin/dskeymgr \ export-ca-cert \ --deploymentKey your-deployment-key \ --deploymentKeyPassword password \ --outputFile ds-ca-cert.pem
Import the DS CA certificate into the IDM truststore:
keytool \ -importcert \ -alias ds-ca-cert \ -keystore /path/to/openidm/security/truststore \ -storepass changeit \ -file ds-ca-cert.pem
Owner: CN=Deployment key, O=ForgeRock.com Issuer: CN=Deployment key, O=ForgeRock.com ... Trust this certificate? [no]:
yes
Certificate was added to keystore
(Optional) Check that the DS CA certificate is in the IDM truststore:
keytool \ -list \ -keystore /path/to/openidm/security/truststore \ -storepass changeit
...ds-ca-cert, date, trustedCertEntry, Certificate fingerprint (SHA-256): fingerprint
...Restart IDM:
/path/to/openidm/shutdown.sh; /path/to/openidm/startup.sh
Configure the Password Synchronization Plugin to Accept AM Bearer Tokens
This procedure uses the Platform Setup Guide as the basis for setting up IDM to use AM bearer tokens for authentication, and may need adjustment for your specific environment.
Perform Platform Setup - Deployment Two - Shared Identity Store, using the following settings during the applicable steps:
adminConnectorPort 4444
ldapPort 1389
enableStartTls
ldapsPort 1636
httpsPort 8443
replicationPort 8989
deploymentKey your-deployment-key
adminConnectorPort 4445
ldapPort 1390
ldapsPort 1637
replicationPort 8990
deploymentKey your-deployment-key
port: 8080
redirects: 8444
openidm.port.http=8081
openidm.port.https=8445
openidm.port.mutualauth=8446
openidm.host=openidm.example.com
openidm.auth.clientauthonlyports=8446
Configure a
ds-password-sync-plugin
OAuth Client for the Password Sync Plugin:If you're not currently logged in to the AM console as the
amAdmin
user, log in.In the Top Level Realm, select Applications > OAuth 2.0 > Clients, and click Add Client.
Enter the following details:
Client ID:
ds-password-sync-plugin
Client secret:
ds-password-sync-plugin
Scopes:
fr:idm:*, openid, am-introspect-all-tokens, am-introspect-all-tokens-any-realm
Click Create.
On the Advanced tab:
Token Endpoint Authentication Method: Select
client_secret_basic
.Grant Types: Add
Client Credentials
.
Click Save Changes.
If you haven't performed the following procedures, do that now:
Add
openidm-localhost
to theidm.default
mapping alias array in your project'sconf/secrets.json
file:"mappings": [ { "secretId": "idm.default", "types": [ "ENCRYPT", "DECRYPT" ], "aliases": [ "&{openidm.config.crypto.alias|openidm-sym-default}", "openidm-localhost" ] }, ... ]
Log in to the IDM Admin UI as
amAdmin
and create a new managed/user:From the navigation bar of the Admin UI, select Manage > User, and then click + New User.
On the New User page, enter the Username
ds-password-sync-plugin
, other information, as necessary, and click Save.On the ds-password-sync-plugin user page, select the Authorization Roles tab.
Click Add Authorization Roles, select all of the following roles, and then click Add:
openidm-admin
openidm-authorized
openidm-cert
openidm-reg
Add a
staticUserMapping
for theds-password-sync-plugin
user to theconf/authentication.json
file:{ "subject" : "ds-password-sync-plugin", "localUser" : "managed/user/ds-password-sync-plugin", "roles" : [ "internal/role/openidm-authorized", "internal/role/openidm-admin" ] }
Installing and Configuring the DS Password Synchronization Plugin
The following steps install the password synchronization plugin on a DS directory server that is running on the same host as IDM (localhost). If you are running DS on a different host, use the fully qualified domain name instead of localhost
.
You must use the plugin version that corresponds to your IDM and DS versions. For more information, see "Supported Password Synchronization Plugins". This procedure assumes that you are using IDM 7.1, DS 7.1, and version 7.1 of the password synchronization plugin.
Depending on whether you are using IDM with AM, select one of the following plugin installation and configuration procedures:
Extract the .zip file contents to the DS installation directory:
unzip ~/Downloads/
DS-IDM-account-change-notification-handler-7.1.zip
-d /path/to/opendj/Restart DS to load the additional schema from the password synchronization plugin:
/path/to/opendj/bin/stop-ds --restart
Stopping Server... ...msg=Loaded extension from file '/path/to/opendj/lib/extensions/opendj-openidm-account-change-notification-handler-7.1.jar' ... ...msg=The Directory Server has started successfully
Configure the password synchronization plugin:
/path/to/opendj/bin/dsconfig \ create-account-status-notification-handler \ --type openidm \ --handler-name "OpenIDM Notification Handler" \ --set enabled:true \ --set openidm-url:https://openidm-localhost:8444/openidm/managed/user \ --set private-key-alias:openidm-localhost \ --set certificate-subject-dn:"CN=openidm-localhost, O=OpenIDM Self-Signed Certificate, OU=None, L=None, ST=None, C=None" \ --set ssl-cert-nickname:ssl-key-pair \ --set key-manager-provider:PKCS12 \ --set trust-manager-provider:PKCS12 \ --set password-attribute:password \ --set attribute-type:entryUUID \ --set attribute-type:uid \ --set query-id:for-userName \ --set log-file:logs/pwsync \ --set update-interval:5s \ --set request-retry-attempts:5000 \ --hostname localhost \ --port 4444 \ --bindDn uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --no-prompt
The Openidm Account Status Notification Handler was created successfully
Adapt the settings to match your DS and IDM deployments:
Setting Details enabled
Enables the plugin.
Leave this setting as shown.
openidm-url
The endpoint where the plugin finds IDM managed user accounts.
Port
8444
is the IDM default for mutual TLS connections.private-key-alias
The IDM private key, used to decrypt the JSON objects from DS that contain passwords.
The example references the default IDM private key of the self-signed key pair generated at setup time.
certificate-subject-dn
The certificate subject DN for the IDM public key.
The DS plugin encrypts JSON objects with the IDM public key, so this must match the certificate for the IDM private key specified for the
private-key-alias
property.The example shows the subject DN of the default IDM self-signed certificate.
ssl-cert-nickname
The alias of the DS TLS certificate used to authenticate to IDM.
The example uses the default DS server certificate generated at setup time.
key-manager-provider
The provider for the keystore where DS finds its TLS key pair specified in
ssl-cert-nickname
.The example uses the default DS provider configured at setup time.
trust-manager-provider
The provider for the keystore where DS finds the IDM public key specified in
certificate-subject-dn
.The example uses the default DS provider configured at setup time, and updated in "Enable DS to Trust the IDM Certificate".
password-attribute
The name of the password field in the JSON that DS sends to IDM for a password change.
This attribute type must be defined in the managed object schema in IDM, and it must have either the user password or auth password syntax.
attribute-type
LDAP attributes that the DS plugin sends to IDM with the password. IDM can use these to uniquely identify the user, even if the user's account has moved.
If no attribute types are specified, DS sends only the DN and the new password to IDM.
query-id
The query-id for the patch-by-query request.
Leave this setting as shown.
log-file
The DS directory where the plugin writes log files containing encrypted passwords before notifying IDM.
This setting has no effect in the example, where the
update-interval
is zero seconds.update-interval
The interval at which the DS plugin sends password changes to IDM.
If this value is zero, the plugin sends updates synchronously. No encrypted passwords are stored in the configured
log-file
directory. The plugin does not retry failed requests, irrespective of therequest-retry-attempts
setting.request-retry-attempts
The number of times the plugin attempts a synchronization request if the first attempt fails. If this value is zero, the request is not retried. If the value is greater than zero, the plugin retries the specified number of times before giving up and removing the request from its queue.
When a request fails due to a transient condition, such as failure to contact IDM, or a connection timeout, the plugin does not decrement the number of retry attempts. The plugin logs a message with the reason the request failed, and continues to retry until IDM responds.
Restart DS for the new configuration to take effect:
/path/to/opendj/bin/stop-ds --restart
Update DS password policies to use the password synchronization plugin.
The following example updates the default DS password policy:
/path/to/opendj/bin/dsconfig \ set-password-policy-prop \ --policy-name "Default Password Policy" \ --set account-status-notification-handler:"OpenIDM Notification Handler" \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --no-prompt
For details on configuring DS password policies, see Passwords in the DS Security Guide.
The password synchronization plugin uses client certificate authentication to authenticate to IDM. You must also update your security configuration to add the IDM key alias.
If your authentication configuration does not already include client certificate authentication, configure it as follows:
Add the
CLIENT_CERT
authentication module to your authentication configuration.Set the
allowedAuthenticationIdPatterns
property to the certificate DN of the DS SSL certificate (ssl-key-pair
by default).Add
internal/role/openidm-cert
to the array ofdefaultUserRoles
.
The following example assumes that you are using the default DS
ssl-key-pair
certificate that has a certificate subject DN ofCN=DS, O=ForgeRock
:"authModules" : [ ... { "name" : "CLIENT_CERT", "properties" : { "queryOnResource" : "managed/user", "defaultUserRoles" : [ "internal/role/openidm-cert", "internal/role/openidm-authorized" ], "allowedAuthenticationIdPatterns" : [ ".*CN=DS, O=ForgeRock.com.*" ] }, "enabled" : true }, ... ]
For more information about client certificate authentication, see "CLIENT_CERT".
Update the IDM secret store (
conf/secrets.json
) to add the alias used in theprivate-key-alias
plugin setting to theidm.default
secretId:"mappings": [ { "secretId" : "idm.default", "types": [ "ENCRYPT", "DECRYPT" ], "aliases": [ "&{openidm.config.crypto.alias|openidm-sym-default}", "openidm-localhost" ] }, ... ]
For more information about secret stores, see "Configuring Secret Stores".
Extract the .zip file contents to the DS identity store installation directory:
unzip ~/Downloads/
DS-IDM-account-change-notification-handler-7.1.zip
-d /path/to/opendj-identity/Configure the password synchronization plugin to use AM bearer token authentication:
/path/to/opendj-identity/bin/dsconfig \ create-account-status-notification-handler \ --type openidm \ --handler-name "OpenIDM Notification Handler" \ --set certificate-subject-dn:"CN=openidm-localhost,O=OpenIDM Self-Signed Certificate,OU=None,L=None,ST=None,C=None" \ --set enabled:true \ --set attribute-type:entryUUID \ --set attribute-type:uid \ --set trust-manager-provider:PKCS12 \ --set key-manager-provider:PKCS12 \ --hostname identities.example.com \ --port 4445 \ --bindDn uid=admin \ --trustAll \ --bindPassword str0ngAdm1nPa55word \ --set log-file:logs/pwsync \ --set password-attribute:password \ --set query-id:for-userName \ --set private-key-alias:openidm-localhost \ --set openidm-url:https://openidm-localhost:8445/openidm/managed/user \ --set oauth2-access-token-url:http://am.example.com:8080/openam/oauth2/realms/root/access_token \ --set oauth2-scope:"openid fr:idm:*" \ --set oauth2-client-id:ds-password-sync-plugin \ --set oauth2-client-secret:ds-password-sync-plugin \ --set request-retry-attempts:5000 \ --set update-interval:5s \ --no-prompt
The Openidm Account Status Notification Handler was created successfully
Note
Adapt the above settings to match your DS, IDM, and AM deployments.
Restart DS for the new configuration to take effect:
/path/to/opendj-identity/bin/stop-ds --restart
Configure the DS password policy to use the password synchronization plugin. The following example updates the default DS password policy:
/path/to/opendj-identity/bin/dsconfig \ set-password-policy-prop \ --policy-name "Default Password Policy" \ --set account-status-notification-handler:"OpenIDM Notification Handler" \ --hostname identities.example.com \ --port 4445 \ --bindDN uid=admin \ --bindPassword str0ngAdm1nPa55word \ --usePkcs12TrustStore /path/to/opendj-identity/config/keystore \ --trustStorePasswordFile /path/to/opendj-identity/config/keystore.pin \ --no-prompt
For details on configuring DS password policies, see Passwords in the DS Security Guide.
Generate an AM bearer token. For example:
curl -k \ --request POST \ --user "ds-password-sync-plugin:ds-password-sync-plugin" \ --data "grant_type=client_credentials" \ --data "scope=openid fr:idm:*" \ "http://am.example.com:8080/openam/oauth2/realms/root/access_token"
{ "access_token": "access_token", "scope": "openid fr:idm:*", "id_token": "id_token", "token_type": "Bearer", "expires_in": 3599 }
Optionally, to test the AM bearer token, create a new managed user using the token as the authorization. For example:
curl -v \ --header "Authorization: Bearer access_token" \ --header "accept: application/json" \ --header "Accept-API-Version: resource=1.0" \ --header "Content-Type: application/json" \ --request POST "http://openidm-localhost:8081/openidm/managed/user?_action=create" \ --data '{"userName":"jdoe", "password": "6fNcHgBF", "mail": "jdoe@example.com", "sn": "Doe", "givenName": "Jane"}'
{ "_id": "7884b8ab-a226-4ee5-b9b9-0718f5a19335", "_rev": "00000000f527116e", "userName": "jdoe", "accountStatus": "active", "givenName": "Jane", "sn": "Doe", "mail": "jdoe@example.com" }
Trying the DS Password Synchronization Plugin
With the plugin installed and configured, and with secure communications enabled between DS and IDM, you can test that the setup has been successful as follows:
Change a user password in DS:
/path/to/opendj/bin/ldappasswordmodify \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --bindDN uid=admin \ --bindPassword password \ --authzID dn:uid=bjensen,ou=people,dc=example,dc=com \ --newPassword Chngth5pwd
The LDAP password modify operation was successful
The message
The LDAP password modify operation was successful
only indicates that the password change succeeded for DS. This does not mean that DS has propagated the change to IDM.When you have successfully updated the password in DS, DS attempts to synchronize the change to the corresponding IDM managed user account.
You should now be able to log in to the Self Service UI (https://localhost:8443/#login/) as that user ID, with the new password.
Updating the DS Password Synchronization Plugin
Additional steps may be necessary when updating the DS password synchronization plugin after upgrading DS. Check the corresponding Knowledge Base article for more information.
Uninstalling the DS Password Synchronization Plugin
To uninstall the plugin, change the DS configuration as follows:
Reset your DS password policy configuration so that it no longer uses the password synchronization plugin.
The following command resets the default password policy:
/path/to/opendj/bin/dsconfig \ set-password-policy-prop \ --policy-name "Default Password Policy" \ --reset account-status-notification-handler \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --no-prompt
Delete the IDM Notification Handler from the DS configuration:
/path/to/opendj/bin/dsconfig \ delete-account-status-notification-handler \ --handler-name "OpenIDM Notification Handler" \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePasswordFile /path/to/opendj/config/keystore.pin \ --no-prompt
The Account Status Notification Handler was deleted successfully
Remove the password synchronization plugin from the DS extensions:
rm /path/to/opendj/lib/extensions/opendj-openidm-account-change-notification-handler*
Restart DS for the new configuration to take effect:
/path/to/opendj/bin/stop-ds --restart