Solutions

AM 6.0.0.x removes username from shared state in authentication nodes when it is not found

Last updated Nov 12, 2018

The purpose of this article is to provide a solution for use cases that have users belonging to different LDAP identity stores which require credentials to be shared between nodes within an AM authentication tree. For example, you require similar behavior to shared state with authentication chains, where credentials are passed through the modules in the chain so users do not have to re-enter their credentials.


Symptoms

The username is removed from the shared state, which prevents authentication in a second node. 

The following errors are shown in the Authentication debug log when this happens:

  • Data Store Decision node:
    amAuthInternalSMModule:10/11/2018 03:37:44:344 PM BST: <SKIP>
    SMSAuthModule::login() From shared state: Username: user.10 Password: <present>
    amAuthInternalSMModule:10/11/2018 03:37:44:344 PM BST: <SKIP>
    SMSAuthModule::login() For authentication: Username: user.10 Password: <present>
    amAuth:10/11/2018 03:37:44:344 PM BST: <SKIP>
    WARNING: invalid username error
    amAuth:10/11/2018 03:37:44:344 PM BST: <SKIP>
    newSharedState {realm=/, authLevel=0}
    
  • LDAP Decision node:
    amAuth:10/11/2018 03:37:44:253 PM BST: <SKIP>
    Connecting to [http://opendj.example.com:1389]
    Searching dc=example,dc=com for (uid=demo)
    scope = sub
    amAuth:10/11/2018 03:37:44:253 PM BST:  <SKIP>
    userAttrSize is : 1
    amAuth:10/11/2018 03:37:44:261 PM BST:  <SKIP>
    Cannot find entries for (uid=demo)
    amAuth:10/11/2018 03:37:44:261 PM BST:  <SKIP>
    loginState userNotFound
    amAuth:10/11/2018 03:37:44:261 PM BST:  <SKIP>
    newSharedState {realm=/, authLevel=0}
    

Expected behavior

Similar behavior to shared state with authentication chains, where credentials are passed through the modules in the chain so users do not have to re-enter their credentials.

For example, if you have two groups of users belonging to two different LDAP identity stores and want them to authenticate without having to enter their credentials twice. This type of scenario was possible using chains and modules, where you could configure one LDAP module for the first store and another LDAP module for the second store, add them both to a chain (with the first being SUFFICIENT and the second one REQUIRED) and then add options to enable sharedState and use, for example, TryFirstPass.

Recent Changes

Upgraded to, or installed AM 6.0.0.x.

Implemented authentication trees.

Causes

Authentication data is held in two different storage mechanisms in trees:

  • The shared state (similar to how authentication modules work) keeps information available to all subsequent nodes in the tree.
  • The transient state keeps information like the password and keys; this content is only available until the authentication flow reaches the next node requiring user interaction. See the following description of the Password Collector Node in the Admin Guide:

The Password Collector authentication node prompts the user to enter their password. The captured password is transient, persisting only until the authentication flow reaches the next node requiring user interaction.

When the outcome of a decision node (for example the LDAP Decision node or Data Store Decision node) is false, the user name is removed from the shared state, which means it cannot be reused in a second decision node. The following known issues exist:

Solution

Caution

Disclaimer for the following code samples, please review before implementing these scripts. These scripts are just samples and will need customizing to fit your use case. Creating scripted nodes is outside the scope of ForgeRock support; if you want more tailored advice, consider engaging Professional Services.  

You can workaround this issue by utilizing Scripted Decision nodes. For example, consider the following common scenario: Two groups of users belong to two different LDAP identity stores. The tree should collect their credentials, validate the credentials using one LDAP Decision node. If the outcome is false, it should validate the credentials with the next LDAP Decision node, without requesting credentials from the user again.

You can address this scenario by creating two scripted Decision nodes:

  • shareUsername - saves the user name in a shared state under another variable name, which makes the user name available to all the nodes in the tree regardless of what happened previously in the authentication flow.
  • retrieveUsername - retrieves the user name and adds it to the shared state, which allows the following decision node to access the user name.

You can use these scripted Decision nodes as follows:

  1. Create a script for sharing the user name by navigating to Realms > [Realm Name] > Scripts and clicking New Script. Enter a name for your script ("share username" in this example) and select Decision node script for authentication trees as the script type.
  2. Specify the script, for example:
    var shareduser=sharedState.get("username")
    sharedState.put("shareduser",shareduser);
    
    outcome = "true";
    
    This example script takes the user name content and adds it to a local variable called shareduser; the shareduser variable is then added to the shared state, so that it can be used by any node during the authentication process.
  3. Create a script for retrieving the user name by navigating to Realms > [Realm Name] > Scripts and clicking New Script. Enter a name for your script ("retrieve username" in this example) and select Decision node script for authentication trees as the script type.
  4. Specify the script, for example:
    var username = sharedState.get("shareduser");
    sharedState.put("username",username);
    
    outcome = "true";
    
    This example script retrieves the shareduser value and stores it in a local variable called username and then adds the user name to the shared state.
Note

Using the variable name username is critical here as it is the variable name that the LDAP and DataStore nodes expect when retrieving the name of the user. Additionally, you should only use this script in front of a node that needs the user name in case the user name was removed previously.

  1. Create a tree for your specific authentication flow ensuring you incorporate two Scripted Decision nodes that utilize the scripts you created in the preceding steps. The Outcomes for these nodes should be set to true. 

Example

A basic tree that includes these Scripted Decision nodes would look like this:

You should adapt this tree to your needs, test it thoroughly and ensure the correct security features are added, according to your security team guidelines.

See Also

Best practice for migrating Authentication Chains to Trees in AM 6

How do I automate the creation of an authentication tree in AM 5.5.x and 6.x?

Authentication trees in AM

Authentication and Single Sign-On Guide › About Authentication Trees

Authentication and Single Sign-On Guide › Configuring Authentication Trees

Related Training

N/A

Related Issue Tracker IDs

OPENAM-13531 (LDAP Decision node removes username from shared state when it is not found)

OPENAM-13530 (Datastore Decision node removes username from shared state when it is not found )

OPENAM-13217 (make transient state available to scripted node type)



Copyright and TrademarksCopyright © 2018 ForgeRock, all rights reserved.
Loading...