Thursday, 16 November 2017

Using IDM and DS to synchronise hashed passwords


In this post I will describe a technique for synchronising a hashed password from ForgeRock IDM to DS.
Out of the box, IDM has a Managed User object that encrypts a password in symmetric (reversible) encryption.  One reason for this is that sometimes it is necessary to pass, in clear text, the password to a destination directory in order for it to perform its own hashing before storing it.  Therefore the out of the box synchronisation model for IDM is take the encrypted password from its own store, decrypt it, and pass it in clear text (typically over a secure channel!) to DS for it to hash and store.
You can see this in the samples for IDM.

However, there are some times when storing an encrypted, rather than hashed, value for a password is not acceptable.  IDM includes the capability to hash properties (such as passwords) not just encrypt them.  In that scenario, given that password hashes are one way, it's not possible to decrypt the password before synchronisation with other systems such as DS.

Fortunately, DS offers the capability of accepting pre-hashed passwords so IDM is able to pass the hash to DS for storage.  DS obviously needs to know this value is a hash, otherwise it will try to hash the hash!

So, what are the steps required?

  1. Ensure that DS is configured to accept hashed passwords.
  2. Ensure the IDM data model uses 'Hashing' for the password property.
  3. Ensure the IDM mapping is setup correctly

Ensure DS is configured to accept hashed passwords

This topic is covered excellently by Mark Craig in this article here:

I'm using ForgeRock DS v5.0 here, but Mark references the old name for DS (OpenDJ) because this capability has been around for a while.  The key thing to note about the steps in the article is that you need the allow-pre-encoded-passwords advanced password policy property to be set for the appropriate password policy.  I'm only going to be dealing with one password policy - the default one - so Mark's article covers everything I need.

(I will be using a Salted SHA-512 algorithm so if you want to follow all the steps, including testing out the change of a user's password, then specify {SSHA512} in the userPassword value, rather than {SSHA}.  This test isn't necessary for the later steps in this article, but may help you understand what's going on).

Ensure IDM uses hashing

Like everything in IDM, you can modify configuration by changing the various config .json files, or the UI (which updates the json config files!)
I'll use IDM v5.0 here and show the UI.

By default, the Managed User object includes a password property that is defined as 'Encrypted':
We need to change this to be Hashed:

And, I'm using the SHA-512 algorithm here (which is a Salted SHA-512 algorithm).

Note that making this change does not update all the user passwords that exist.  It will only take effect when a new value is saved to the property.

Now the value of a password, when it is saved, is string representation of a complex JSON object (just like it is when encrypted) but will look something like:

Ensure IDM Mapping is setup correctly

Now we need to configure the mapping.
As you may have noted in the 1st step, DS is told that the password is pre-hashed by the presence of {SSHA512} at the beginning of the password hash value.  Therefore we need a transformation script that takes the algorithm and hash value from IDM and concatenates it in a way suited for DS.
The script is fairly simple, but does need some logic to convert the IDM algorithm representation: SHA-512 into the DS representation: {SSHA512}
This is the transformation script (in groovy) I used (which can be extended of course for other algorithms):
String strHash;
if (source.$crypto.value.algorithm == "SHA-512" ) {
  strHash = "{SSHA512}" + source.$

This script replaces the default IDM script that does the decryption of the password.
(You might want to extend the script to cope with both hashed and encrypted values of passwords if you already have data.  Look at functions such as openidm.isHashed and openidm.isEncrypted in the IDM Integrators Guide).

Now when a password is changed, the password is stored in hashed form in IDM.  Then the mapping is triggered to synchronise to DS applying the transformation script that passes the pre-hashed password value.

Now there is no need to store passwords in reversible encryption!

Wednesday, 21 June 2017

ForgeRock Self-Service Custom Stage


A while ago I blogged an article describing how to add custom stages to the ForgeRock IDM self-service config.  At the time I used the sample custom stage available from the ForgeRock Commons Self-Service code base.  I left it as a task for the reader to build their own stage!  However, I recently had cause to build a custom stage for a proof of concept I was working on.

It's for IDM v5 and I've detailed the steps here.

Business Logic

The requirement for the stage was to validate that a registering user had ownership of the provided phone number.  The phone number could be either a mobile or a landline.  The approach taken was to use Twilio (a 3rd party) to send out either an SMS to a mobile, or text-to-speech to a landline.  The content of the message is a code based on HOTP.

Get the code for the module

Building the module

Follow the instructions in

After deploying the .jar file you must restart IDM for the bundle to be correctly recognised.

The module is targeted for IDMv5.  It uses the maven repositories to get the binary dependencies.
See this article in order to access the ForgeRock 'private-releases' maven repo:

It also uses appropriate pom.xml directives to ensure the final .jar file is packaged as an OSGi bundle so that it can be dropped into IDM

Technical details

The code consists of a few files.  The first two in this list a the key files for any stage.  They implement the necessary interfaces for a stage.  The remaining files are the specific business logic for this stage.
  •  This class manages reading the configuration data from the configuration file.  It simply represents each configuration item for the stage as properties of the class.
  •  This is main orchestration file for the stage.  It copes with both registration and password reset scenarios.  It manages the 'state' of the flow within this stage and generates the appropriate callbacks to user, but relies on the other classes to do the real code management work.  If you want to learn about the way a 'stage' works then this is file to consider in detail.
  •  This is taken from the OATH Initiative work and is unchanged by me.  It is a java class to generate a code based on the HOTP algorithm.
  • This class manages the process of sending the code.  It generates the code then decides whether to send it using SMS or TTS.  (In the UK, all mobile phone numbers start 07... so it's very simple logic for my purpose!)  This class also provides a method to validate the code entered by the user.  
  •  The class provides the utility functions that interact directly with the Twilio APIs for sending either an SMS or TTS


There are also two sample config files for registration and password reset.  You should include the JSON section relating to this class in your self-service configuration files for IDM.
For example:
            "class" : "org.forgerock.selfservice.twilio.TwilioStageConfig",
            "codeValidityDuration" : "6000",
            "codeLength" : "5",
            "controlUrl" : "",
            "fromPhone" : "+441412803033",
            "accountSid" : "<Enter accountSid>",
            "tokenId" : "<Enter tokenId>",
            "telephoneField" : "telephoneNumber",
            "skipSend" : false

Most configuration items should be self explanatory.  However, the 'skipSend' option is worthy of special note.  This, when true, will cause the stage to avoid calling the Twilio APIs and instead return the code as part of the callback data.  This means that if you're using the OOTB UI then the 'placeholder' HTML attribute of the input box will tell you the code to enter.  This is really useful for testing this stage if you don't have access to a Twilio account as this also ignores the Twilio account specific configuration items.

Of course, now you need to deploy it as per my previous article!