Hyperion Security Integration SDK Reference

# Hyperion Security Integration SDK Reference

This file contains the following sections:

Introduction

New Features

Environment Setup

Overview of Security Platform API Components

Sample Programs

Common Application-Implementation Examples

Guidelines for Writing a Custom Provider

Java API Documentation

## Introduction

The Hyperion security platform provides authentication operations between Hyperion applications. This documentation describes the application programming interface that is provided by the security platform.

The security platform provides a unified authentication capability between Hyperion products and an authentication framework that enables the development of custom-built authentication modules.

The security platform includes the following capabilities:

- A userid and password authentication mechanism that can be used by all Hyperion products and that supports multiple authentication providers
- A plug-in style architecture that enables customers to use their preferred authentication method, for example, Microsoft Active Directory (MSAD), Lightweight Directory Access Protocol (LDAP) directories, Windows NT LAN Manager (NTLM) domains, or a custom scheme
- Support for the development of custom authentication modules; for example, modules that interact with authentication information stored in a relational database
- Secure transmission of authentication data within an intranet or Internet environment

In order to be granted access to a Hyperion application or a resource within a Hyperion application, users need to prove their identities. Users commonly provide authentication credentials each time they log on to a Hyperion application (for example, a username and password or a certificate). The user information is commonly stored as part of the Hyperion application or resource.

Integration into the Hyperion security platform eliminates the need for users to provide credentials to each and every Hyperion resource accessed. The Hyperion security platform takes advantage of user information stored outside Hyperion resources, in a corporate authentication repository such as an LDAP directory, a Windows NT LAN Manager domain, or Microsoft Active Directory. Assuming that such a corporate store exists, administrators of Hyperion applications can enable the following:

- Log on of externally authenticated users to any Hyperion application.
- Single sign-on, using the external credentials, between multiple Hyperion applications.

Single sign-on allows user credentials stored in a common location to be passed from one Hyperion application to another Hyperion application, so that users do not have to authenticate separately on each Hyperion application.

Top

## New Features

The following functionality is new to this release of the Hyperion security platform.

- Single sign-on with Web access management solutions is enabled. If your corporate data is protected by a Web access management solutions provider such as Netegrity SiteMinder, you can configure the security platform to require only that users authenticate through SiteMinder, after which they will not be required to present credentials again when logging in to Web-based Hyperion applications.

  > Note: Essbase is not a Web-based application, so single sign-on is not applicable for Essbase.

- Hyperion Remote Authentication Module can be used to link Windows domains. The Hyperion Remote Authentication Module, formerly called the NTLM Remote Server, can be installed from the Hyperion Download Center. In addition to enabling UNIX application users to log in using a Windows domain, the Hyperion Remote Authentication Module also allows Hyperion applications to authenticate users belonging to other domains that are not trusted by the domain on which the Hyperion application is installed. This removes the necessity to establish trust relationships between the domains. For example, Hyperion Planning users can log in using either the DOMAIN_1 domain hosted on corpsvr1, or log in using DOMAIN_2 domain hosted on corpsvr2, as long as there is a Remote Authentication Module linking corpsvr1 and corpsvr2.

Top

## Environment Setup

### Supported Authentication Repositories

These instructions assume that you have access to a corporate authentication repository containing user and group information and that you want to use the security platform to implement the corporate authentication schema with your custom Hyperion application.

The following authentication repositories are supported as built-in providers to the security platform package:

- Windows NT LAN Manager (NTLM): NT 4.0 Service Pack 6 or higher, Windows 2000, Windows 2003
- LDAP version 3 compatible directories:
  - iPlanet 5.2 or higher (now known as Sun TM Open Net Environment [Sun ONE])
  - Novell eDirectory 8.7 or higher
  - IBM Directory Server 5.1
  - Domino LDAP 5.x or 6.0
- Microsoft Active Directory server: Windows 2000 Server and Advanced Server, Service Pack 3 or higher

### Supported Operating Systems

The following operating systems are supported for Hyperion applications using the security platform API: Check the operating system requirements for the Hyperion application development platform that you are using.

- Solaris 8 and 9
- AIX 5.1L
- HP-UX 11.i
- Windows NT 4.0 Service Pack 6a or higher
- Windows 2000 Server and Advanced Server, Service Pack 3 or higher

### Installation Recommendations

To set up your system for implementing the security platform,

1. Because you are working with a Java package, ensure installation of JDK 1.3.1 or later from the Java TM 2 Platform, Standard Edition (J2SETM). JDK 1.4.1 or later is recommended and is the version that Analytic Services installs with all platforms. Check the Analytic Services Installation Guide and the Readme for the latest platform information.
2. Install Analytic Services and the Analytic Services API. The main security components as they are installed with Analytic Services are described below:

   `HYPERION_HOME\common\CSS\2.5.x\configuration\css-full.xml` | A sample XML configuration file.
   `HYPERION_HOME\common\CSS\2.5.x\bin\css-2_5_x.dll` | A .dll enabling the security platform to use NT LAN Manager.
   `HYPERION_HOME\common\CSS\2.5.x\lib\css-2_5_x.jar` | The security platform .jar file. Required external .jar files (listed under Dependencies) are also installed here.

3. Make sure that all the .jar files (and the configuration XML file) are in the classpath. For example, on Windows:

       %HYPERION_HOME%\common\CSS\2.5.0\lib\;%HYPERION_HOME%\common\CSS\2.5.0\lib\css-2_5_0.jar;
       %HYPERION_HOME%\common\XML\JDOM\0.8.0\jdom.jar;
       %ARBORPATH%\java\lib\log4j.jar;%HYPERION_HOME%\common\XML\JAXP\1.2.2\dom.jar;
       %HYPERION_HOME%common\XML\JAXP\1.2.2\xercesImpl.jar;%HYPERION_HOME%common\XML\JAXP\1.2.2\sax.jar;
       %HYPERION_HOME%common\XML\JAXP\1.2.2\jaxp-api.jar

   Classpath settings are IDE dependent, so if you need instructions for setting the classpath, see the documentation for your Java development environment.
4. The security platform supports Level 1 localization (as specified in the Java specification ResourceBundle). Localization is possible using the `CSSMessages.properties` file located in the security platform jar file.
5. Edit the configuration XML file to suit your environment. See Configuration.
6. Edit the source code for the application-interface-implementation sample class, `MyApp.java`, to point to the location of your configuration file.

### Dependencies

If you are developing a program that needs to share single sign-on with other Hyperion applications, ensure that those other Hyperion applications support single sign-on before beginning development. Check the product documentation, and check for the existence of `css-2_0_0.jar` (or a higher version, such as `css-2_0_7.jar`) in the product installation.

You need the tools described in the List of Dependencies in addition to the security platform components supplied with your Hyperion application development toolkit. Your Hyperion application development platform may already include some or all of these tools, but use the following list to check that you have everything that is needed.

Notes:

- If you are using JDK 1.4.1_01, all but JDOM and Log4j are included in that package. Be sure to add `sax.jar`, `dom.jar`, and `xercesImpl.jar` to the classpath as indicated in the JAXP section below.
- If you are using JDK 1.3.1, you need to install each of the dependencies separately.
- If you are using JDK 1.3, validation will not occur. The JAXP section below contains details.
- If you are not planning to use Secure Sockets Layer (SSL) for secure data transmission to and from an LDAP-compatible directory, or to specify the location of the configuration file, then you do not need the JSSE dependency listed below. If you use the `https://` protocol, you are using SSL and therefore you need this dependency.

List of Dependencies

Refer to the following list to be sure you have everything that you need:

- JavaTM API for XML Processing (JAXP), version 1.2. This dependency enables XML processing and validation of the Hyperion application configuration files. Available at http://java.sun.com/xml/jaxp/index.html. The included `sax.jar`, `xercesImpl.jar`, and `dom.jar` need to be included in the classpath for your project. If you are using JDK 1.3.1, you also need to include `jaxp-api.jar` in your classpath, because it is not included in JDK 1.3.1.
  Note: If the security platform is not configured with JAXP 1.2, validation of configuration does not occur; however, the security platform still functions if the configuration file is valid and has the required information. Therefore, JDK 1.3.1 and above is recommended, but you can use JDK 1.3 with JAXP 1.1 (as JDK 1.3 does not support JAXP 1.2) if you proceed with caution.
- JDOMTM Beta8. This dependency also enables XML processing of the Hyperion application configuration files. Available at http://jdom.org. The included `JDOM.jar` needs to be included in the classpath for your project.
- Apache Log4j, version 1.2.7 or later. This dependency is the mechanism for the security platform logging framework. Available from the Apache Jakarta Project, at http://jakarta.apache.org/log4j/docs/index.html. The included `log4j-1.2.7.jar` needs to be included in the classpath for your project.
- JavaTM Cryptography Extension (JCE), version 1.2 or later. This enables the cryptography framework for the security platform. JCE is included with JDK 1.4 and is located in the installation of JDK 1.4 at `%JRE_HOME%/lib/jce.jar`. If you are using JDK 1.3.1, JCE is also available at http://java.sun.com/products/jce/, and is packaged in a `.zip` file with Analytic Services on AIX. For JDK 1.3.1 users, the following included `.jar` files need to be included in the classpath for your project: `jce1_2_2.jar`, `local_policy.jar`, `sunjce_provider.jar`, and `US_export_policy.jar`.
- Java Naming and Directory InterfaceTM (JNDI), including the LDAP service provider. This dependency enables the security platform to work with LDAP directories. Available at http://java.sun.com/products/jndi/. JNDI is included in JDK 1.3.1 and higher, so you should not need to add anything to the classpath for JNDI.
- JavaTM Secure Sockets Extension (JSSE), version 1.0.3 or later. You need this dependency if you want to enable secure data transmission using the SSL protocol (Secure Sockets Layer). Available at http://java.sun.com/products/jsse/. JSSE is included in JDK 1.4 and higher, so you should not need to add anything to the classpath if you are using JDK 1.4. If you are using JDK 1.3.1, you must do the following:
  1. Download and install the JSSE extension from http://java.sun.com/products/jsse/; or, if you are using Analytic Services on AIX, this is packaged as a `.zip` file with Analytic Services.
  2. Add the following included `.jar` files to the classpath for your project: `jcert.jar`, `jnetr.jar`, and `jsse.jar`.
  3. Set the Java system properties to include support for the protocol. For example:

         java -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol

### Configuration

Configuration is the responsibility of the administrator or installer of the Hyperion application that uses the security platform with a corporate authentication repository. To enable external authentication, the administrator or installer should modify the `.xml` configuration document provided with the Hyperion application to match properties and attributes of the corporate directory store. To enable single sign-on, the administrator using more than one Hyperion application should select and configure one `.xml` configuration file to be shared by multiple Hyperion applications. The administrator should perform configuration as specified in the documentation for each Hyperion application. If it is necessary to use multiple configuration files, care should be taken to ensure that the separate configurations all point to the same directory store.

See the "Security Platform Reference" section of the Technical Reference to find the Analytic Services configuration documentation.

Top

## Overview of Security Platform API Components

The diagram below depicts a flexible authentication architecture that allows Hyperion customers to choose the authentication system to be used. This authentication architecture is loosely modeled after the Java Authentication and Authorization Services (JAAS) model. This architecture supports the concept of an authentication plug-in that interfaces with the underlying authentication system. This feature allows Hyperion and its partners and customers to write plug-in Hyperion application programs to standard and custom authentication systems.

### Architecture Diagram

The security platform is a multi-layered system.

The following are the components of the security platform:

- Application interface. The access point for Hyperion applications to the security platform is through the application interface (represented in the drawing as AppIF). The application interface is the contract that must be implemented by Hyperion applications in order to:
  - initialize the security platform
  - provide the location of the Hyperion application configuration file to the security platform
  - provide the necessary details to enable the security platform to log messages in the format required by the Hyperion application
- Security platform API. The security platform API implements the logic necessary to allow Hyperion applications to transparently connect using the application interface to the external authentication provider, without being concerned with provider specific functionality.
- Provider SPI. The service provider interface (SPI) implements the logic necessary to authenticate a user stored in a specific provider. LDAP, NTLM, and MSAD are built-in provider implementations. In the future, the Provider SPI can be used to build support for custom security providers.

### Communication Between the Layers

#### How Hyperion Applications Communicate with the Security Platform

The application interface specifies the contract that the Hyperion-based application (such as Hyperion Financial Management, Hyperion Planning, or a third-party Hyperion application) needs to implement. Primarily, the application interface provides a callback so the security platform API can communicate back into the Hyperion application. Hyperion applications (such as Planning) initialize the security platform API component by providing a reference to their implementations of the application interface (CSSApplicationIF). This reference allows the security platform API to interact with the Hyperion application as necessary. Thus, the Hyperion application provides a callback object (in the form of the implementation of the CSSApplicationIF) that the security platform component can use to perform functions such as the following:

- Getting the URL of the Hyperion application configuration file
- Logging messages into the Hyperion application log file
- Getting the user identities and sending them back to the calling Hyperion application
- Re-assigning user identities

The Hyperion application initiates the conversation by getting the handle of the security platform component, using the CSSSystem class in the security platform API:

    CSSSystem system = CSSSystem.getInstance();
    CSSAPIIF api = system.getCSSAPI();

Subsequently, the implementation of the CSSApplicationIF (provided by the Hyperion application) is used to initialize CSS API:

    CSSApplicationIF testAppCallback = new TestAppImpl();
    api.initialize(testAppCallback);

#### How the Security Platform Communicates with the Hyperion Application

The security platform interface interacts with the calling Hyperion application using a callback interface. After the security platform API is initialized, it is able to make calls back to the calling Hyperion application in order to get more details about the Hyperion application, such as the location of the Hyperion application configuration file, the identities of the Hyperion application users, and where to send messages for the Hyperion application to include in its log file.

#### What Kind of Communication Is Needed Between the Hyperion Application and the Security Platform

Implementations of the CSSApplicationIF are passed to the security platform API, allowing the security platform API to interact back to the calling Hyperion application, retrieving specific data (such as the configuration file URL), and sending information to the Hyperion application log.

See MyApp.java for an example of how the application interface must implement the methods getConfigFile() and log().

The security platform component may also need to call back the Hyperion application (for example, Planning) to tell it to perform certain methods, such as get information about user identities or reset user identities. See the javadoc for the methods getUserIdentities() and reAssignIdentity(), in CSSApplicationIF.

### API Documentation

The reference documentation for the Hyperion Security Integration SDK can be launched from this link.

Top

## Sample Programs

The following sample applications and classes are included to help you learn how to implement the security platform API interfaces.

`CSSHelloWorld.java` is a sample application demonstrating the use of the security platform for external authentication of users and groups in a directory.

`CSSHelloSSO.java` is a sample application additionally that demonstrates single sign-on, wherein when an application launches another application, the user's logon credentials are remembered.

`MyApp.java` is a sample callback class that is used by the sample applications `CSSHelloWorld.java` and `CSSHelloSSO.java` in order to get information about the application configuration and message-logging requirements. MyApp.java is a sample implementation of the application interface, `CSSApplicationIF`.

`MySSOApp.java` is a sample callback class that is used by the sample application `CSSHelloSSO.java` in order to authenticate users based on a token rather than requiring users to log on again when moving to a second application. MySSOApp.java is a sample implementation of the application interface, `CSSApplicationIF`.

`CSSHelloSSOWithSA.java` demonstrates the authentication of users that exist in the external repository using headers populated by a security agent.

`CSSSampleAlgoImplementation.java` demonstrates the implementation of the algorithm for authenticating a user using the security platform in an environment where the resources are protected by a security agent.

### MyApp.java

The `MyApp.java` class implements the application interface, known as `CSSApplicationIF` in the package `com.hyperion.css.application`.

This class 1) specifies a configuration, which is required in order to initialize the security platform, and 2) specifies a log method to store the messages from the security platform; for example, messages can be logged in the application's specified log file format.

    package sampleApplications;
    import java.io.File;
    import java.net.MalformedURLException;
    import java.net.URL;

    import com.hyperion.css.CSSException;
    import com.hyperion.css.application.CSSApplicationIF;

    /**
     * <p>This class implements the application interface, providing the security platform
     * interface with a callback object.</p>
     *
     * <p>The callback object is invoked for the purposes of the security platform
     * gaining access to the configuration and providing log messages to the
     * calling application.</p>
     *
     * @author gkhanna
     */
    public class MyApp implements CSSApplicationIF
    {

      /**
       * <p>Replace with the path where your configuration file is kept.</p>
       */
      public String path = "C:/temp/sample.xml";

      /**
       * <p>This returns the configuration file for the security platform to initialize and
       * be configured.</p>
       *
       * @see com.hyperion.css.application.CSSApplicationIF#getConfigFile()
       */
      public URL getConfigFile()
      {
        try
        {
          return new URL("file://localhost/" + path);
        }
        catch (MalformedURLException e)
        {
          System.out.println("Exception while creating URL: " +e);
          return null;
        }
      }

      /**
       * @see com.hyperion.css.application.CSSApplicationIF#log(String)
       */
      public void log(String message)
      {
        System.out.println(message);
      }

      /**
      * @see com.hyperion.css.application.CSSApplicationIF#getUserIdentities()
       */
      public String[] getUserIdentities()
      {
        return null;
      }
      /**
       * @see com.hyperion.css.application.CSSApplicationIF#reAssignIdentity(String, String)
       */
      public void reAssignIdentity(String originalIdentity, String newIdentity)
      {
      }

    }

Up

### CSSHelloWorld.java

This sample application uses the application-contract implementation in the class `MyApp.java` to 1) initialize the security platform and 2) invoke the security platform in order to retrieve users and groups from an external repository.

The security platform responds to the application's request to print user and group information. Based on the configuration specified in the application's configuration file, the security platform searches the appropriate directory or directories, and prints the requested user and group information to the application console.

    package sampleApplications;
    import java.util.HashMap;
    import java.util.Map;

    import com.hyperion.css.CSSAPIIF;
    import com.hyperion.css.CSSException;
    import com.hyperion.css.CSSSystem;
    import com.hyperion.css.common.CSSGroupIF;
    import com.hyperion.css.common.CSSUserIF;

    /**
     * This sample application interacts with the security platform interface
     * (@link com.hyperion.css.CSSAPIIF}, walking through groups in the directory
     * and printing user and group information.
     * The user and group information is printed recursively.
     *
     * <p>This application uses the following classes of this package:
     * <ul>
     * <li> <tt>MyApp.java</tt>
     * </ul>
     * </p>
     *
     */
    public class CSSHelloWorld
    {
    	static CSSSystem system = CSSSystem.getInstance();
    	static CSSAPIIF css = system.getCSSAPI();
    	static Map context = new HashMap();

    	/**
    	 * Main part of program: Create instance of application MyApp,
    	 * and write back to the log file of MyApp if exceptions occur.
    	 *
    	 * @param args
    	 */
    	public static void main(String args[])
    	{

    		/**
    		 * create the app instance.
    		 */
    		CSSGroupIF g[];
    		int i = 0;

    		MyApp myApp = new MyApp();
    		try
    		{
    			context.clear();
    			css.initialize(myApp);
    			g = css.getGroups(context, null);
    			for (i = 0; i < g.length; i++)
    				printGroup(g[i], 0);
    		}
    		catch (CSSException e)
    		{
    			myApp.log("EXCEPTION: " + e);
    		}
    		// Print the root group
    	}

    	/**
    	 * Print the groups on a particular level.
    	 *
    	 * @param String[] groups - the groups to print.
    	 * @param level - the level of the groups.
    	 */
    	public static void printGroups(String groups[], int level)
    		throws CSSException
    	{
    		int i = 0;
    		CSSGroupIF g;
    		for (i = 0; i < groups.length; i++)
    		{
    			context.clear();
    			g = css.getGroupByIdentity(context, groups[i]);
    			printGroup(g, level);
    		}
    	}

    	/**
    	 * Print the group and the level recursively.
    	 *
    	 * @param g - the group to print, along with all its subgroups and users, recursively.
    	 * @param level - the level of the group in the hierarchy.
    	 */
    	public static void printGroup(CSSGroupIF g, int level) throws CSSException
    	{
    		System.out.println("Level: " + level);
    		System.out.println("Group Name: " + g.getName());
    		System.out.println("Group Identity: " + g.getIdentity());

    		printUsers(g.getUserList(), level + 1);
    		printGroups(g.getGroupList(), level + 1);
    	}

    	/**
    	 * Print users' first names and identity strings, and their corresponding levels.
    	 *
    	 * @param users
    	 * @param level - the level of the users in the group hierarchy.
    	 */
    	public static void printUsers(String users[], int level)
    		throws CSSException
    	{
    		int i = 0;
    		CSSUserIF u;
    		for (i = 0; i < users.length; i++)
    		{
    			context.clear();
    			u = css.getUserByIdentity(context, users[i]);
    			System.out.println("    Level: " + level);
    			System.out.println("    First Name is:" + u.getFirstName());
    			System.out.println("    Identity is:" + u.getIdentity());
    		}
    	}
    }

Up

### MySSOApp.java

`MySSOApp.java` is a sample class that demonstrates how to authenticate a user based on a token passed from another application. This class is used by the sample application `CSSHelloSSO.java` to authenticate a user and log information about the authenticated user. This class also makes use of the callback class `MyApp.java`.

    package sampleApplications;
    import java.util.HashMap;
    import java.util.Map;

    import com.hyperion.css.CSSAPIIF;
    import com.hyperion.css.CSSException;
    import com.hyperion.css.CSSSystem;
    import com.hyperion.css.common.CSSUserIF;

    /**
     * This class demonstrates how to authenticate a user
     * based on a token passed from another application -
     * this application authenticates a user, logs information
     * about the authenticated user, and then quits.
     *
     */
    public class MySSOApp extends Thread
    {

      private Map context;
      private CSSSystem system;
      private CSSAPIIF css;
      private MyApp myApp;
      private String appIdentity;

      public MySSOApp(String CSSToken, String identity)
      {

        context = new HashMap();

        /**
         * Put the token received into the context and do
         * initialization. The actual authentication takes place in the
         * run() method.
         *
         */
        context.put(CSSAPIIF.TOKEN, CSSToken);
        appIdentity = identity;
        system = CSSSystem.getInstance();
        css = system.getCSSAPI();
        myApp = new MyApp();
        try
        {
          css.initialize(myApp);
        }
        catch (CSSException e)
        {
          myApp.log("Exception in constructor for " + appIdentity);
          myApp.log(e.toString());
        }
      }

      public void run()
      {

        try
        {
          /**
           *  Authenticate is called in the same way...
           */
          CSSUserIF user = css.authenticate(context);

          /**
           *  Authentication succeeded and application continues...
           */
          displayUser(user);
          myApp.log(appIdentity + " quitting...");
        }
        catch (CSSException e)
        {
          myApp.log("Exception in authenticate for " + appIdentity);
          myApp.log(e.toString());
        }

      }

      private void displayUser(CSSUserIF user) throws CSSException
      {
        if (user == null)
        {
          myApp.log("USER IS NULL");
          return;
        }
        StringBuffer buffer = new StringBuffer("****"+appIdentity+"******USER IS: ");
        buffer.append("\n");
        buffer.append("First Name: " + user.getFirstName() );
        buffer.append("\n");
        buffer.append("Last Name: " + user.getLastName() );
        buffer.append("\n");
        buffer.append("Email : ");
        String [] emails = user.getEmailAddress();
        if (emails != null)
        {
          for (int i = 0; i < emails.length; i++)
          {
            buffer.append(emails[i]);
            buffer.append("\t");
          }
        }
        buffer.append("\n");
        buffer.append("Identity: " + user.getIdentity() );
        buffer.append("\n");
        buffer.append("Token: " + user.getToken() );
        buffer.append("\n");
        buffer.append("Groups List: ");
        String[] groups = user.getGroupsList();
        if (groups != null)
          for (int i = 0; i < groups.length; i++)
          {
            buffer.append(groups[i]);
            buffer.append("\t");
          }
        Map otherProps = user.getUserInfo();
        buffer.append("\nlogin name: "  +otherProps.get(CSSAPIIF.LOGIN_NAME) );

        myApp.log(buffer.toString() );

      }
    }

Up

### CSSHelloSSO.java

`CSSHelloSSO.java` is a sample application that demonstrates use of the authenticate() method for authentication of user names and passwords, as well as the token authentication that enables single sign-on. This application provides token-passing services to the application implementations represented by `MySSOApp.java` and `MyApp.java`.

    package sampleApplications;
    import java.util.HashMap;
    import java.util.Map;

    import com.hyperion.css.CSSAPIIF;
    import com.hyperion.css.CSSException;
    import com.hyperion.css.CSSSystem;
    import com.hyperion.css.common.CSSUserIF;

    /**
     * This sample application demonstrates the authentication of users to the
     * external repository using simple (user names and password combination)
     * and token based authentication.
     *
     * <p>This application authenticates a user using a userName and password.
     * It then passes the user credentials as a token to the
     * constructor for mySSOApp1 and mySSOApp2. These hypothetical applications,
     * when launched, authenticate the same user using the token. </p>
     *
     * <p>This application uses the following classes of this package:
     * <ul>
     * <li> <tt>MyApp.java</tt>
     * <li> <tt>MySSOApp.java</tt>
     * </ul>
     * </p>
     *
     */
    public class CSSHelloSSO
    {

    	static CSSSystem system = CSSSystem.getInstance();
    	static CSSAPIIF css = system.getCSSAPI();

    	/**
    	 *  Instantiate the class that implements CSSApplicationIF
    	 */
    	static MyApp myApp = new MyApp();

    	public static void main(String[] args)
    	{

    		try
    		{
    			/**
    			 * Replace userName and userPassword
    			 * with appropriate values for your environment
    			 */
    			String userName = "Jeff";
    			String userPassword = "Jeff";

    			/**
    			 * Create a context and populate it with
    			 * the userName and userPassword
    			 */
    			Map initialContext = new HashMap();
    			initialContext.put(CSSAPIIF.LOGIN_NAME, userName);
    			initialContext.put(CSSAPIIF.PASSWORD, userPassword);

    			/**
    			 * Initialize css
    			 */
    			css.initialize(myApp);

    			/**
    			 * Authenticate the user in the first application
    			 */
    			CSSUserIF user1 = css.authenticate(initialContext);

    			/**
    			 * Authenticate another user
    			 */
    			userName = "Gary";
    			userPassword = "Gary";

    			initialContext.clear();
    			initialContext.put(CSSAPIIF.LOGIN_NAME, userName);
    			initialContext.put(CSSAPIIF.PASSWORD, userPassword);

    			CSSUserIF user2 = css.authenticate(initialContext);

    			/**
    			 * Authenticate yet another user
    			 */
    			userName = "Susan";
    			userPassword = "Susan";

    			initialContext.clear();
    			initialContext.put(CSSAPIIF.LOGIN_NAME, userName);
    			initialContext.put(CSSAPIIF.PASSWORD, userPassword);

    			CSSUserIF user3 = css.authenticate(initialContext);

    			/**
    			 * When the user moves to another application,
    			 * only the token needs to be passed to that
    			 * application.
    			 *
    			 * Lets consider mySSOApp1 and mySSOApp2 to be two such
    			 * applications that authenticate the user using the token
    			 */
    			MySSOApp mySSOApp1 = new MySSOApp(user1.getToken(), "mySSOApp1");
    			MySSOApp mySSOApp2 = new MySSOApp(user2.getToken(), "mySSOApp2");
    			MySSOApp mySSOApp3 = new MySSOApp(user3.getToken(), "mySSOApp3");

    			mySSOApp1.start();
    			mySSOApp2.start();
    			Thread.sleep(2000);
    			mySSOApp3.start();
    		}
    		catch (Exception e)
    		{
    			myApp.log(" Exception in CSSHelloSSO ");
    			myApp.log(e.toString());
    			e.printStackTrace();
    		}
    	}
    }

### CSSHelloSSOWithSA.java

This application demonstrates the authentication of users that exist in the external repository using headers populated by a security agent. A security agent is a security system employed by companies to manage and enforce authentication, authorization, and single sign-on. Example: Netegrity SiteMinder. The Hyperion security platform enables single sign-on for a user into a Web-based Hyperion application without challenging the user for credentials, as long as the security agent has already authenticated the user. Integration with a security agent requires configuration of the `<securityAgent></securityAgent>` element in the XML configuration file.

    package sampleApplications;
    import java.util.HashMap;
    import java.util.Locale;
    import java.util.Map;

    import com.hyperion.css.CSSAPIIF;
    import com.hyperion.css.CSSException;
    import com.hyperion.css.CSSSystem;
    import com.hyperion.css.common.CSSUserIF;

    /**
     * <p>This sample application demonstrates the authentication of users
     * that exist in the external repository using headers populated by
     * the Security Agent.</p>
     * <p> The pre-condition to running this sample is the presence
     * of the <tt><securityAgent></tt> element in the configuration and
     * the availability of the <tt>login name</tt> as an argument to
     * the <tt>authenticate</tt> method.</p>
     * <p>The user is authenticated based on the header that is passed.
     * A token is generated upon authentication. This sample application
     * also demonstrates authentication by using the token that is generated.</p>
     *
     * <p>This application authenticates a user using a <tt>login name</tt> when the
     * Security Agent is configured.
     * It then passes the user credentials as a token to the
     * constructor for mySSOApp1. This hypothetical application,
     * when launched, authenticates the same user using the token. </p>
     *
     * <p>This application uses the following classes of this package:</p>
     * <ul>
     * <li> <tt>MyApp.java</tt>
     * <li> <tt>MySSOApp.java</tt>
     * </ul>
     *
     *
     * @author gkhanna
     */
    public class CSSHelloSSOWithSA
    {

    	static CSSSystem system = CSSSystem.getInstance();
    	static CSSAPIIF css = system.getCSSAPI();

    	/**
    	 *  Instantiate the class that implements CSSApplicationIF
    	 */
    	static MyApp myApp = new MyApp();

    	/**
    	 * Main part of the program that details the invocation of the
    	 * CSS authenticate method when a SecurityAgent provided header
    	 * whose value is the "login name" for an user is available.
    	 */
    	public static void main(String[] args)
    	{

    		try
    		{
    			/**
    			 * The login name is retrieved from the HTTP headers.
    			 * Subsitute the value here with any other value that exists
    			 * in the directories that are specified in the configuration.
    			 */
    			String loginNameFromHeader= "Jeff";

    			/**
    			 * Create a context and populate it with
    			 * the userName and userPassword
    			 */
    			Map context = new HashMap();
    			context.put(CSSAPIIF.LOCALE, new Locale("en", "US"));
    			context.put(CSSAPIIF.LOG_PREPEND_TEXT, "[APP_NAME/1.0.0]");
    			/**
    			 * This is the path to the configuration file.
    			 * Subsitute this with a valid path to your configuration file.
    			 */
    			myApp.path = "C:/temp/sample.xml";

    			/**
    			 * Initialize the security platform.
    			 */
    			css.initialize(context, myApp);

    			/**
    			 * Specify to the security platform that the authentication is to be performed based
    			 * on the condition that the Security Agent (for example, SiteMinder)
    			 * has already authenticated the user.
    			 */
    			context.put(CSSAPIIF.SECURITY_AGENT_LOGIN_NAME, loginNameFromHeader);

    			/**
    			 * Authenticate the user in the first application.
    			 */
    			CSSUserIF user1 = css.authenticate(context);

    			context.clear();

    			/**
    			 * When the user moves to another application,
    			 * only the token needs to be passed to that
    			 * application.
    			 *
    			 * Presume that mySSOApp1 is an application
    			 * that authenticates the user using the token.
    			 */
    			MySSOApp mySSOApp1 = new MySSOApp(user1.getToken(), "mySSOApp1");

    			mySSOApp1.start();
    		}
    		catch (Exception e)
    		{
    			myApp.log(" Exception in CSSHelloSSOWithSA ");
    			myApp.log(e.toString());
    			e.printStackTrace();
    		}
    	}
    }

### CSSSampleAlgoImplementation.java

This application demonstrates the implementation of the algorithm for authenticating a user using the security platform in an environment where the resources are protected by a security agent such as Netegrity SiteMinder. This application differs from CSSHelloSSOWithSA in that it implements the algorithm that the custom application's Web interface should implement. The security agent provides the Web interface with the required HTTP header information. In contrast, CSSHelloSSOWithSA demonstrates invocation of the security platform from the Web application.

    package sampleApplications;

    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Hashtable;
    import java.util.Locale;
    import java.util.Map;

    import com.hyperion.css.CSSAPIIF;
    import com.hyperion.css.CSSException;
    import com.hyperion.css.CSSSystem;
    import com.hyperion.css.common.CSSUserIF;

    /**
     * <p>This class demonstrates the implementation of the algorithm
     * for authenticating a user using the security platform in an environment where
     * the resources are protected by a Security Agent. </p>
     *
     * <p>The Security Agent could be Netegrity SiteMinder.</p>
     *
     * <p>The algorithm is detailed below (in pseudo code):</p>
     *  <pre>
     * Variable Definitions:
     * 1. HeadersThatHoldTheLoginName[] => this is an array containing the names
     * of the headers - one entry of which should be present in the HTTP request in order to
     * extract its value (the login name). The login name is then used to perform
     * single sign-on from a Security Agent into a Hyperion Application.
     * The Hyperion Application must have an HTTP interface in order for single sign-on to succeed.
     * Each entry in the array contains the name of the header that could carry the
     * the login name. The reason for having more than one header is to account for the
     * differences in representing HTTP Request headers in Web servers. For
     * instance: a header HTTP_HYPERION_ABC_DEF in IIS would appear as
     * hyperion-abc-def in Tomcat.
     * 2. LoginNameFromHeader => holds the value of the login name from the header whose name
     * is specified by an entry in "HeaderThatHoldsTheLoginName"
     * 3. HTTPRequest => this specifies the wrapper for the HTTP Request object. This holds the HTTP request headers.
     * 4. CSSToken => holds the token that has been passed to the Hyperion Application for single sign-on.
     * This is per the token-passing specifications.
     * 5. CSSAPI => the reference to the security platform API.
     * 6. Context => the Map argument containing name-value pairs for the authenticate method.
     * 7. LoginName => the login name of the user that is entered on the login page.
     * 8. Password => the password entered by the user on the login page.
     *
     * begin()
     * {
     * HeadersThatHoldTheLoginName[] = null;
     * LoginNameFromHeader = null;
     * // Gets the HTTP Request from the container.
     * HTTPRequest = getHTTPRequest();
     * CSSToken = null;
     * CSSAPI = null;
     * Context = null;
     * CSSAPI = getCSSAPI();
     * Context = createContext(locale);
     * CSSAPI.initialize(context);
     *
     *
     * if (CSSAPI.isSecurityAgentEnabled() )
     * {
     * 	// get the array of entries where each entry specifies a header name
     *	// that is used by the Security Agent to populate the login name of the user.
     *  HeadersThatHoldTheLoginName = CSSAPI.getHeaderNamesFromSecurityAgent(context);
     * 	// get the login name from the header in the HTTP Request
     * 	LoginNameFromHeader = getFromHTTPHeaders(HTTPRequest, HeadersThatHoldTheLoginName);
     * 	if (LoginNameFromHeader != null)
     * 		addToContext(Context, "SECURITY_AGENT_LOGIN_NAME", LoginNameFromHeader);
     * }
     *
     * if (LoginNameFromHeader == null)
     * {
     * 	// this implies that the security platform is not configured for Web Security Agent or
     * 	// that the security platform is configured but the header is not present.
     * 	CSSToken = getTokenFromHTTPRequest();
     * 	if (CSSToken == null)
     * 	{
     * 		popUpDialog(LoginName, Password);
     * 		AddToContext(Context, "LOGIN_NAME", LoginName);
     * 		AddToContext(Context, "PASSSORD", password)
     * 	}
     * 	else
     * 	{
     * 		// the token is added to the context.
     * 		AddToContext(Context, "TOKEN", CSSToken)
     * 	}
     * }
     *
     * CSSUser = CSSAPI.authenticate(Context);
     * }
     *
     * <p>This algorithm specifies the integration with a Security Agent.</p>
     * <p>
     * CSSSampleAlgoImplementation is a sample implementation of the algorithm that is
     * implemented in the Web-tier by security platform clients. Please note
     * that this is a sample implementation intended only to help you understand the
     * implementation of the algorithm. It is not intended to be used as commercial-quality code.
     *
     * @since CSSv2.5
     * @author gkhanna
     */
    public class CSSSampleAlgoImplementation
    {

    	static CSSSystem system = CSSSystem.getInstance();
    	static CSSAPIIF css = system.getCSSAPI();
    	// this variable specifies a HTTP Request
    	static HashTableEg hTTPRequest = new HashTableEg();

    	/**
    	 *  Instantiate the class that implements CSSApplicationIF
    	 */
    	static MyApp myApp = new MyApp();

    	/**
    	 * Main part of the program.
    	 * This method demonstrates the algorithm detailed above
    	 * and displays the user information for an authenticated user.
    	 */
    	public static void main(String[] args)
    	{

    		try
    		{
    			/**
    			 * Create a context and populate it with
    			 * the userName and userPassword
    			 */
    			Map context = new HashMap();
    			context.put(CSSAPIIF.LOCALE, new Locale("en", "US"));
    			context.put(CSSAPIIF.LOG_PREPEND_TEXT, "[APP_NAME/1.0.0]");
    			myApp.path = "C:/temp/sample.xml";

    			/**
    			 * Initialize the security platform.
    			 */
    			css.initialize(context, myApp);
    			String loginNameFromHeader = null;

    			if (css.isSecurityAgentProtected(context))
    			{
    				/**
    				 * protected by the security agent
    				 */
    				myApp.log("Protected by the security agent");
    				// get the headers
    				String[] headersFromSecAgent = css.getHeaderNamesFromSecurityAgent(context);
    				/**
    				 *  A better approach would be to save the HTTP header that returns the login name
    				 * into session.
    				 */
    				Enumeration headersFromRequest = getFromHTTPHeaders(headersFromSecAgent);
    				while (headersFromRequest.hasMoreElements())
    				{
    					String headerName = (String) headersFromRequest.nextElement();
    					for (int i = 0; i < headersFromSecAgent.length; i++)
    					{
    						if (headersFromSecAgent[i].equalsIgnoreCase(headerName))
    							loginNameFromHeader = hTTPRequest.getHeader(headerName);

    						myApp.log("HEADER[" + i + "]: " + headersFromSecAgent[i]);
    						if (loginNameFromHeader != null)
    						{
    							context.put(CSSAPIIF.SECURITY_AGENT_LOGIN_NAME, loginNameFromHeader);
    							myApp.log("The login name from header: " + loginNameFromHeader);
    							break;
    						}
    					}
    					if (loginNameFromHeader != null)
    						break;
    				}
    			} // end if
    			if (loginNameFromHeader == null)
    			{
    				/**
    				 *  check to see if token is passed in
    				 */
    				String token = hTTPRequest.getParameter("sso_token");
    				myApp.log("The token passed in: " + token);
    				if (token == null)
    				{
    					/**
    					 * pop up dialog for username and password
    					 */
    					context.put(CSSAPIIF.LOGIN_NAME, "gkhanna");
    					context.put(CSSAPIIF.PASSWORD, "password");
    				}
    				else
    				{
    					/**
    					 * 	authenticate the user using a token
    					 */
    					myApp.log("USING TOKEN: ");
    					context.put(CSSAPIIF.TOKEN, "DUMMY_TOKEN");
    				}

    			}

    			/**
    			 * we are here => the loginNameFromHeader != null
    			 */
    			myApp.log("Security Agent login");
    			context.put(CSSAPIIF.SECURITY_AGENT_LOGIN_NAME, loginNameFromHeader);

    			CSSUserIF user = css.authenticate(context);
    			displayUser(user);
    		}

    		catch (Exception e)
    		{
    			myApp.log(" Exception in CSSHelloSSOWithSA ");
    			myApp.log(e.toString());
    			e.printStackTrace();
    		}
    	}

    	/**
    	 * This method is used to demonstrate  a call to get all the header names
    	 * from an HTTP Request.
    	 *
    	 * @param headersFromSecAgent
    	 * @return Enumeration
    	 */
    	private static Enumeration getFromHTTPHeaders(String[] headersFromSecAgent)
    	{
    		hTTPRequest.put("HTTP_ACCEPT_ENCODING", "gzip, deflate");
    		hTTPRequest.put("HTTP_ACCEPT_LANGUAGE", "en-us");
    		hTTPRequest.put("HTTP_CONNECTION", "Keep-Alive");
    		hTTPRequest.put("HTTP_COOKIE", "SMCHALLENGE=YES");
    		hTTPRequest.put("HTTP_HOST", "serverw2k-2");
    		hTTPRequest.put("HTTP_HYPLOGIN", "Jeff");
    		hTTPRequest.put("HTTP_SM_AUTHDIRNAME", "CSSLDAPDirectory");
    		hTTPRequest.put("HTTP_SM_AUTHDIRNAMESPACE", "LDAP:");
    		hTTPRequest.put("HTTP_SM_AUTHDIROID", "0e-3913bbfb-5191-49fb-b6fd-a0227c2e4ee5");
    		hTTPRequest.put("HTTP_SM_AUTHDIRSERVER", "serverw2k-1:3131");
    		hTTPRequest.put("HTTP_SM_AUTHENTIC", "YES");
    		hTTPRequest.put("HTTP_SM_AUTHORIZED", "YES");
    		hTTPRequest.put("HTTP_SM_AUTHREASON", "0");
    		hTTPRequest.put("HTTP_SM_AUTHTYPE", "Basic");
    		hTTPRequest.put("HTTP_SM_REALM", "CSSIISRealm");
    		hTTPRequest.put("HTTP_SM_REALMOID", "06-09beabac-b02c-4e6f-9106-9be158cb7cb3");
    		hTTPRequest.put("HTTP_SM_SERVERSESSIONID", "WM9VEGzmIlCob3F/i4/SMn68Ryg=");
    		hTTPRequest.put(
    			"HTTP_SM_SERVERSESSIONSPEC",
    			"vaQszymZ/LvzyRIx9BxZpqDpjdGDVOR6TVy4DsAauAH87GGdzcVBtNuEnvlJI58r0KsbgmFlGk9qkJYsbvt+OLOV1s5A2xNh5CXRiEIHQWxO3zm2e3hx/gCw+Y3VT6jmd28Frnlz7ZU1Xt2Z7M2aqo9+a1gNtLArh1kXwNOpWSvcTpUqkfoN1yi+IA5N5nVgWHkya/Z/IBMw804NHLy/erGdlLtFll8mK+AT06sc9yHjdQzZH4mcZRI4KbwdzACeeL8Wyhm8ff1hkZ4K7o/qdi0aybXtyC+M+HXfavYSnQ5buFSkEhiK/RlWSTlwKfqvBDaG8Hn8k4uOQNI9P7p4yTd5TXLAOnCQHVFup+rKywvkJkoWChxaUKpNSlYsbTvp/sqX8/uJfkQ=");
    		hTTPRequest.put("HTTP_SM_SESSIONDRIFT", "0");
    		hTTPRequest.put("HTTP_SM_TIMETOEXPIRE", "7200");
    		hTTPRequest.put("HTTP_SM_TRANSACTIONID", "7b191bac-1164-3fb403ee-1134-003e6784");
    		hTTPRequest.put("HTTP_SM_USER", "Jeff");
    		hTTPRequest.put("HTTP_SM_USERDN", "cn=Jeff,ou=people,dc=serverw2k-1,dc=company,dc=com");
    		hTTPRequest.put("HTTP_USER_AGENT", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)");

    		return hTTPRequest.keys();
    	}

    	/**
    	 *
    	 * This is just a demonstration class therefore there has been no error checking.
    	 *
    	 * @since CSSv2.5
    	 * @author gkhanna
    	 */
    	static class HashTableEg extends Hashtable
    	{
    		String getHeader(String headerName)
    		{
    			return (String) get(headerName);
    		}

    		String getParameter(String parameterName)
    		{
    			return null;
    		}
    	}

    	private static void displayUser(CSSUserIF user) throws CSSException
    	{
    		if (user == null)
    		{
    			myApp.log("USER IS NULL");
    			return;
    		}
    		StringBuffer buffer = new StringBuffer("**********USER IS: ");
    		buffer.append("\n");
    		buffer.append("First Name: " + user.getFirstName());
    		buffer.append("\n");
    		buffer.append("Last Name: " + user.getLastName());
    		buffer.append("\n");
    		buffer.append("Email : ");
    		String[] emails = user.getEmailAddress();
    		if (emails != null)
    		{
    			for (int i = 0; i < emails.length; i++)
    			{
    				buffer.append(emails[i]);
    				buffer.append("\t");
    			}
    		}
    		buffer.append("\n");
    		buffer.append("Identity: " + user.getIdentity());
    		buffer.append("\n");
    		buffer.append("Token: " + user.getToken());
    		buffer.append("\n");
    		buffer.append("Groups List: ");
    		String[] groups = user.getGroupsList();
    		if (groups != null)
    			for (int i = 0; i < groups.length; i++)
    			{
    				buffer.append(groups[i]);
    				buffer.append("\t");
    			}
    		Map otherProps = user.getUserInfo();
    		buffer.append("\nlogin name: " + otherProps.get(CSSAPIIF.LOGIN_NAME));

    		myApp.log(buffer.toString());
    	}
    }

Top

## Common Application-Implementation Examples

For clarity, exception handling code is not shown in the following examples. Line numbers are shown, and `...` represents lines skipped in the examples.

How do I initialize the security platform API?
How do I authenticate a user?
How do I extract the token?
How do I recieve a token?
How do I pass a token to another application? (Single sign-on)
How should I use "Get" functions?

### How do I initialize the security platform API?

1. Write a class that implements the application interface, com.hyperion.css.application.CSSApplicationIF. Refer to the javadocs for details on the application contract specified by CSSApplicationIF. In the following code snippet, `MyApp` is such a class (code for `MyApp.java` is available in sampleApplications).
2. Get a CSSSytem object by using the CSSSystem.getInstance() method [`Line 011`].
3. Use the CSSSystem object obtained in step 2 to get a CSSAPIIF object by using the getCSSAPI() method [`Line 012`].
4. Create an instance of the MyApp class (the class that implemented CSSApplicationIF in step 1) [`Line 020`].
5. Call the initialize method on the CSSAPIIF object obtained in step 3, passing it the instance of the MyApp class obtained in step 4 [`Line 027`].

The security platform is now initialized.

    		...
    	005	import com.hyperion.css.CSSSystem;
    	006	import com.hyperion.css.CSSAPIIF;
    		....
    	011	static CSSSystem system = CSSSystem.getInstance();
    	012	static CSSAPIIF css = system.getCSSAPI();
    		...
    		...
    	020	MyApp myApp = new MyApp();
    		...
    		...
    	027	css.initialize(myApp);
    		....

Up

### How do I authenticate a user?

Part I. Authenticating with user name and password

1. Make sure the security platform is initialized.
2. Create a new HashMap and populate it with user name and password [`Lines 110` through `112`].
3. Call the authenticate method [`Line 113`].

    	002	import java.util.Map;
    	003	import java.util.HashMap;
    	006	import com.hyperion.css.CSSAPIIF;
    	007	import com.hyperion.css.common.CSSUserIF;
    		...
    	108	String userName = "Jeff";
    	109	String userPassword = "Jeff";
    	110	Map context = new HashMap();
    	111	context.put(CSSAPIIF.LOGIN_NAME,userName);
    	112	context.put(CSSAPIIF.PASSWORD,userPassword);
    	113	CSSUserIF user = css.authenticate(context);
    		...

Part II. Authenticating with a token (single sign-on)

1. Make sure the security platform is initialized.
2. Receive the token. [`Line 207`]. See also How do I recieve a token?
3. Create a new HashMap and populate it with the token [`Lines 210 -211`].
4. Call the authenticate method [`Line 212`].

    	002	import java.util.Map;
    	003	import java.util.HashMap;
    	006	import com.hyperion.css.CSSAPIIF;
    	007	import com.hyperion.css.common.CSSUserIF;
    		...
    	207	String cssToken = myCustomMethodToReceiveTheToken();
    		...
    	210	Map context = new HashMap();
    	211	context.put(CSSAPIIF.TOKEN,cssToken);
    	212	CSSUserIF user = css.authenticate(context);
    		...

Up

### How do I extract the token?

1. Authenticate the user.
2. Call the getToken() method on a CSSUserIF object returned by the authenticate method [`Line 235`].

    		...
    	235	String cssToken = user.getToken();
    		...

Up

### How do I recieve a token?

In the following sample JSP code, the Web application expects the calling applications to send a cssToken in the `"token"` parameter. After the token is obtained, the user can be authenticated as described in the example for authenticating a user with a token.

    		...
    	250	<%
    		...
    	254	String token = request.getParameter("sso_token");
    	255	%>
    		...
    	260	<%
    		...now that we have the token, authenticate using the token ..
    	265	%>

Up

### How do I pass a token to another application?

In the following sample JSP code, `secondApplication` is a Web application hosted on `server` and using a SignIn JSP page that accepts tokens. The following code shows one method to send a token from your application to the SignIn page of `secondApplication`.

        300	<%
    		...authenticate the user ...
    		...user is a CSSUserIF object that's returned by the authenticate method...
        308	String token = user.getToken();
        309	%>
    		...
        320	<form name="sendToken" action="http://server/secondApplication/jsp/SignIn.jsp" method=post>
        321	<input type="hidden" name="sso_token" value="<%=token%>">
    		... any other information that you might want to exchange with "secondApplication" ...
        325	</form>
    		...

The security platform does not place any restrictions on how you pass and receive tokens.

Up

### How should I use "Get" functions?

The following discussion is a high-level example of using various "Get" functions in an application implementation called WIDGET.

In WIDGET, all application users are given access (and security rights) either by being specified directly or by virtue of a group membership.

To give access to an externally authenticated user named Tom, the following actions take place for WIDGET:

1. The WIDGET Administrator adds `Tom` to an application.
2. WIDGET calls CSSAPI.getUsers() for `Tom`.
3. WIDGET uses the returned CSSUserIF to call getIdentity().
4. The Identity is stored in the WIDGET database.
5. User logs on to WIDGET as `Tom` with password `xxxxxx`.
6. WIDGET calls CSSAPI.authenticate() with `Tom`'s credentials.
7. If `Tom` is successfully authenticated, WIDGET queries the security platform for Tom's identity.
8. WIDGET finds Tom's identity in the database and allows access.

Additionally, the WIDGET administrator may want to give everyone in the `MyGroup` group access but not want to add every member (or manage changes to the group). In that case the administrator might simply add the `MyGroup` group to the list of application users. This scenario might work as follows:

1. The WIDGET Administrator adds `MyGroup` to an application.
2. WIDGET calls CSSAPI.getGroups() for `MyGroup`.
3. WIDGET uses the returned CSSGroupIF to call getIdentity().
4. The Identity is stored in the WIDGET database.
5. User logs on to WIDGET as `Jane` with password `xxxxxx`.
6. WIDGET calls CSSAPI.authenticate() with Jane's credentials.
7. If `Jane` is successfully authenticated, WIDGET queries the security platform for Jane's identity.
8. WIDGET does not find Jane's identity.
9. WIDGET calls CSSUserIF.getGroupsList() for `Jane`.
10. WIDGET checks if any of Jane's group identities are in the database (and MyGroup's identity is).
11. `Jane` is given access.

After a user has access, WIDGET keeps a record of the user's identity and the identities of all of the user's groups. For every task that the user subsequently tries to perform, WIDGET checks the database to see if the user's identity (or any of the group identities) has rights to perform that task. After a user is logged on to WIDGET, the user is known by his or her identity. One use of the CSSAPI.getUserByIdentity() function might be for WIDGET to log an action that a user is performing.

For example:

1. User starts a consolidation.
2. WIDGET calls CSSAPI.getUserByIdentity() with the user's identity.
3. WIDGET writes the following message:
   `CSSUserIF.getName() + " started consolidation at 18:37 EST "`

Top

## Guidelines for Writing a Custom Provider

The security platform provides the ability to plug in providers for various repositories of user and group information.

The following authentication repositories are supported as built-in providers to the security platform:

- Windows NT LAN Manager (NTLM): 4.0 or higher
- LDAP-compatible directories: iPlanet 4.15 or higher (now known as Sun TM Open Net Environment [Sun ONE]) or Novell eDirectory 8.7 or higher
- Microsoft Active Directory server: Windows 2000 Server and Advanced Server

In the case that the above built-in providers do not serve the needs for your environment, or new providers need to be implemented, you can build a custom provider. This document specifies the steps required to create a provider and plug it into the security platform framework.

The following steps need to be taken in order to write a custom provider:

1. Implement the Provider Factory Interface
2. Implement the Provider Interface
3. Update the Configuration
4. Test the Provider

### Implement the Provider Factory Interface

com.hyperion.css.spi.CSSProviderFactoryIF is a factory interface whose implementation creates and initializes the provider. The security platform uses this instance as the reference instance for providers.

The "map" argument contains all the configuration parameters that are specified in the configuration for this provider. The configuration parameters specified in the configuration XML file are passed on as key-value pairs in this map. For information about the configuration XML file, see Update the Configuration.

### Implement the Provider Interface

This interface needs to be implemented by the provider. The JavaDocs for this interface specify the contract that needs to be followed.

Please note that your implementation of the Provider can be accessed concurrently from multiple threads. Therefore it needs to be thread safe.

Use the CSSIdentityHelper

The identity string is a combination of attributes that can uniquely identity a user or group entity across multiple directories/repositories. The identity string is the only object that is stored in the internal repositories of Hyperion applications involved in single sign-on.

The format of an identity string is as follows:

`Provider.TYPE://Provider.ID?Entry.Type`

where:

`Provider.TYPE` | The type of the provider. Possible values: `ntlm`, `msad`, `ldap`, or `custom`.
`Provider.ID` | The unique identifier for the user or group. The `Provider.ID` also contains the name of the attribute that uniquely specifies the user or group; for example, `DN` or `SID`.
`Entry.Type` | Possible values: `USER`, `GROUP`, or `OTHER`.

The following are examples of correctly formatted identity strings:

    ldap:// DN=cn=gkhanna,ou=people, o=Hyperion?USER
    NTLM:// SID=761236312623762376AS1238712?USER

The CSSIdentityHelper class is responsible for constructing the identity that uniquely identifies a user and group to the security platform.

The CSSIdentity.getIdentity() method returns an identity string in the correct format based on the parameters that are passed to it.

### Update the Configuration

Assume that the provider has been written according to the contract, and it now needs to be plugged into the security platform framework. To achieve this, you must update the configuration XML file with the following entries:

Provider Configuration Section of XML File:

    <custom name="ProviderName">
    	<factory>FactoryClass</factory>
    	        <url>SomeURL</url>
    	<trusted>false</trusted>
    	<property>
    		<key>SomeKey</key>
    		<value>SomeValue</value>
    	</property>
    </custom>

where:

Name | The name of the provider ("ProviderName").
Factory | The class implementing the factory interface.
Url | Between the `<url></url>` tags, replace `ldap://host:portNo/DIT` with the URL that specifies the location of the provider. The following is an example of a LDAP URL that includes a directory information tree (DIT): `ldap://ldap_server:389/DC=company,DC=com` Note: Be sure to include no extra spaces in the URL. It is mandatory to have a value in this element.
Trusted | Between the `<trusted></trusted>` tags, leave the default value of `true`, or, if the specified provider is not a trusted provider, replace the value with `false`. If the entire `<trusted></trusted>` section including the tags is deleted, the default value of `true` is used. Do not delete only the values of the tags. If the trust setting is `true`, a password is not present or required in the token generated upon user authentication. If the trust setting is false, a password is part of the token.
Property | The `<property></property>` element should contain key-value pairs where the "key" specifies the name of the property and the "value" element contains the value for that property.

Search Order Section of XML File:

    <searchOrder>
    	<el>ntlmServer</el>
    	<el>ldapServer</el>
    	<el>msadServer</el>
    	<el>providerName</el>
    </searchOrder>

Move the <el> sections around as needed to place the provider types in the order that they should be searched whenever a user tries to log on to a Hyperion application.

It would make sense to place the provider containing the most users of Hyperion applications first in the search order, if that information is known. For example, in the above section, the NTLM provider would be searched first for user information.

### Test the Provider

Once the provider has been written and plugged in, it needs to be tested to ensure that the contract outlined in the CSSProviderIF Javadocs is being followed.

Suggested testing strategies:

1. Make sure that the provider fails over to the next one in the search order if it cannot connect to its repository.
2. Make sure that the provider throws the right kind of exceptions - this is how the security framework collects information to return to the client.
3. Make sure that the correct values are being returned in the right format.

Top

©2004 Hyperion Solutions Corporation. All Rights Reserved. http://www.hyperion.com