Customizing CTS-Based Session Quota Exhaustion Actions

This section demonstrates a custom session quota exhaustion action plugin. AM calls a session quota exhaustion action plugin when a user tries to open more CTS-based sessions than their quota allows. Note that session quotas are not available for client-based sessions.

You only need a custom session quota exhaustion action plugin if the built-in actions are not flexible enough for your deployment. See "Configuring Session Quotas".

Creating & Installing a Custom Session Quota Exhaustion Action

You build custom session quota exhaustion actions into a .jar that you then plug in to AM. You must also add your new action to the Session service configuration, and restart AM in order to be able to configure it for your use.

Your custom session quota exhaustion action implements the com.iplanet.dpro.session.service.QuotaExhaustionAction interface, overriding the action method. The action method performs the action when the session quota is met, and returns true only if the request for a new session should not be granted.

The example in this section simply removes the first session it finds as the session quota exhaustion action.

/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * 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 2012-2019 ForgeRock AS. All Rights Reserved
 */

package org.forgerock.openam.examples.quotaexhaustionaction;

import java.util.Map;

import javax.inject.Inject;

import org.forgerock.guice.core.InjectorHolder;
import org.forgerock.openam.session.Session;
import org.forgerock.openam.session.clientsdk.SessionCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.iplanet.dpro.session.SessionException;
import com.iplanet.dpro.session.SessionID;
import com.iplanet.dpro.session.service.QuotaExhaustionAction;
import com.iplanet.dpro.session.service.SessionService;

/**
 * This is a sample {@link QuotaExhaustionAction} implementation,
 * which randomly kills the first session it finds.
 */
public class SampleQuotaExhaustionAction implements QuotaExhaustionAction {

    private static Logger debug = LoggerFactory.getLogger(SampleQuotaExhaustionAction.class);

    private final SessionCache sessionCache;
    private final SessionService sessionService;

    public SampleQuotaExhaustionAction() {
        this.sessionCache = InjectorHolder.getInstance(SessionCache.class);
        this.sessionService = InjectorHolder.getInstance(SessionService.class);
    }

    @Inject
    public SampleQuotaExhaustionAction(SessionCache sessionCache, SessionService sessionService) {
        this.sessionCache = sessionCache;
        this.sessionService = sessionService;
    }

    /**
     * Check if the session quota for a given user has been exhausted and
     * if so perform the necessary actions. This implementation randomly
     * destroys the first session it finds.
     *
     * @param is               The InternalSession to be activated.
     * @param existingSessions All existing sessions that belong to the same
     *                         uuid (Map:sid->expiration_time).
     * @return true If the session activation request should be rejected,
     *              otherwise false.
     */
    @Override
    public boolean action(
            Session is,
            Map<String, Long> existingSessions, long excessSessionCount) {
        for (Map.Entry<String, Long> entry : existingSessions.entrySet()) {
            try {
                // Get a Session from the cache based on the session ID, and destroy it.
                SessionID sessionId = new SessionID(entry.getKey());
                Session session = sessionCache.getSession(sessionId);
                sessionService.destroySession(session, sessionId);
                // Only destroy the first session.
                break;
            } catch (SessionException se) {
                if (debug.isDebugEnabled()) {
                    debug.debug("Failed to destroy existing session.", se);
                }
                // In this case, deny the session activation request.
                return true;
            }
        }
        return false;
    }
}

If you have not already done so, download and build the sample code.

For information on downloading and building AM sample source code, see How do I access and build the sample code provided for OpenAM 12.x, 13.x and AM (All versions)? in the Knowledge Base.

In the sources, you find the following files:

pom.xml

Apache Maven project file for the module

This file specifies how to build the sample plugin, and also specifies its dependencies on AM components and on the Servlet API.

src/main/java/org/forgerock/openam/examples/quotaexhaustionaction/SampleQuotaExhaustionAction.java

Core class for the sample quota exhaustion action plugin

Once built, copy the .jar to WEB-INF/lib/ where AM is deployed.

$ cp target/*.jar /path/to/tomcat/webapps/openam/WEB-INF/lib/

Using the ssoadm command, update the Session Service configuration:

$ ssoadm \
 set-attr-choicevals \
 --adminid amadmin \
 --password-file /tmp/pwd.txt \
 --servicename iPlanetAMSessionService \
 --schematype Global \
 --attributename iplanet-am-session-constraint-handler \
 --add \
 --choicevalues myKey=\
org.forgerock.openam.examples.quotaexhaustionaction.SampleQuotaExhaustionAction
Choice Values were set.

Extract amSession.properties and if necessary the localized versions of this file from openam-core-7.0.1.jar to WEB-INF/classes/ where AM is deployed. For example, if AM is deployed under /path/to/tomcat/webapps/openam, then you could run the following commands.

$ cd /path/to/tomcat/webapps/openam/WEB-INF/classes/
$ jar -xvf ../lib/openam-core-7.0.1.jar amSession.properties
inflated: amSession.properties

Add the following line to amSession.properties.

myKey=Randomly Destroy Session

Restart AM or the container in which it runs.

You can now use the new session quota exhaustion action. In the AM console, navigate to Configure > Global Services, click Session, scroll to Resulting behavior if session quota exhausted, and then choose an option.

Before moving to your test and production environments, be sure to add your .jar file and updates to amSession.properties into a custom .war file that you can then deploy. You must still update the Session service configuration in order to use your custom session quota exhaustion action.

Listing Session Quota Exhaustion Actions

List session quota exhaustion actions by using the ssoadm command:

$ ssoadm \
 get-attr-choicevals \
 --adminid amadmin \
 --password-file /tmp/pwd.txt \
 --servicename iPlanetAMSessionService \
 --schematype Global \
 --attributename iplanet-am-session-constraint-handler

I18n Key                  Choice Value
------------------------- ---...-----------------------------------------
choiceDestroyOldSession   org...session.service.DestroyOldestAction
choiceDenyAccess          org...session.service.DenyAccessAction
choiceDestroyNextExpiring org...session.service.DestroyNextExpiringAction
choiceDestroyAll          org...session.service.DestroyAllAction
myKey                     org...examples...SampleQuotaExhaustionAction

Removing a Session Quota Exhaustion Action

Remove a session quota exhaustion action by using the ssoadm command:

$ ssoadm \
 remove-attr-choicevals \
 --adminid amadmin \
 --password-file /tmp/pwd.txt \
 --servicename iPlanetAMSessionService \
 --schematype Global \
 --attributename iplanet-am-session-constraint-handler \
 --choicevalues \
 org.forgerock.openam.examples.quotaexhaustionaction.SampleQuotaExhaustionAction
Choice Values were removed.
Read a different version of :