Hyperion Security Integration SDK Reference |
This file contains the following sections:
Overview of Security Platform API Components
Common Application-Implementation Examples
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:
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:
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.
The following functionality is new to this release of the Hyperion security platform.
Note: Essbase is not a Web-based application, so single sign-on is not applicable for Essbase.
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:
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.
To set up your system for implementing the security platform,
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. |
%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.jarClasspath settings are IDE dependent, so if you need instructions for setting the classpath, see the documentation for your Java development environment.
CSSMessages.properties
file located in the security platform jar file.MyApp.java
, to point to the location of your configuration file.
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:
sax.jar
, dom.jar
, and xercesImpl.jar
to the classpath as indicated in the JAXP section below. 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:
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.JDOM.jar
needs to be included in the classpath for your project.log4j-1.2.7.jar
needs to be included in the classpath for your project.%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
..zip
file with Analytic Services..jar
files to the classpath for your project: jcert.jar
, jnetr.jar
, and jsse.jar
.java -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol
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.
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.
The security platform is a multi-layered system.
The following are the components of 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:
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);
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.
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.
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.
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) { } }
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()); } } }
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() ); } }
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(); } } }
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(); } } }
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()); } }
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?
MyApp
is such a class (code for MyApp.java
is available in sampleApplications).Line 011
].Line 012
].Line 020
].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); ....
Part I. Authenticating with user name and password
Lines 110
through 112
].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)
Line 207
]. See also How do I recieve a token?Lines 210 -211
].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); ...
Line 235
].... 235 String cssToken = user.getToken(); ...
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 %>
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.
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:
Tom
to an application.Tom
.Tom
with password xxxxxx
.Tom
's credentials.Tom
is successfully authenticated, WIDGET queries the security platform for Tom's identity.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:
MyGroup
to an application.MyGroup
.Jane
with password xxxxxx
.Jane
is successfully authenticated, WIDGET queries the security platform for Jane's identity.Jane
.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:
CSSUserIF.getName() + " started consolidation at 18:37 EST "
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:
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:
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.
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.
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 |
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.
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:
![]() |
©2004 Hyperion Solutions Corporation. All Rights Reserved. http://www.hyperion.com |