Customize server-side session quota exhaustion actions
This page demonstrates a custom session quota exhaustion action plugin. AM calls a session quota exhaustion action plugin when a user tries to open more server-side sessions than their quota allows. Note that session quotas are not available for client-side sessions.
You only need a custom session quota exhaustion action plugin if the built-in actions are not flexible enough for your deployment. See Session quotas.
Create and install 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 PingAM? 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 uid=amAdmin,ou=People,dc=openam,dc=forgerock,dc=org \
--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.4.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.4.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. First, in the AM admin UI, go to Configure > Global Services and click Session. Then scroll to Resulting behavior if session quota exhausted, and 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.
List session quota exhaustion actions
List session quota exhaustion actions by using the ssoadm
command:
$ ssoadm \
get-attr-choicevals \
--adminid uid=amAdmin,ou=People,dc=openam,dc=forgerock,dc=org \
--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
Remove a session quota exhaustion action
Remove a session quota exhaustion action by using the ssoadm
command:
$ ssoadm \
remove-attr-choicevals \
--adminid uid=amAdmin,ou=People,dc=openam,dc=forgerock,dc=org \
--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.