ForgeRock DS and the LDAP Relax Rules Control

In ForgeRock Directory Services 6.5, we’ve added the support for the LDAP Relax Rules Control, both on the server and our clients. One of my colleagues, involved with the customers’ deployment, asked me why we’ve added the control and what it should be used for.

The LDAP Relax Rules Control is an LDAP extension that allows a directory user agent (a client) to request the directory service to temporarily relax enforcement of various data and service model rules. The internet-draft is explicit about which rules can be relaxed or not. But typically it can be used to allow a client to write specific operational attributes that should be read-only and managed by the server.

Starting with OpenDJ 3.0, we’ve removed the ability to bulk import LDIF data to a server while preserving the existing data (the “append mode”). First, performing an import-ldif in append mode was breaking replication. The import needed to be applied to all replica, while no change was to happen on the new data. The process was cumbersome, especially when having multiple data-centers. But also, removing this feature allowed us to have a more generic interface and implement multiple backend using different underlying key-value stores.

But we have a few customers that have the need to seldom bulk load a large set of users to their directory service. In DS 6.0, we’ve added an option to speed bulk operations using ldapmodify or ldapdelete: –numConnections. Instead of serialising all updates or adds contained in an LDIF file, the tool will run them in parallel across multiple connections, while also controlling dependencies of changes. With this options, some of our customers have added several millions of users to their replicated directory services in minutes. By controlling the number of connections, one can also balance the need for speed of bulk loading data against the need to keep bandwidth for the regular client applications.

Doing bulk updates over LDAP is now fast, but some customers used the import process to also carry over some attributes that are usually managed by the directory server and thus read-only, such as the CreateTimeStamp, the CreatorsName.

And this is specifically what the Relax Rules Control is meant to allow.

So, if you have a need to bulk load large set of data, or synchronise over LDAP data from another server, and need to preserve some of the operational attribute, you can use the Relax Rules Control as illustrated below. Note that the OID for the control is but ForgeRock DS tools also recognise the RelaxRules string alias.

$ ldapmodify -p 1389 -D cn=directory\ manager -w secret12
-J RelaxRules:true --numConnections 4 ../50Kusers.ldif
ADD operation successful for DN uid=user.10021,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10022,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10001,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10020,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10026,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10025,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10024,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10005,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10033,ou=People,dc=example,dc=com
ADD operation successful for DN uid=user.10029,ou=People,dc=example,dc=com

Note that because the Relax Rules Control allows to override some of the rules enforced normally by the server, it’s important to control and restrict which clients or users are allowed to make use of it. In ForgeRock DS, you would use ACIs (global or not) to define who has permission to use the control. Out of the box, only Directory Manager can, because it has the bypass access controls privilege. Check the “Use Control or Extended Operation” section of the Administration Guide for the details on how to allow a user to use a control.

Session Quota basics

What is Session Quota?

Session Quota provides a way to limit the number of active sessions for a given user. Basically in the session service you can configure how many active sessions could a user have. For simplicity let’s say that the active session limit is set to 5. If a user would log in for the 6th time, then based on the session quota settings a QuotaExhaustionAction gets executed, which will decide what happens with the new and the existing sessions.

How session quota is evaluated?

When session quota is enabled, OpenAM tracks the user sessions mapped by universal IDs, hence it can easily detect the number of active sessions for a given user (this mapping is only available when session quota is enabled or SFO is being used). There is 3 way how the session quota can be evaluated:

  • Single Server Mode: if there is only one OpenAM node (with or without a site), then the quota will be evaluated per that one server.
  • Local Server Only Mode: When the advanced property “openam.session.useLocalSessionsInMultiServerMode” is set to true, OpenAM will only evaluate session quota per local server (so a user can end up having number of servers * number of allowed concurrent sessions). This option has been introduced to provide a certain level of support for multiserver environments without SFO (see OPENAM-875)
  • Session Failover Mode: In multiserver setup when using SFO it is possible to enforce deployment-wide session quota

So we now know how OpenAM detects if the session quota is being exceeded by a given user, but we don’t know yet what to do when that happens. Here comes QuotaExhaustionAction into the picture. This interface allows deployers to customize the behavior of OpenAM for these cases. To understand this a bit more let’s look at the built-in session quota exhaustion actions:

  • DENY_ACCESS: basically it will deny the access for the new session, but will keep the old session alive.
  • DESTROY_NEXT_EXPIRING: destroys the next expiring session (based on min(full, idle) for all the sessions), and lets the new session live.
  • DESTROY_OLDEST_SESSION: destroys the session with the lowest expiration time, and lets the new session live.
  • DESTROY_OLD_SESSIONS: destroys all the existing sessions, and lets the new session live.

As you can see there are many different ways to handle session quota exhaustion, and it really depends on the requirements, which method really fits. In case none of these are good for you, you can simply implement a custom QuotaExhaustionAction, for that you can find the built-in implementations here, but there is also a sample GitHub project.
Once you are ready with your custom implementation follow the installation steps on the GitHub project README.

How to enable session quota?

On the admin console go to Configuration -> Global -> Session page and:

  • Set the number of “Active User Sessions” to your choosen value.
  • Turn ON “Enable Quota Constraints”.
  • Select the preferred exhaustion action under the “Resulting behavior if session quota exhausted” option.

Quite possibly you need to restart OpenAM for the changes to take effect, but after then it should work just as you would want it to. ;)