OpenAM provides built in support for OATH authentication (not to be confused with OAuth, which is a different kettle of fish altogether).
OATH defines an open standard for One Time Password (OTP) generators. These can be HMAC Hash based (HOTP), or time based (TOTP).
Google Authenticator is a free application that you can download for your Android or iOS device that provides an implementation of the OATH TOTP standard. It turns out to be surprisingly easy to configure Google Authenticator to work with OpenAM.
Let's walk through the steps.
We will configure this in a realm called "test". Realm's are a kick butt feature of OpenAM that allows us to create isolated administration, data store and policy domains. A common use would be to configure separate environments for customers and employees, but realms are also great for creating test environments.
Navigate to your test realm, click on the "Authentication Tab". Under "Modules" edit the OATH module. It should look something like this:
The key attributes we need to set for Google Authenticator are:
- Auth Level. This is a higher strength multi-factor module, so we assign a value of 10 here.
- One Time Password Length: This is the length of the OTP that will be displayed by the Google Authenticator application. Six is the default for Authenticator.
- Minimum secret key length: I used 8 for this example, which is too short for production. This is the length (in hex characters) of the encoded secret.
- Secret Key Attribute: This is the name of the ldap attribute where the secret key is stored. For this example I am using the "title" attribute. This isn't a great choice, and for production you would extend your ldap schema with a dedicated attribute.
- OATH Algorithm: TOTP for Google Authenticator
- Last Login Time Attribute: The OATH TOTP module needs to store the last login timestamps (UNIX long time) in this attribute. I am using "description" but again you should extend your schema with a dedicated attribute.
You will want to ensure that the attributes chosen above are fetched by OpenAM. Navigate to your datastore configuration for the realm and make sure that "LDAP User Attributes" contains the two attributes you have configured in the OATH module.
Now that we have configured the OATH module, we need to modify the default ldapService chain to use the new module:
The above chain will first authenticate the user against the Datastore (i.e. ldap username/password), and if that is successful will pass them on to the OATH module. Both modules are "REQUIRED" - so the user must pass through both to authenticate.
Registering the Shared Secret
Before we can test this out, we need to seed our LDAP with the shared secret. The OpenAM server and Google Authenticator must share a common secret to authenticate the user. Briefly, the way this works is that the Authenticator client will hash the current time using the shared secret to obtain a OTP. The server will do the same and compare the results with the OTP entered by the user.
For convenience the easiest way to register a secret with the Authenticator application is to use a QR code. The user simply scans the generated QR code to setup the account. The same secret is registered with the LDAP server.
Ideally we would have a nice registration page that handles this - but for now we will do this manually.
The tricky bit is the encoding of the secret for storage. The secret key stored in LDAP is the Base16 encoded value of the secret. For generating a QR code for scanning, we must use the Base32 encoding.
Using the example below:
Shared Secret: "hello" (without the quotes)
Base16 encoded value: 68656C6C6F (http://online-calculators.appspot.com/base16/ to generate this)
Base32 encoded value: NBSWY3DP (http://online-calculators.appspot.com/base32/ )
To register the QR code we create a special URL of the form:
Where the secret is the Base32 encoded value that we determined above. This URL can be pasted into a QR generator (http://goqr.me/ for example) and scanned into your Google Authenticator application. Here is an example:
We can use an LDAP Client such as Apache Studio to register the base 16 encoded secret:
Let's give it a whirl! Navigate to the login page for your realm. For example http://openam.example.com:8080/openam/XUI/#login/test
You will first see the LDAP module challenge:
Followed by the OTP challenge:
Enter the OTP displayed by your Google Authenticator Application. You should be authenticated and redirected to the profile landing page.
TroubleshootingIf you run into problems enable the debug log at message level (Configuration -> Servers and Sites -> your server url -> Debugging). Look for messages with "oath" in the string.
The logs are under your openam config directory (openam-config/openam/debug).