Authentication trees in AM

This book provides information on authentication trees in AM.


How do I create an authentication tree in AM 5.5.x, 6.x and 7.x using REST or Amster?

The purpose of this article is to provide information on creating an authentication tree using either the REST API or Amster in AM.

Overview

When creating authentication trees using either the REST API or Amster, you should be aware of the following key points:

  • You must re-create each node in order to create a new authentication tree.
  • Each node must have a valid UUID as its identifier; you can generate UUIDs online, for example: Online UUID Generator. If you don't use a valid UUID, authentication will fail and you will see an error similar to the following in the Authentication debug log: ERROR: Could not get SMS service: authenticationTreesService java.lang.IllegalArgumentException: Invalid UUID string: 12345
  • The entryNodeId field specified when creating the authentication tree is the UUID of the first node in the tree.
  • The outcome field specified when creating the authentication tree is the UUID of the next node; in this way you can move between the nodes.
  • The Success/Failure nodes have static UUIDs that remain constant across all authentication trees and AM versions. These UUIDs are as follows:
    • Success node: 70e691a5-1e33-4ac3-a356-e7b6d60d92e0
    • Failure node: e301438c-0bd0-429c-ab0c-66126501069a
Note

There are known issues that prevent custom nodes being created via Amster: OPENAM-13157 (Custom Authentication Nodes not being exported correctly) and OPENAM-14008 (creating custom auth node fails with amster). As a result, you should create custom nodes via REST instead.

The following sections provide examples for creating a simple tree that consists of three nodes (UsernameCollectorNode, PasswordCollectorNode and DataStoreDecisionNode):

The resulting tree created from these examples looks like this:

Creating a tree using the REST API

Note

Please observe the following when constructing REST calls:

  • Make the REST call to the actual AM/OpenAM server URL (not lb).
  • Change the name of the iPlanetDirectoryPro header to the name of your actual session cookie.
  • Set this session cookie header to the token returned when you authenticated.
  • Ensure the Accept-API-Version header contains valid resource versions (AM 5 and later).

See How do I avoid common issues with REST calls in AM (All versions)? for further information.

The following example demonstrates creating the authentication tree using the REST API:

  1. Generate UUIDs for each of the nodes you want to create. For example:
    • UsernameCollectorNode: 8f9d2280-caa7-433f-93a9-1f64f4cae60a
    • PasswordCollectorNode: 54f14341-d1b7-436f-b159-d1f9b6c626eb
    • DataStoreDecisionNode: 3fc7ce22-fc79-4131-85f2-f1844709d042
  2. Authenticate as an admin user. For example: $ curl -X POST -H "X-OpenAM-Username: amadmin" -H "X-OpenAM-Password: cangetinam" -H "Content-Type: application/json" -H "Accept-API-Version: resource=2.1" http://host1.example.com:8080/openam/json/realms/root/authenticate?authIndexType=service&authIndexValue=adminconsoleservice Example response: { "tokenId": "AQIC5wM2LY4SfcxsuvGEjcsppDSFR8H8DYBSouTtz3m64PI.*AAJTSQACMDIAAlNLABQtNTQwMTU3NzgxODI0NzE3OTIwNAEwNDU2NjE0*", "successUrl": "/openam/console", "realm": "/" }
  3. Create the UsernameCollector node using the following curl command, where the UUID is the one you generated: $ curl -X PUT -H "iPlanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*" -H "Content-Type: application/json" -H "Accept-API-Version: resource=1.0" -H "If-None-Match: *" -d '{"_id":"8f9d2280-caa7-433f-93a9-1f64f4cae60a","_type":{"_id":"UsernameCollectorNode","name":"Username Collector"}}' 'http://host1.example.com:8080/openam/json/realms/root/realms/employees/realm-config/authentication/authenticationtrees/nodes/UsernameCollectorNode/8f9d2280-caa7-433f-93a9-1f64f4cae60a' Example response: {"_id":"8f9d2280-caa7-433f-93a9-1f64f4cae60a","_type":{"_id":"UsernameCollectorNode","name":"Username Collector","collection":true}}
  4. Create the PasswordCollector node using the following curl command, where the UUID is the one you generated: $ curl -X PUT -H "iPlanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*" -H "Content-Type: application/json" -H "Accept-API-Version: resource=1.0" -H "If-None-Match: *" -d '{"_id":"54f14341-d1b7-436f-b159-d1f9b6c626eb","_type":{"_id":"PasswordCollectorNode","name":"Password Collector"}}' 'http://host1.example.com:8080/openam/json/realms/root/realms/employees/realm-config/authentication/authenticationtrees/nodes/PasswordCollectorNode/54f14341-d1b7-436f-b159-d1f9b6c626eb' Example response: {"_id":"54f14341-d1b7-436f-b159-d1f9b6c626eb","_type":{"_id":"PasswordCollectorNode","name":"Password Collector","collection":true}}
  5. Create the DataStoreDecision node using the following curl command, where the UUID is the one you generated: $ curl -X PUT -H "iPlanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*" -H "Content-Type: application/json" -H "Accept-API-Version: resource=1.0" -H "If-None-Match: *" -d '{"_id":"3fc7ce22-fc79-4131-85f2-f1844709d042","_type":{"_id":"DataStoreDecisionNode","name":"Data Store Decision"}}' 'http://host1.example.com:8080/openam/json/realms/root/realms/employees/realm-config/authentication/authenticationtrees/nodes/DataStoreDecisionNode/3fc7ce22-fc79-4131-85f2-f1844709d042' Example response: {"_id":"3fc7ce22-fc79-4131-85f2-f1844709d042","_type":{"_id":"DataStoreDecisionNode","name":"Data Store Decision","collection":true}}
  6. Create the authentication tree with these three nodes, where the UUIDs are the ones you used to create the nodes. Ensure you set entryNodeId to the UUID of the first node and set the outcome of each node to the UUID of the next node. For example: $ curl -X PUT -H "iPlanetDirectoryPro: AQIC5wM2LY4Sfcxs...EwNDU2NjE0*" -H "Content-Type: application/json" -H "Accept-API-Version: resource=1.0" -H "If-None-Match: *" -d '{"entryNodeId":"8f9d2280-caa7-433f-93a9-1f64f4cae60a","nodes":{"8f9d2280-caa7-433f-93a9-1f64f4cae60a":{"displayName":"Username Collector","nodeType":"UsernameCollectorNode","connections":{"outcome":"54f14341-d1b7-436f-b159-d1f9b6c626eb"}},"54f14341-d1b7-436f-b159-d1f9b6c626eb":{"displayName":"Password Collector","nodeType":"PasswordCollectorNode","connections":{"outcome":"3fc7ce22-fc79-4131-85f2-f1844709d042"}},"3fc7ce22-fc79-4131-85f2-f1844709d042":{"displayName":"Data Store Decision","nodeType":"DataStoreDecisionNode","connections":{"false":"e301438c-0bd0-429c-ab0c-66126501069a","true":"70e691a5-1e33-4ac3-a356-e7b6d60d92e0"}}}}' 'http://host1.example.com:8080/openam/json/realms/root/realms/employees/realm-config/authentication/authenticationtrees/trees/MyNewAuthTree' Example response: {"entryNodeId":"8f9d2280-caa7-433f-93a9-1f64f4cae60a","nodes":{"8f9d2280-caa7-433f-93a9-1f64f4cae60a":{"nodeType":"UsernameCollectorNode","displayName":"Username Collector","connections":{"outcome":"54f14341-d1b7-436f-b159-d1f9b6c626eb"}},"54f14341-d1b7-436f-b159-d1f9b6c626eb":{"nodeType":"PasswordCollectorNode","displayName":"Password Collector","connections":{"outcome":"3fc7ce22-fc79-4131-85f2-f1844709d042"}},"3fc7ce22-fc79-4131-85f2-f1844709d042":{"nodeType":"DataStoreDecisionNode","displayName":"Data Store Decision","connections":{"false":"e301438c-0bd0-429c-ab0c-66126501069a","true":"70e691a5-1e33-4ac3-a356-e7b6d60d92e0"}}},"_id":"MyNewAuthTree"}

Creating a tree using Amster

The following example demonstrates creating the authentication tree using Amster:

  1. Generate UUIDs for each of the nodes you want to create. For example:
    • UsernameCollectorNode: 8f9d2280-caa7-433f-93a9-1f64f4cae60a
    • PasswordCollectorNode: 54f14341-d1b7-436f-b159-d1f9b6c626eb
    • DataStoreDecisionNode: 3fc7ce22-fc79-4131-85f2-f1844709d042
  2. Create the UsernameCollector node: $ create UsernameCollector --realm employees --id 8f9d2280-caa7-433f-93a9-1f64f4cae60a --body '{"_id":"8f9d2280-caa7-433f-93a9-1f64f4cae60a","_type":{"_id":"UsernameCollectorNode","name":"Username Collector"}}' ===> { "_rev": "1086377982", "_type": { "_id": "UsernameCollectorNode", "name": "Username Collector", "collection": true }, "_id": "8f9d2280-caa7-433f-93a9-1f64f4cae60a" }
  3. Create the PasswordCollector node: $ create PasswordCollector --realm employees --id 54f14341-d1b7-436f-b159-d1f9b6c626eb --body '{"_id":"54f14341-d1b7-436f-b159-d1f9b6c626eb","_type":{"_id":"PasswordCollectorNode","name":"Password Collector"}}' ===> { "_rev": "-747204328", "_type": { "_id": "PasswordCollectorNode", "name": "Password Collector", "collection": true }, "_id": "54f14341-d1b7-436f-b159-d1f9b6c626eb" }
  4. Create the DataStoreDecision node: $ create DataStoreDecision --realm employees --id 3fc7ce22-fc79-4131-85f2-f1844709d042 --body '{"_id":"3fc7ce22-fc79-4131-85f2-f1844709d042","_type":{"_id":"DataStoreDecisionNode","name":"Data Store Decision"}}' ===> { "_rev": "756753534", "_type": { "_id": "DataStoreDecisionNode", "name": "Data Store Decision", "collection": true }, "_id": "3fc7ce22-fc79-4131-85f2-f1844709d042" }
  5. Create the authentication tree with these three nodes, where the UUIDs are the ones you used to create the nodes. Ensure you set entryNodeId to the UUID of the first node and set the outcome of each node to the UUID of the next node. For example: $ create AuthTree --realm employees --id MyNewAuthTree --body '{"entryNodeId":"8f9d2280-caa7-433f-93a9-1f64f4cae60a","nodes":{"8f9d2280-caa7-433f-93a9-1f64f4cae60a":{"displayName":"Username Collector","nodeType":"UsernameCollectorNode","connections":{"outcome":"54f14341-d1b7-436f-b159-d1f9b6c626eb"}},"54f14341-d1b7-436f-b159-d1f9b6c626eb":{"displayName":"Password Collector","nodeType":"PasswordCollectorNode","connections":{"outcome":"3fc7ce22-fc79-4131-85f2-f1844709d042"}},"3fc7ce22-fc79-4131-85f2-f1844709d042":{"displayName":"Data Store Decision","nodeType":"DataStoreDecisionNode","connections":{"false":"e301438c-0bd0-429c-ab0c-66126501069a","true":"70e691a5-1e33-4ac3-a356-e7b6d60d92e0"}}}}' ===> { "entryNodeId":"8f9d2280-caa7-433f-93a9-1f64f4cae60a", "nodes":{ "54f14341-d1b7-436f-b159-d1f9b6c626eb":{ "nodeType":"PasswordCollectorNode", "displayName":"Password Collector", "connections":{ "outcome":"3fc7ce22-fc79-4131-85f2-f1844709d042" } }, "3fc7ce22-fc79-4131-85f2-f1844709d042":{ "nodeType":"DataStoreDecisionNode", "displayName":"Data Store Decision", "connections":{ "false":"e301438c-0bd0-429c-ab0c-66126501069a", "true":"70e691a5-1e33-4ac3-a356-e7b6d60d92e0" } }, "8f9d2280-caa7-433f-93a9-1f64f4cae60a":{ "nodeType":"UsernameCollectorNode", "displayName":"Username Collector", "connections":{ "outcome":"54f14341-d1b7-436f-b159-d1f9b6c626eb" } } }, "_rev":"1365759445", "_id":"MyNewAuthTree" }

See Also

Best practice for migrating Authentication Chains to Trees in AM 6.x

How do I modify the prompt text shown when authenticating to a tree in AM 5.5.x, 6.x and 7.x?

Authentication and Single Sign-On Guide › Configuring Authentication Trees

Entity Reference › UsernameCollector

Entity Reference › PasswordCollector

Entity Reference › DataStoreDecision

Entity Reference › AuthTree

Related Training

N/A

Related Issue Tracker IDs

N/A


Customization


How do I customize the email sent by the OTP Email Sender node in AM (All versions)?

The purpose of this article is to provide information on customizing the text in the OTP email sent by the OTP Email Sender authentication node in AM. The OTP Email Sender node sends an email containing a generated one-time password to the user.

Background information

The OTP email template is Plain Text. You can make simple changes to the content of the OTP email by editing the OneTimePasswordSmtpSenderNode.properties file, which is located in the auth-nodes-<version>.jar file in the WEB-INF/lib directory of the AM WAR file. You can find this file in the following path within the jar file: org/forgerock/openam/auth/nodes.

If you want more extensive changes that require HTML or Rich Text formatting, you will need to create a custom SMS Gateway Implementation Class, specify a different content type in the custom.java file and update the OTP Email Sender node configuration to specify the Gateway Implementation class you are using. See Authentication Node Development Guide (AM 6.5 and later) or How do I customize authentication tree nodes using source code in AM 5.5.x and 6? for further information on customizing nodes.

Note

Creating and using a custom SMS Gateway Implementation class is outside the scope of ForgeRock support; if you want more tailored advice, consider engaging Deployment Support Services.

Changing the OTP email content

You can update the OTP email subject and body as follows:

  1. Unpack the AM WAR file and extract the auth-nodes-<version>.jar file from the WEB-INF/lib directory.
  2. Navigate to the org/forgerock/openam/auth/nodes path within the extracted jar.
  3. Edit the OneTimePasswordSmtpSenderNode.properties file and change the following properties as required to update the email subject and body:messageSubject=One Time Password messageContent=Your One Time Password:
  4. Repack the auth-nodes-<version>.jar with your changes.
  5. Add your customization to the AM WAR file:
    • Replace the existing jar file in the WEB-INF/lib directory with your customized jar file.
    • Repack the AM WAR file and deploy as normal.
  6. Restart the web application container in which AM runs.
  7. Test your changes.

See Also

OTP Email Sender Node

Authentication Node Development Guide

Related Training

N/A

Related Issue Tracker IDs

N/A


How do I modify the prompt text shown when authenticating to a tree in AM 5.5.x, 6.x and 7.x?

The purpose of this article is to provide assistance if you want to customize the prompt text displayed when authenticating to a tree. This article focuses on changing the User Name and Password prompts.

Background information

Collector nodes provide a callback mechanism where input is collected. A typical example is the username collector, which provides a single text-based callback.

The two main collectors of interest when customizing the login process are the Username Collector Node and the Password Collector Node; each of the collector nodes has a corresponding properties file, which contains the callback.[name] property. This property defines the prompt text.

The collector nodes' property files are located in the auth-nodes-<version>.jar file in the WEB-INF/lib directory of the AM WAR file. You can find these files in the following path within the jar file: org/forgerock/openam/auth/nodes.

Modifying the prompt text

The following example demonstrates changing the user name and password prompts:

  1. Unpack the AM WAR file and extract the auth-nodes-<version>.jar file from the WEB-INF/lib directory.
  2. Navigate to the org/forgerock/openam/auth/nodes path within the extracted jar.
  3. Edit the UsernameCollectorNode.properties file to update the callback.username property to the prompt of your choice, for example: callback.username=Your User Name
  4. Edit the PasswordCollectorNode.properties file to update the callback.password property to the prompt of your choice, for example: callback.password=Your Password
  5. Repack the auth-nodes-<version>.jar with your changes.
  6. Add your customization to the AM WAR file:
    • Replace the existing jar file in the WEB-INF/lib directory with your customized jar file.
    • Repack the AM WAR file and deploy as normal.
  7. Restart the web application container in which AM runs.
  8. Test your changes.

The resulting login page looks like this after a restart:

Followed by the Password Collector Node:

See Also

How do I customize authentication tree nodes using source code in AM 5.5.x and 6?

Authentication Node Development Guide

Related Training

N/A

Related Issue Tracker IDs

OPENAM-14467 (RFE: Ability to customise Authentication Tree's)

OPENAM-12978 (API Explorer - Create Page Node Example Value is inadequate)


How do I register or re-register a custom authentication node in AM 5.5.x and 6?

The purpose of this article is to provide assistance on registering a custom authentication node in AM. If you make changes to the custom node, you will need to re-register it to apply the changes.

Overview

In AM 6.5 and later, you should refer to the Authentication Node Development Guide for information on working with custom nodes.

Pre-AM 6.5

A custom authentication node can be registered by deploying a JAR file. If you make changes to your custom node once it has been registered, you must re-register it to apply your changes.

See the following sections for further details:

Preparing the JAR file

You must ensure you have a valid JAR file before registering or re-registering your node.

The JAR file must contain the following files, which are needed to register the node with AM:

META-INF/services/org.forgerock.openam.plugins.AmPlugin com/example/customAuthNode/myCustomAuthNodePlugin.java

Where:

  • The org.forgerock.openam.plugins.AmPlugin file holds the fully qualified class name of the AmPlugin that registers the custom implementations. The org.forgerock.openam.plugins.AmPlugin file must not be renamed or placed in a different directory. For example: $ cat META-INF/services/org.forgerock.openam.plugins.AmPlugin .......... # When distributing Covered Software, include this CDDL Header Notice in each file and include # the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL # Header, with the fields enclosed by brackets [] replaced by your own identifying # information: "Portions copyright [year] [name of copyright owner]". # # Copyright 2017-2018 ForgeRock AS. # com.example.customAuthNode.myCustomAuthNodePlugin The above file would find the myCustomAuthNodePlugin file and execute the file.
  • The myCustomAuthNodePlugin Java class implements the org.forgerock.openam.plugins.AmPlugin interface. See Authentication and Single Sign-On Guide › The Plugin Class of an Authentication Node for further information.

You can use Apache Maven™ to generate the archetype, which creates a template of the Plugin installer to get you started as described in: Authentication and Single Sign-On Guide › Preparing to Customize Authentication Nodes.

See How do I customize authentication tree nodes using source code in AM 5.5.x and 6? and Authentication and Single Sign-On Guide › Customizing Authentication Trees for further information on building the JAR file.

Registering a custom node

You can register a custom node as follows:

  1. Copy the custom authentication node JAR file to the /path/to/tomcat/webapps/openam/WEB-INF/lib directory, for example: $ cp custom-node-X.X.X.jar /path/to/tomcat/webapps/openam/WEB-INF/lib 
  2. Restart the web application container in which AM runs to complete the registration of the custom node.

See Authentication and Single Sign-On Guide › Building and Installing Authentication Nodes for further information.

Re-registering a custom node

This section assumes you have already built your new JAR file and it contains the files outlined in the Preparing the JAR file section.

If you make any changes to your custom node, you must re-register the node with AM as follows:

  1. Take a backup of your configuration prior to making any changes in case you need to revert per How do I make a backup of configuration data in AM 5.x or 6.x?
  2. Uninstall the custom node using ssoadm, for example:  $ ./ssoadm delete-svc -u amadmin -f pwd.txt -s [service_name​]​​​​​​Replacing [service_name] with the name of the Java file (minus the .java extension). For example, if your file is called myCustomAuthNodePlugin.java, then your service name is myCustomAuthNodePlugin.
  3. Delete the node sub-entry in the configuration store using ldapdelete, for example:$ ./ldapdelete --hostname host1.example.com --port 50389 --bindDN "cn=Directory Manager" --bindPassword password "ou=[plugin_name],ou=plugins,ou=default,ou=GlobalConfig,ou=1.0,ou=amPluginService,ou=services,[configuration_suffix]"Replacing [plugin_name] and [configuration_suffix] as follows:
    • [plugin_name] - for example, com.example.customAuthNode.myCustomAuthNodePlugin. You can find this in your META-INF/services/org.forgerock.openam.plugins.AmPlugin file, for example: $ cat META-INF/services/org.forgerock.openam.plugins.AmPlugin .......... # When distributing Covered Software, include this CDDL Header Notice in each file and include # the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL # Header, with the fields enclosed by brackets [] replaced by your own identifying # information: "Portions copyright [year] [name of copyright owner]". # # Copyright 2017-2018 ForgeRock AS. # com.example.customAuthNode.myCustomAuthNodePlugin
    • [configuration_suffix] - for example, dc=openam,dc=forgerock,dc=org
  4. Delete or rename the old JAR file in the /path/to/tomcat/webapps/openam/WEB-INF/lib directory and replace with the updated JAR file.
  5. Restart the web application container in which AM runs to apply the changes.

See Also

Authentication trees in AM

API Javadoc › Interface AmPlugin

Authentication and Single Sign-On Guide › Customizing Authentication Trees

Related Training

N/A

Related Issue Tracker IDs

OPENAM-12347 (AmPlugin Custom Authentication Module cannot be uninstalled or reregistered)


Known Issues


Login page does not load when using authentication trees with custom or Marketplace nodes in AM 6.5.x or 7.x

The purpose of this article is to provide assistance if the login page does not load when using authentication trees in AM 6.5.x and the tree editor in the console is missing nodes. These issues occur when you have custom or Marketplace nodes. You will see "Unsupported node type" errors when this happens.

Symptoms

Note

The Unsupported node type referenced in the following errors does not indicate the custom or Marketplace node causing the issues; instead it refers to one of the nodes in the tree you are accessing.

Login page

The browser shows a Loading... message but nothing else happens.

Errors similar to the following are shown when this happens:

  • CoreSystem debug log: frRest:12/19/2018 02:34:05:080 pm GMT: Thread[http-nio-48080-exec-5,5,main]: TransactionId[8447c05f-4bc1-4d38-bae0-ad6b3cca7b44-69807] ERROR: Could not invoke method: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.forgerock.openam.http.annotations.AnnotatedMethod.invoke(AnnotatedMethod.java:76) at org.forgerock.openam.http.annotations.Endpoints$1.handle(Endpoints.java:64) at org.forgerock.http.routing.Router.handle(Router.java:100) at org.forgerock.openam.audit.AbstractHttpAccessAuditFilter.filter(AbstractHttpAccessAuditFilter.java:59) Caused by: java.lang.IllegalArgumentException: Unsupported node type ZeroPageLoginNode at org.forgerock.openam.auth.trees.engine.NodeFactory.createNode(NodeFactory.java:122) at org.forgerock.openam.auth.trees.engine.AuthTreeExecutor.process(AuthTreeExecutor.java:97) at org.forgerock.openam.core.rest.authn.trees.AuthTrees.processTree(AuthTrees.java:389) at org.forgerock.openam.core.rest.authn.trees.AuthTrees.evaluateTreeAndProcessResult(AuthTrees.java:245) at org.forgerock.openam.core.rest.authn.trees.AuthTrees.invokeTree(AuthTrees.java:237) at org.forgerock.openam.core.rest.authn.RestAuthenticationHandler.authenticate(RestAuthenticationHandler.java:203) at org.forgerock.openam.core.rest.authn.http.AuthenticationServiceV1.authenticate(AuthenticationServiceV1.java:164) ... 89 more
  • Authentication debug log: amAuth:12/19/2018 02:34:06:437 pm GMT: Thread[http-nio-48080-exec-7,5,main]: TransactionId[8447c05f-4bc1-4d38-bae0-ad6b3cca7b44-69841] ERROR: Unsupported node type ZeroPageLoginNode

Console

You will notice one or more of the following symptoms in the AM console when you select a tree to edit:

  • The authentication tree designer is completely empty; it does not include any nodes nor the Start and Failure entry/exit points. An empty pink warning message box briefly displays upon selecting the tree.
  • The Components panel is missing all or some of the available nodes.
  • The required node appears in the Components panel but does not have any outcomes when dragged onto the authentication tree designer. An empty pink warning message box briefly displays upon moving the node.

An error similar to the following may be shown in the CoreSystem debug log when this happens:

frRest:12/19/2018 10:19:59:093 am GMT: Thread[http-nio-48080-exec-7,5,main]: TransactionId[8447c05f-4bc1-4d38-bae0-ad6b3cca7b44-1420] ERROR: A runtime exception occurred during the CREST request handling java.lang.IllegalStateException: Exception from invocation expected to be handled by promise at org.forgerock.json.resource.AnnotatedMethod.invoke(AnnotatedMethod.java:100) at org.forgerock.json.resource.AnnotatedMethod.invoke(AnnotatedMethod.java:65) at org.forgerock.json.resource.AnnotationCollectionInstance.handleRead(AnnotationCollectionInstance.java:51) at org.forgerock.json.resource.FilterChain$Cursor.handleRead(FilterChain.java:105) at org.forgerock.json.resource.Resources$CollectionInstanceIdContextFilter.filterRead(Resources.java:528) ... Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.forgerock.json.resource.AnnotatedMethod.invoke(AnnotatedMethod.java:96) ... 141 more Caused by: java.lang.IllegalArgumentException: Unsupported node type UsernameCollectorNode at org.forgerock.openam.auth.trees.engine.NodeFactory.getOutcomeProvider(NodeFactory.java:173) at org.forgerock.openam.auth.trees.engine.NodeFactory.getNodeOutcomes(NodeFactory.java:199) at org.forgerock.openam.core.rest.sms.AuthTreesCollectionProvider.read(AuthTreesCollectionProvider.java:296) ... 146 more

Recent Changes

Upgraded to, or installed AM 6.5 or later.

Installed a custom or Marketplace node. For example, the Have I Been Pwned Authentication Marketplace node.

Causes

The dependency on forgerock-guava was removed in AM 6.5 and instead these libraries are retrieved directly from Google Guava. For example, all the node .java files have been updated as follows:

import com.google.common.collect.ImmutableList; //import org.forgerock.guava.common.collect.ImmutableList;

The custom or Marketplace node fails because it uses one of the 'org.forgerock.guava' classes; these classes have been removed from the classpath since they are no longer supported.

Solution

This issue can be resolved either by updating the node so that it does not use any org.forgerock.guava classes or by adding a dependency on Guava.

Remove org.forgerock.guava classes

You can either use simple replacements from the standard JDK collections classes or one of the following methods:

  • Collections.singletonMap
  • Collections.singletonList
  • Arrays.asList

Add a dependency

If you want to continue using these org.forgerock.guava classes, you should add a dependency on Guava and bundle it properly per the instructions in Authentication Node Development Guide › The Maven Project for an Authentication Node.

Note

Customizing authentication nodes is outside the scope of ForgeRock support; if you want more tailored advice, consider engaging Deployment Support Services.

See Also

Authentication trees in AM

Authentication Node Development Guide

Guava: Google Core Libraries for Java

Using the BackStage Marketplace

Related Training

N/A

Related Issue Tracker IDs

OPENAM-14092 (Custom node can prevent all default nodes appearing in admin view)


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

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

This issue can be resolved by upgrading to AM 6.5 or later; you can download this from BackStage.

Workaround 

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 Deployment Support 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.x

How do I create an authentication tree in AM 5.5.x, 6.x and 7.x using REST or Amster?

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 Trademarks Copyright © 2021 ForgeRock, all rights reserved.

This content has been optimized for printing.