Extending OpenAM OpenAM services solve a wide range of access and federation management problems out of the box. Yet, OpenAM also exposes APIs and SPIs that enable you extend OpenAM services when built-in functionality does not fit your deployment. This part of the guide covers OpenAM mechanisms for plugging in additional functionality not available out of the box. Creating a Post Authentication Plugin Post authentication plugins (PAP) let you include custom processing at the end of the authentication process, immediately before the subject is authenticated. Common uses of post authentication plugins include setting cookies and session variables. Post authentication plugins are often used in conjunction with policy agents. The post authentication plugin sets custom session properties, and then the policy agent injects the custom properties into the request header to the protected application. Two issues should be considered when writing a post authentication plugin for an OpenAM deployment that uses stateless sessions: Cookie size You can set an unlimited number of session properties in a post authentication plugin. When OpenAM creates a stateless session, it writes the session properties into the session cookie, increasing the size of the cookie. Very large session cookies can exceed browser limitations. Therefore, when implementing a post authentication plugin in a deployment with stateless sessions, be sure to monitor the session cookie size and verify that you have not exceeded browser cookie size limits. For more information about stateless session cookies, see "Session Cookies" in the Administration Guide. Cookie security The OpenAM administrator secures custom session properties residing on the OpenAM server for stateful sessions by using firewalls and other typical security techniques. However, when using stateless sessions, custom session properties are written in cookies and reside on end users' systems. Cookies can be long-lasting and might represent a security issue if any session properties are of a sensitive nature. When developing a post authentication plugin for a deployment that uses stateless sessions, be sure that you are aware of the measures securing the session contained within the cookie. For more information about stateless session cookie security, see "Stateless Session Cookie Security" in the Administration Guide. This section explains how to create a post authentication plugin. Designing Your Post Authentication Plugin Your post authentication plugin class implements the AMPostAuthProcessInterface interface, and in particular the following three methods. public void onLoginSuccess( Map requestParamsMap, HttpServletRequest request, HttpServletResponse response, SSOToken token ) throws AuthenticationException public void onLoginFailure( Map requestParamsMap, HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException public void onLogout( HttpServletRequest request, HttpServletResponse response, SSOToken token ) throws AuthenticationException OpenAM calls the onLoginSuccess() and onLoginFailure() methods immediately before informing the user of login success or failure, respectively. OpenAM calls the onLogout() method only when the user actively logs out, not when a user’s session times out. See the OpenAM Java SDK API Specification for reference. These methods can perform whatever processing you require. Yet, know that OpenAM calls your methods synchronously as part of the authentication process. Therefore, if your methods take a long time to complete, you will keep users waiting. Minimize the processing done in your post authentication methods. Building Your Sample Post Authentication Plugin The following example post authentication plugin sets a session property during successful login, writing to its debug log if the operation fails. package com.forgerock.openam.examples; import java.util.Map; import com.iplanet.sso.SSOException; import com.iplanet.sso.SSOToken; import com.sun.identity.authentication.spi.AMPostAuthProcessInterface; import com.sun.identity.authentication.spi.AuthenticationException; import com.sun.identity.shared.debug.Debug; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SamplePAP implements AMPostAuthProcessInterface { private final static String PROP_NAME = "MyProperty"; private final static String PROP_VALUE = "MyValue"; private final static String DEBUG_FILE = "SamplePAP"; protected Debug debug = Debug.getInstance(DEBUG_FILE); public void onLoginSuccess( Map requestParamsMap, HttpServletRequest request, HttpServletResponse response, SSOToken token ) throws AuthenticationException { try { token.setProperty(PROP_NAME, PROP_VALUE); } catch (SSOException e) { debug.error("Unable to set property"); } } public void onLoginFailure( Map requestParamsMap, HttpServletRequest request, HttpServletResponse response ) throws AuthenticationException { // Not used } public void onLogout( HttpServletRequest request, HttpServletResponse response, SSOToken token ) throws AuthenticationException { // Not used } } The sample post authentication plugin source is available online. Get a local clone so that you can try the sample on your system. 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 post authentication plugin, and also specifies its dependencies on OpenAM components and on the Servlet API. src/main/java/com/forgerock/openam/examples/SamplePAP.java Core class for the sample post authentication plugin Build the module using Apache Maven. $ cd /path/to/openam-post-auth-sample $ mvn install [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building openam-post-auth-sample 1.0.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ ... [INFO] [INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ openam-post-auth-sample -- [INFO] Building jar: .../target/openam-post-auth-sample-1.0.0-SNAPSHOT.jar ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 6.727s [INFO] Finished at: Mon Nov 25 17:07:23 CET 2013 [INFO] Final Memory: 20M/227M [INFO] ------------------------------------------------------------------------ Copy the .jar to the WEB-INF/lib directory where you deployed OpenAM. $ cp target/*.jar /path/to/tomcat/webapps/openam/WEB-INF/lib/ Restart OpenAM or the container in which it runs. Configuring Your Post Authentication Plugin You can associate post authentication plugins with realms or services (authentication chains). Where you configure the plugin depends on the scope to which the plugin should apply: Plugins configured at the realm level are executed when authenticating to any authentication chain in the realm, provided the authentication chain does not have an associated plugin. Plugins configured at the service level are executed if that authentication chain is used for authentication. Any plugins configured at the realm level will not execute. In OpenAM Console, navigate to Realms > Realm Name > Authentication > Settings > Post Authentication Processing. In the Authentication Post Processing Classes list, add the sample plugin class, com.forgerock.openam.examples.SamplePAP, and then click Save. Alternatively, you can configure sample plugin for the realm by using the ssoadm command. $ ssoadm set-svc-attrs --adminid amadmin --password-file /tmp/pwd.txt --servicename iPlanetAMAuthService --realm /myRealm --attributevalues iplanet-am-auth-post-login-process-class= com.forgerock.openam.examples.SamplePAP iPlanetAMAuthService under /myRealm was modified. Testing Your Post Authentication Plugin To test the sample post authentication plugin, login successfully to OpenAM in the scope where the plugin is configured. For example, if you configured your plugin for the realm, /myRealm, specify the realm in the login URL. http://openam.example.com:8080/openam/UI/Login?realm=myRealm Although as a user you do not notice anywhere in the user interface that OpenAM calls your plugin, a policy agent or custom client code could retrieve the session property that your plugin added to the user session. Extending UMA Workflow with Extension Points OpenAM provides a number of extension points for extending the UMA workflow. These extension points are provided as filters and are dynamically loaded by using the Java ServiceLoader framework during the UMA workflow. The extension points available are described in the sections below: "Resource Set Registration Extension Point" "Permission Request Extension Point" "Authorization Request Extension Point" "Resource Sharing Extension Point" Resource Set Registration Extension Point OpenAM provides the ResourceRegistrationFilter extension point, which can be used to extend UMA resource set registration functionality. Resource Set Registration Extension Methods Method Parameters Description beforeResourceRegistration resourceSet (type: ResourceSetDescription) Invoked before a resource set is registered in the backend. Changes made to the __resourceSet__ object at this stage __will__ be persisted. afterResourceRegistration resourceSet (type: ResourceSetDescription) Invoked after a resource set is registered in the backend. Changes made to the __resourceSet__ object at this stage __will not__ be persisted. Permission Request Extension Point OpenAM provides the PermissionRequestFilter extension point, which can be used to extend UMA permission request functionality. Permission Request Extension Methods Method Parameters Description onPermissionRequest resourceSet (type: ResourceSetDescription) __requestedScopes__ (type: `Set<String>`) __requestingClientId__ (type: `String`) Invoked before a permission request is created. Authorization Request Extension Point OpenAM provides the RequestAuthorizationFilter extension point, which can be used to extend UMA authorization functionality. Authorization Request Extension Methods Method Parameters Description beforeAuthorization permissionTicket (type: PermissionTicket) __requestingParty__ (type: `Subject`) __resourceOwner__ (type: `Subject`) Invoked before authorization of a request is attempted. Throws `UmaException` if authorization of the request should not be attempted. afterAuthorization isAuthorized (type: boolean) __permissionTicket__ (type: `PermissionTicket`) __requestingParty__ (type: `Subject`) __resourceOwner__ (type: `Subject`) Invoked before authorization of a request is attempted. If the authorization request was successful, __isAuthorized__ will be `true`. Resource Sharing Extension Point OpenAM provides the ResourceDelegationFilter extension point, which can be used to extend UMA resource sharing functionality. Resource Sharing Extension Methods Method Parameters Description beforeResourceShared umaPolicy (type: UmaPolicy) Invoked before creating a sharing policy for a resource. Changes to the __umaPolicy__ object at this stage __will__ be persisted. Throws `ResourceException` if a sharing policy for the resource should not be created. afterResourceShared umaPolicy (type: UmaPolicy) Invoked after creating a sharing policy for a resource. Changes to the __umaPolicy__ object at this stage __will not__ be persisted. beforeResourceSharedModification currentUmaPolicy (type: UmaPolicy) __updatedUmaPolicy__ (type: `UmaPolicy`) Invoked before altering the sharing policy of a resource. Changes to the __updatedUmaPolicy__ object at this stage __will__ be persisted. Throws `ResourceException` if the sharing policy of the resource should not be modified. onResourceSharedDeletion umaPolicy (type: UmaPolicy) Invoked before deleting the sharing policy of a resource. Throws `ResourceException` if the sharing policy of the resource should not be deleted. beforeQueryResourceSets userId (type: String) __queryFilter__ (type: `QueryFilter<JsonPointer>`) Invoked before querying the resource sets owned or shared with a user. The __userId__ parameter provides the ID of the user making the query request. The __queryFilter__ parameter provides the incoming request query filter. Returns a `QueryFilter` that can be used to return the user's resource sets. Customizing OpenAM Scripting OpenAM