IBM Support

Creating Single Sign-on Logout Action in IBM Content Navigator

Technical Blog Post


Abstract

Creating Single Sign-on Logout Action in IBM Content Navigator

Body

Background

When single sign-on (SSO) is configured in IBM Content Navigator, an SSO provider typically handles authentication, instead of IBM Content Navigator. This allows a user with the appropriate access rights to enter the runtime desktop view without being prompted for credentials in IBM Content Navigator. Since IBM Content Navigator is not responsible for the initial authentication, IBM Content Navigator does not display the log off action in the banner context menu that is typically available when the user enters credentials directly in the IBM Content Navigator log in pane. This is often the desired behavior, but there have been a few situations where customers wanted the log out action to be available in IBM Content Navigator and the result of the log out action to redirect the user to the SSO provider. This article will describe how to create an IBM Content Navigator plug-in to perform the standard IBM Content Navigator log out and then redirect to the log in/out process of an SSO provider. For more information about plug-in development and customizing IBM Content Navigator, refer to the “Customizing and Extending IBM Content Navigator” Redbook.

Creating a Redirect Plug-in

In order to create a new action to perform the standard IBM Content Navigator log off and redirect to an SSO provider, we have to create a custom log off action. We also have to define a new version of the default banner user session context menu. To create these extensions we have to create a new IBM Content Navigator plug-in. For this article, I used the Eclipse extensions provided with the IBM Content Navigator Redbook, referenced above, to create a new IBM Content Navigator Plug-in project in Eclipse.

After defining the project we need to create a new plug-in action. All plug-in extensions require a Java class, which defines the basic properties of the extension to the IBM Content Navigator plug-in framework. Below is the Java class that defines the custom log off action:

 

/**

 * Provides a custom SSO log out action for IBM Content Navigator.

 */

public class SSOLogoutAction extends PluginAction {

 

   /**

    * Returns an alphanumeric identifier that is used to describe this action.

    * 

    * @return An alphanumeric <code>String</code> that is used to identify the

    *         action.

    */

   public String getId() {

       return "SSOLogoutAction";

   }

 

   /**

    * Returns a descriptive label for this action that is displayed on pop-up menus and as hover help for the icon on the toolbar.

    * 

    * @param locale

    *            The current locale for the user.

    * @return A short description of the action.

    */

   public String getName(Locale locale) {

      return "SSO Log Out";

   }

 

   /**

    * @deprecated Since 2.0.3. Plugins should provide an icon cascading style sheet class and override getIconClass to

    *             specify images for buttons and menu items.

    */

   public String getIcon() {

      return "";

   }

 

   /**

     * Returns a <code>String</code> that contains the list of privilege names

     * that the user must have on the selected documents for this action to be

     * enabled.

     * 

     * @return A list of one or more comma-separated privilege names. An empty

     *         string indicates that no privileges are required for this action

     *         to be enabled.

     */

    public String getPrivilege() {

       return "";

    }

 

   /**

    * Returns a Boolean value that indicates whether this action is enabled

    * when multiple documents are selected.

    * 

    * @return A value of <code>true</code> if the action is enabled when

    *         multiple documents are selected.

    */

   public boolean isMultiDoc() {

      return false;

   }

 

   /**

    * Returns a Boolean value that indicates whether this action is global.

    * 

    * @return A value of <code>true</code> if the action should be global. By

    *         default, this function returns <code>false</code>.

    */

   public boolean isGlobal() {

      return true;

   }

 

   /**

    * Provides the name of the JavaScript function that is invoked for this action.

    * 

    * @return The name of a JavaScript function that is contained in one of the script files with the plug-in.

    */

   public String getActionFunction() {

      return "ssoLogoutPluginAction";

   }

 

   /**

    * Returns the server types that this action is valid on.

    * 

    * @param Returns an empty string, because this action supports all server types.

    */

   public String getServerTypes() {

      return "";

   }

 

   /**

    * Returns the menu types that this action is appropriate.

    * 

    * @return an array of menu type identifiers

    */

   public String[] getMenuTypes() {

      return new String[] { "BannerUserSessionContextMenu" };

   }

 

   /**

    * Provides the name of the <code>ecm.model.Action</code> subclass to use when this plug-in action is invoked.

    * 

    * @return The name of an instance of <code>ecm.model.Action</code> to use

    *         for this action.

    */

   public String getActionModelClass() {

      return "ssoLogoutPluginDojo.SSOLogoutAction";

   }

}

 

 

The three methods to pay close attention to in this class are “getActionFunction”, “getMenuTypes” and “getActionModelClass”. The “getActionFunction” method tells IBM Content Navigator which JavaScript method contains the logic for this action. The “getMenuTypes” method isolates this action to the “BannerUserSessionContextMenu” menu type in IBM Content Navigator, while the “getActionModelClass” tells IBM Content Navigator to use the “ssoLogoutPluginDojo.SSOLogoutAction” provided with this plug-in instead of default “ecm.model.Action” class when creating this action. Now let’s review the custom SSOLogoutAction JavaScript class:

 

 

define(["dojo/_base/declare",

        "ecm/model/Desktop",

        "ecm/model/Action"],

function(declare, Desktop, Action) {

 

  /**

   * @name ssoLogoutPluginDojo.SSOLogoutAction

   * @class Describes a user-executable action, providing a custom SSO logout

   * @augments ecm.model.Action

   */

  return declare("ssoLogoutPluginDojo.SSOLogoutAction", [ Action ], {

  /** @lends ssoLogoutPluginDojo.SSOLogoutAction.prototype */

 

     constructor: function() {

        this.inherited(arguments);

        // Set the label to the standard logoff string, instead of displaying the name defined in the plugin action definition.

        this.name = this.messages.logout;

     },

 

     /**

      * Returns true if this action should be visible

      */

     isVisible: function() {

        // Only show the action if the desktop contains the redirect URL.

        if (Desktop.ssoLogoutRedirectURL) {

           return true;

        }

        return false;

     }

  });

});

 

This extension to the IBM Content Navigator ecm.model.Action JavaScript model class does two things:

  1. Overrides the name of the custom action with the “log out” text that is typically displayed for the IBM Content Navigator logout action. The name of this action is defined in the plugin action Java class above. You could set the text in the Java class to the text you want to render in the user interface, but since we know we want to render the standard text shown in IBM Content Navigator, we will override the plug-in text with text defined in IBM Content Navigator’s resource bundle.
  2. Overrides the “isVisible” method to ensure the action is only rendered when the SSO redirect URL is set in the desktop. Later I will demonstrate how to add the SSO redirect URL to the plugin configuration and include it in the desktop.

Now let’s review the JavaScript code, added to the main plugin JavaScript class “SSOLogoutPlugin.js”, that performs the actual logic behind the SSO log out:

 

/**

 * Provides a custom action that first executes the typical IBM Content Navigator Logout and then redirects to the SSO provider

 * logoff URL.

 *

 * @param repository A handle to the {@link ecm.model.Repository} object.

 */

lang.setObject("ssoLogoutPluginAction", function(repository) {

   // Get the layout widget from the desktop object in order to change the standard desktop logout behavior.

   Desktop.getLayout(function(layout) {

      // Disconnect the logout handler event in the standard layout widget to prevent the log in pane from displaying. Instead we will

      // redirect to the URL provided in the plugin configuration directly from the main layout pane.

      if (layout.repDisconnectHandler) {

          connect.disconnect(layout.repDisconnectHandler);

      }

 

      // Connect a new logout handler, which will handle the redirect after a standard desktop logoff.

      var logOffHandle = aspect.after(Desktop, "onLogout", function() {

          if (Desktop.ssoLogoutRedirectURL) {

             location.replace(Desktop.ssoLogoutRedirectURL);

          }

 

          // This is not necessary, since location.replace should clear this, but it's generally good practice to always ensure

          // you disconnect any handles you create. If we were not using location.replace, it's possible to create a memory leak

          // if you do not disconnect handles.

          if (logOffHandle)

             logOffHandle.disconnect();

      });

 

       // Call the desktop logoff method to ensure the typical logoff processing is done before redirecting to the plugin

       // provided redirect URL.

       Desktop.logoff();

   });

});

 

 

The first step in this action is to disconnect an event in the desktop layout. This is done to prevent the typical post-logoff behavior in IBM Content Navigator, which will show the user the log in pane. In this case, we do not want the log in pane to display. Instead we want the user to be redirected immediately to the redirect URL. The second part of this code handles the redirect, by connecting to the “onLogout” event method of the desktop. This event method fires as soon as the IBM Content Navigator log off server call completes successfully, so we connect to this event and use “location.replace” to replace the URL in the browser with the redirect URL. Finally we call the IBM Content Navigator desktop logoff API to initiate the typical IBM Content Navigator server log off behavior.

Now let’s review how we prompt the administrator to provide the redirect URL and set the redirect URL as a desktop parameter to ensure it’s available for the log off action. To prompt the administrator for the redirect URL and store it in the plugin configuration, we create a configuration pane to load for this plug-in in the IBM Content Navigator plug-in administration. Plug-in configuration panes MUST extend from the “ecm.widget.admin.PluginConfigurationPane” widget provided with IBM Content Navigator:

 

define([

   "dojo/_base/declare",

   "dijit/_TemplatedMixin",

   "dijit/_WidgetsInTemplateMixin",

   "ecm/widget/admin/PluginConfigurationPane",

   "ecm/widget/HoverHelp",

   "ecm/widget/ValidationTextBox",

   "./Messages",

   "dojo/text!./templates/ConfigurationPane.html"

],

function(declare, _TemplatedMixin, _WidgetsInTemplateMixin, PluginConfigurationPane, HoverHelp, ValidationTextBox, Messages, template) {

 

   /**

    * @name ssoLogoutPluginDojo.ConfigurationPane

    * @class Provides the configuration pane for the IBM Content Navigator plugin administration

    * @augments ecm.widget.admin.PluginConfigurationPane, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin

    */

   return declare("ssoLogoutPluginDojo.ConfigurationPane", [ PluginConfigurationPane, _TemplatedMixin, _WidgetsInTemplateMixin], {

 

      templateString: template,

      widgetsInTemplate: true,

      messages: Messages,

 

      postCreate: function() {

         this.inherited(arguments);

         // Set the hover help for the label in the configuration pane using a message defined in the JavaScript resource bundle.

         this.ssoLogoutURIHoverHelp.set("message", Messages.sso_logout_url_hover);

      },

 

      /**

       * Called when the plugin is loaded.

       *

       * @param callback Callback function.

       */

      load: function(callback) {

         // Set the value in the configuration pane input to the value saved in the plugin configuration. If this is the first time

         // the plugin has been loaded, the configuration string will be empty, so we first check for null before attempting to set

         // the value.

         if (this.configurationString) {

            var jsonConfig = eval('(' + this.configurationString + ')');

            this.ssoLogoutURI.set('value', jsonConfig.ssoLogoutUri);

         }

      },

 

      /**

       * Handles the change event on the configuration pane input box.

       */

      _onFieldChange: function() {

         var configJson = {  

            ssoLogoutUri: this.ssoLogoutURI.get('value')

         };

         this.configurationString = JSON.stringify(configJson);

         this.onSaveNeeded(true);

      },

 

      /**

       * Method called by the plugin configuration to validate the input from the user. The plugin cannot be saved if no

       * sso logout uri is provided.

       */

      validate: function() {

         if (!this.ssoLogoutURI.isValid())

            return false;

         return true;

      }

   });

});

 

In this configuration pane, we only need to prompt the user for a single parameter, the SSO redirect URL. The load function is called by the IBM Content Navigator plug-in administration to load this plug-in. If this is not the first time IBM Content Navigator has loaded this plug-in there will be a configuration string, which will contain the current SSO redirect URL. The “_onFieldChange” method handles the change event on the input box in the plug-in administration. Finally the validate method ensures we will not allow the administrator to save the plug-in without specifying an SSO redirect URL.

After we have prompted the administrator for the redirect URL and saved it in the configuration, we need to ensure it’s available at runtime for the log out action. To accomplish this goal, we create a response filter on the “getDesktop” service API and add the redirect URL to the desktop. A response filter is a plug-in extension that is loaded after IBM Content Navigator has finished executing a specific action, but prior to returning a response to the user. Response filters are typically used to manipulate the JSON return from an IBM Content Navigator service. In this case, we will use a response filter to insert our custom redirect URL into the desktop JSON payload. Below is the response filter for this plugin:

 

/**

 * Provides a filter for responses from a the IBM Content Navigator "getDesktop" service API.

 */

public class SSOLogoutPluginDesktopResponseFilter extends PluginResponseFilter {

 

   /**

    * Returns an array of the services that are extended by this filter.

    * 

    * @return A <code>String</code> array of names of the services.

    */

   public String[] getFilteredServices() {

      return new String[] { "/getDesktop" };

   }

 

   /**

    * Filters the response from the Desktop service, inserting the custom redirect URL saved in the plugin configuration.

    * 

    * @param serverType

    *            A <code>String</code> that indicates the type of server that

    *            is associated with the service.

    * @param callbacks

    *            An instance of the

    *            <code>{@link com.ibm.ecm.extension.PluginServiceCallbacks PluginServiceCallbacks}</code>

    *            class that contains functions that can be used by the service.

    * @param request

    *            An <code>HttpServletRequest</code> object that provides the

    *            request.

    * @param jsonResponse

    *            The <code>JSONObject</code> object that is generated by the

    *            service. Typically, this object is serialized and sent as the

    *            response. The filter modifies this object to change the

    *            response that is sent.

    * @throws Exception

    *             For exceptions that occur when the service is running.

    *             Information about the exception is logged as part of the

    *             client logging and an error response is automatically

    *             generated and returned.

    */

   public void filter(String serverType, PluginServiceCallbacks callbacks, HttpServletRequest request, JSONObject jsonResponse) throws Exception {

      String configStr = callbacks.loadConfiguration();

 

      if (configStr != null && configStr.length() > 0 && jsonResponse != null) {

         JSONObject configJson = null;

         try {

            configJson = JSONObject.parse(configStr);

         } catch (Exception e) {

            callbacks.getLogger().logError(this, "filter", "Configuration data is invalid for the SSOLogoutPlugin!", e);

         }

 

        // Add the custom parameter to the Desktop response.

        if (configJson != null) {

           jsonResponse.put("ssoLogoutRedirectURL", configJson.get("ssoLogoutUri"));

        }

      }

   }

}

 

The filter first uses the PluginServiceCallbacks class to get the configuration saved for this plug-in. The configuration should be a JSON format, so we parse it to a JSONObject. Finally we insert a new parameter called “ssoLogoutRedirectURL” into the desktop JSON payload and set the value to the “ssoLogoutUri” saved in the plugin configuration.

The last step to ensure the log out redirect URL is present in the runtime desktop is to make sure it’s extracted from the desktop JSON response payload and added to the desktop object. This is done with a small block of JavaScript code in the main plugin Javascript class “SSOLogoutPlugin.js”:

 

ready(function() {

   // Add the custom redirect URL provided in the plugin configuration to the Desktop, so it will be available later

   // for the custom action.

   aspect.after(Desktop, "onDesktopLoaded", function(response) {

      if (response.ssoLogoutRedirectURL) {

         Desktop.ssoLogoutRedirectURL = response.ssoLogoutRedirectURL;

      }

   }, true);

});

 

 

The “dojo/ready” class provides the “ready” function, which registers our function when the DOM is ready and all require calls have been resolved. Once the page is loaded, we attach a function to the “onDesktopLoaded” event method, which sets the redirect URL from the JSON response we added in our response filter to a variable on the Desktop model object.

Now that we have our action defined, a response filter in place and the JavaScript code written to set the redirect URL in the desktop and execute the log out, we have the extensions we need to enable the SSO redirect log out. To expose the action to the user we need to create a new version of the IBM Content Navigator default “BannerUserSessionContextMenu”. This can be done using the IBM Content Navigator menu configuration feature in the IBM Content Navigator administration. However, to make things easier I have included a plug-in extension to create the menu, so now we’re ready to deploy the plug-in to IBM Content Navigator.

Deploying the Plug-in

The following steps will walk you through deploying the plug-in to IBM Content Navigator 2.0.3:

1) Log in to the IBM Content Navigator administration and click on the Plug-ins link in the category list on the left.  After the plugin list loads, click on the “New Plug-in” button to deploy the SSOLogoutPlugin.jar file included in this ZIP file.

image

2) Copy the SSOLogoutPlugin JAR file to a location on your web application server. If you have other plug-ins installed, such as the External Data Services Plug-in, consider copying the plugin to the same directory. After copying the plug-in JAR file to a web application server location, you must provide the URL path to the plug-in JAR file in the new plug-in dialog. For example:

image

3) After specifying the path, click the “Load” button to load the plug-in. If the plug-in path is correct, you will be prompted for the SSO logout redirect URL. Specify the redirect URL and save the plug-in.

image

4) The plug-in adds a new custom logout action and creates a new version of the IBM Content Navigator banner user session menu definition. To enable the new menu, edit your Desktop definition. Click on the “Desktops” link in the category list on the left and click on the desktop you want to present the custom logout and then click the “Edit” button. After clicking the edit button, IBM Content Navigator will load the desktop configuration panel:

image

5) Click on the “Menus” tab. Scroll down to find the “Banner user session context menu” and click on the drop-down to change this menu to the new “BannerUserSessionSSOLogoutMenu”:

image

After setting the desktop menu, you will be able to use the new SSO redirect logout action from the banner drop-down menu in IBM Content Navigator!

 

The entire source of this solution can be found here.

 

[{"Business Unit":{"code":"BU053","label":"Cloud & Data Platform"},"Product":{"code":"SSCTJ4","label":"IBM Case Manager"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB45","label":"Automation"}}]

UID

ibm11280878