Access Management 7.2.2

Node class

In Java terms, an authentication node is a class that implements the Node interface, org.forgerock.openam.auth.node.api.Node.

The Node class may access and modify the persisted state that is shared between the nodes within a tree, and may request input by using callbacks. The class also defines the possible exit paths from the node.

The class is annotated with org.forgerock.openam.auth.node.api.Node.Metadata. The annotation has two main attributes - configClass and outcomeProvider. Typically, the configClass attribute is an inner interface in the node implementation class.

For simple use cases, the abstract implementations of the node interface, org.forgerock.openam.auth.node.api.SingleOutcomeNode and org.forgerock.openam.auth.node.api.AbstractDecisionNode, have their own outcome providers that can be used. For more complex use cases you can provide your own implementation.

The sections that follow describe the Node class.

Annotation

The annotation specifies the outcome provider and configuration class. The outcome provider can use the default SingleOutcomeNode or MultipleOutcomeNode, or a custom OutcomeProvider can be created and referenced from the annotation.

See the Choice Collector node for an example of a custom outcome provider.

Private constants

These are optional.

Config

The config interface defines the configuration data for a node. A node cannot have state, but it can have configuration data.

Note that you do not need to provide the implementation class for the Config interface you define. AM will create these automatically, as required.

An example is the Account Lockout node. The node can be configured to lock or unlock the users' account, based on it’s configuration.

Configuration is per-node. Different nodes of the same type in the same tree have their own configuration.

The config interface configures values using methods. To provide no default value to the tree administrator, provide the method’s signature but not the implementation. To provide a default value to the tree administrator, mark the method as default and provide both a method and a value. For example:

public interface Config {

  //This will have no default value for the UI
  @Attribute(order = 10)
  String noDefaultAttribute();

  //This will default to the value LOCK.
  @Attribute(order = 20)
  default LockStatus lockAction() {
    return LockStatus.LOCK;
  }
}

The Config above would resemble the following in the tree designer view:

The output from an example Config interface.

The @Attribute annotation is required. It can be configured with an order value, which determines the position of the attribute in the UI, and with validators, to validate the values being set.

In the example above, a custom enum called LockStatus is returned. The options are displayed to the user automatically.

Constructor

Dependencies should be injected by using Guice as this makes it easier to unit test your node. For example, you should accept the config as a parameter.

You may also wish to obtain AM core classes, such as CoreWrapper, instances of third-party dependencies, or your own types.

@Inject
public AccountLockoutNode(CoreWrapper coreWrapper, @Assisted Config config)
throws NodeProcessException {
  this.coreWrapper = coreWrapper;
  this.config = config;
}

process method

The process method takes a TreeContext parameter, does some processing, and returns an Action object.

An action encapsulates changes to state and flow control. The TreeContext parameter is used to access the request, callbacks, shared state and other input.

The process method is where state is retrieved and stored. The returning Action can be a response of callback to the user, an update of state, or a choice of outcome.

The choice of outcome in a simple decision node would be true or false, resulting in the authentication tree flow moving from the current node to a node at the relevant connection.

Private methods

These are optional.

Custom outcome provider

This is optional.

Example implementation

The following example is the SetSessionPropertiesNode class, taken from the Set Session Properties node:

package org.forgerock.openam.auth.nodes;

import java.util.Map;

import javax.inject.Inject;

import org.forgerock.openam.annotations.sm.Attribute;
import org.forgerock.openam.auth.node.api.Action;
import org.forgerock.openam.auth.node.api.Node;
import org.forgerock.openam.auth.node.api.SingleOutcomeNode;
import org.forgerock.openam.auth.node.api.TreeContext;
import org.forgerock.openam.auth.nodes.validators.SessionPropertyValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.assistedinject.Assisted;

/**
 * A node which contributes a configurable set of properties to be added to the user's session, if/when it is created.
 */
@Node.Metadata(outcomeProvider = SingleOutcomeNode.OutcomeProvider.class,
        configClass = SetSessionPropertiesNode.Config.class) (1)
public class SetSessionPropertiesNode extends SingleOutcomeNode { (2)

    /**
     * Configuration for the node.
     */
    public interface Config { (3)
        /**
         * A map of property name to value.
         * @return a map of properties.
         */
        @Attribute(order = 100, validators = SessionPropertyValidator.class)
        Map<String, String> properties();
    }

    private final Config config;
    private final Logger logger = LoggerFactory.getLogger("amAuth");

    /**
     * Constructs a new SetSessionPropertiesNode instance.
     * @param config Node configuration.
     */
    @Inject (4)
    public SetSessionPropertiesNode(@Assisted Config config) {
        this.config = config;
    }

    @Override
    public Action process(TreeContext context) { (5)
        logger.debug("SetSessionPropertiesNode started");
        Action.ActionBuilder actionBuilder = goToNext();
        config.properties().entrySet().forEach(property -> {
            actionBuilder.putSessionProperty(property.getKey(), property.getValue());
            logger.debug("set session property {}", property);
        });
        return actionBuilder.build();
    }
}
1 The @Node.Metadata annotation. See Metadata annotation.
2 Implementing the Node interface. See Node interface.
3 Implementing the Config interface. See Config interface.
4 Injecting the Node instance. See Inject objects into a node instance.
5 Creating an Action instance. See Action class.
Copyright © 2010-2024 ForgeRock, all rights reserved.