PingAM 8.0.0

Store values in shared tree state

Tree state exists for the lifetime of the journey session. When the tree has completed, the journey session is terminated and an authenticated session is created. The purpose of tree state is to hold state between the nodes.

A good example is the Username Collector node, which gets the username from the user and stores it in the shared tree state. Later, the Data Store Decision node can pull this value from the shared tree state and use it to authenticate the user.

Authentication trees can be stateful or stateless. When they are stateful, the AM server that starts the authentication flow mustn’t change. A load balancer cookie is set on the responses to the user to ensure the same AM server is used. When they are stateless, any AM instance in a deployment can proceed with the journey session.

You can find more information on configuring sessions in Sessions.

Store values in a tree’s node states

Always store the authentication state in the NodeState object that AM lets you access from the TreeContext object passed to the node’s process() method. AM ensures the node state is made available to downstream nodes:

  • Store non-sensitive information with the NodeState.putShared() method.

  • Store sensitive information, such as passwords, with the NodeState.putTransient() method.

    AM encrypts the transient state with the key that has the am.authn.trees.transientstate.encryption secret label. Downstream nodes must have the same key to decrypt and read it.

    Limit what you store with the putShared() and putTransient() methods to make sure the authentication flow isn’t bloated with calls to encrypt or decrypt data, and the journey session size stays small. This is especially true when the realm is configured for client-side journey sessions.

Get and set values stored in tree state

Internally, AM distinguishes the following node state data:

  • Shared state, where nodes store non-sensitive information that needs to be available during the authentication flow.

    You store this with the NodeState.putShared() method.

  • Transient state, where nodes store sensitive information that AM encrypts on round trips to the client.

    You store this with the NodeState.putTransient() method.

  • Secure state, where nodes store decrypted transient state.

Learn more in NodeState.

Set values in the tree state

To set node state values, get the NodeState using the TreeContext.getStateFor(Node node) method. Then, use the NodeState.putShared() and NodeState.putTransient() methods as described above.

For example:

// Setting values in NodeState
public Action process(TreeContext context) {
  String username;
  String password;
  // ...
  NodeState state = context.getStateFor(this);
  state.putShared(USERNAME, username);      // Non-sensitive information
  state.putTransient(PASSWORD, password);   // Sensitive information
  if (!state.isDefined(OPTIONAL_NUMERIC)) { // Check before updating
    state.putShared(OPTIONAL_NUMERIC, 42);
  }
  goToNext().build();
}

Get values in the tree state

To read node state values, use the NodeState.isDefined(String key) and NodeState.get(String key) methods.

For example:

// Getting values from NodeState
public Action process(TreeContext context) {
  NodeState state = context.getStateFor(this);
  String username;
  if (state.isDefined(USERNAME)) {
      username = state.get(USERNAME);
  } else {
    throw new NodeProcessException("Username is required");
  }
  // ...
  goToNext().build();
}

The get(String key) method retrieves the state for the key from NodeState states in the following order:

  1. transient

  2. secure

  3. shared

For example, if the same property is stored in the transient and shared states, the method returns the value of the property in the transient state first.

Combine objects

To combine objects from shared, transient and secure state, use the getObject method.

For example, if the following objectAttributes value exists in shared state:

"objectAttributes": { "sharedKey": "value" }

and the following objectAttributes value exists in transient state:

"objectAttributes": { "transientKey": "value" }

when you call nodeState.getObject("objectAttributes");, the combined result is as follows:

{
   "sharedKey": "value",
   "transientKey": "value"
}

This object is read-only.

Merge keys

To merge keys in an object, use the mergeShared and mergeTransient methods.

Learn more in Access shared state data.