Developing custom user registries

This development provides considerable flexibility in adapting WebSphere Application Server security to various environments where some notion of a user registry, other than LDAP or Local OS, already exists in the operational environment.

Before you begin

WebSphere Application Server security supports the use of custom user registries in addition to Local OS and Lightweight Directory Access Protocol (LDAP) registries for authentication and authorization purposes. A custom implemented user registry uses the UserRegistry Java interface as provided by WebSphere Application Server. A custom-implemented user registry can support virtually any type or notion of an accounts repository from a relational database, flat file, and so on.

Implementing a custom user registry is a software development effort. Use the methods that are defined in the UserRegistry interface to make calls to the appropriate user registry to obtain user and group information. The interface defines a general set of methods for encapsulating a wide variety of registries. You can configure a custom user registry as the active user registry when configuring WebSphere Application Server global security.

Make sure that your implementation of the custom user registry does not depend on any WebSphere Application Server components such as data sources, Enterprise JavaBeans (EJB) and Java Naming and Directory Interface (JNDI). Do not have this dependency because security is initialized and enabled prior to most of the other WebSphere Application Server components during startup. If your previous implementation used these components, make a change that eliminates the dependency. For example, if your previous implementation used data sources to connect to a database, use DriverManager to connect to the database.

[z/OS] Note: The user registry is used in controllers and servants. There is an increased risk of integrity exposure in that configuration if the registry implementation is not secured.

Refer to the Migrating custom user registries for more information on migrating. If your previous implementation uses data sources to connect to a database, change the implementation to use Java database connectivity (JDBC) connections. However, it is recommended that you use the new interface to implement your custom registry.

Procedure

  1. Implement all the methods in the interface except for the CreateCredential method, which is implemented by WebSphere Application Server. FileRegistrySample.java file is provided for reference.
    Attention: The sample provided is intended to familiarize you with this feature. Do not use this sample in an actual production environment.
  2. Build your implementation.
    [AIX HP-UX Linux Solaris Windows] [z/OS] To compile your code, you need the %install_root%/lib/sas.jar and the %install_root%/lib/wssec.jar files in your class path. For example: [Windows]
    %install_root%/java/bin/javac -classpath 
    %install_root%/lib/wssec.jar;
    %install_root%/lib/sas.jar
    your_implementation_file.java
    [AIX] [HP-UX] [Linux] [Solaris] [z/OS]
    %install_root%\java\bin\javac -classpath 
    %install_root%\lib\wssec.jar:
    %install_root%\lib\sas.jar
    your_implementation_file.java
  3. Copy the class files that are generated in the previous step to the product class path.
    [AIX HP-UX Linux Solaris Windows] [z/OS] The preferred location is the following directory:
    • [Windows] %install_root%/lib/ext
    • [AIX] [HP-UX] [Linux] [Solaris] [z/OS] %install_root%\lib\ext
    Copy these class files to all of the product process class paths.
  4. Follow the steps in Configuring custom user registries to configure your implementation using the administrative console. This step is required to implement custom user registries.

Example

A custom user registry is a customer-implemented user registry that implements the UserRegistry Java interface, as provided by WebSphere Application Server. A custom-implemented user registry can support virtually any type or form of an accounts repository from a relational database, flat file, and so on. The custom user registry provides considerable flexibility in adapting WebSphere Application Server security to various environments where some form of a user registry, other than Lightweight Directory Access Protocol (LDAP) or Local OS, already exist in the operational environment.

If you are using the WebSphere Application Server Version 4.x com.ibm.websphere.security.CustomRegistry interface, you must migrate to the com.ibm.websphere.security.UserRegistry interface. The com.ibm.websphere.security.CustomRegistry interface has been removed after it was deprecated in WebSphere Application Server Version 5.x.

To view a sample custom registry, refer to the following files:
Result.java file

This module is used by user registries in WebSphere Application Server when calling the getUsers and getGroups methods. The user registries use this method to set the list of users and groups and to indicate if more users and groups in the user registry exist than requested.

//
//  5639-D57, 5630-A36, 5630-A37, 5724-D18 
// (C) COPYRIGHT International Business Machines Corp. 1997, 2005
//  All Rights Reserved * Licensed Materials - Property of IBM
//
package com.ibm.websphere.security;

import java.util.List;

public class Result implements java.io.Serializable {
    /**
      Default constructor
    */
    public Result() {
    }

    /**
       Returns the list of users and groups
       @return the list of users and groups
    */
    public List getList() {
      return list;
    }

    /**
       indicates if there are more users and groups in the registry
    */
    public boolean hasMore() {
      return more;
    }
    /**
       Set the flag to indicate that there are more users and groups 
       in the registry to true
    */
    public void setHasMore() {
      more = true;
    }

    /*
      Set the list of users and groups
      @param list   list of users/groups
    */
    public void setList(List list) {
      this.list = list;
    }

    private boolean more = false;
    private List list;
}
UserRegistry.java files

The following file is a custom property that is used with a custom user registry.

For more information, see Configuring custom user registries.

// 5639-D57, 5630-A36, 5630-A37, 5724-D18 
// (C) COPYRIGHT International Business Machines Corp. 1997, 2005
// All Rights Reserved * Licensed Materials - Property of IBM
//
// DESCRIPTION:
//
//    This file is the UserRegistry interface that custom registries in WebSphere 
//    Application Server implement to enable WebSphere security to use the custom 
//    registry.
//

package com.ibm.websphere.security;

import java.util.*;
import java.rmi.*;
import java.security.cert.X509Certificate;
import com.ibm.websphere.security.cred.WSCredential;

/**
 * Implementing this interface enables WebSphere Application Server Security 
 * to use custom registries. This interface extends java.rmi.Remote because the  
 * registry can be in a remote process.
 *
 * Implementation of this interface must provide implementations for:
*
* initialize(java.util.Properties)
* checkPassword(String,String)
* mapCertificate(X509Certificate[])
* getRealm
* getUsers(String,int)
* getUserDisplayName(String)
* getUniqueUserId(String)
* getUserSecurityName(String)
* isValidUser(String)
* getGroups(String,int)
* getGroupDisplayName(String)
* getUniqueGroupId(String)
* getUniqueGroupIds(String)
* getGroupSecurityName(String)
* isValidGroup(String)
* getGroupsForUser(String)
* getUsersForGroup(String,int)
* createCredential(String)
**/

public interface UserRegistry extends java.rmi.Remote
{

  /**
   * Initializes the registry. This method is called when creating the
   * registry.
   *
   * @param	props	the registry-specific properties with which to 
   *              	initialize the  custom registry 
   * @exception	CustomRegistryException 
   *                    if there is any registry specific problem
   * @exception RemoteException 
   * 			as this extends java.rmi.Remote
   **/
   public void initialize(java.util.Properties props)
      throws CustomRegistryException,
             RemoteException;
  /**
   * Checks the password of the user. This method is called to authenticate a
   * user when the user's name and password are given.
   *
   * @param userSecurityName the name of the user 
   * @param password the password of the user
   * @return a valid userSecurityName. Normally this is 
   *   the name of same user whose password was checked but if the 
   *  implementation wants to return any other valid 
   *  userSecurityName in the registry it can do so
   * @exception CheckPasswordFailedException if userSecurityName/
   *  password combination does not exist in the registry
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String checkPassword(String userSecurityName, String password)
      throws PasswordCheckFailedException,
             CustomRegistryException,
             RemoteException;

  /**
   * Maps a certificate (of X509 format) to a valid user in the registry.
   * This is used to map the name in the certificate supplied by a browser 
   * to a valid userSecurityName in the registry
   *
   * @param cert the X509 certificate chain
   * @return the mapped name of the user userSecurityName
   * @exception CertificateMapNotSupportedException if the particular
   *            certificate is not supported.
   * @exception CertificateMapFailedException if the mapping of the 
   *            certificate fails.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String mapCertificate(X509Certificate[] cert)
      throws CertificateMapNotSupportedException,
             CertificateMapFailedException,
             CustomRegistryException,
             RemoteException;

  /**
   * Returns the realm of the registry.
   *
   * @return the realm. The realm is a registry-specific string indicating 
   *            the realm or domain for which this registry 
   *            applies.  For example, for OS400 or AIX this would be the 
   *            host name of the system whose user registry this object 
   *            represents.
   *            If null is returned by this method realm defaults to the 
   *            value of "customRealm". It is recommended that you use
   *            your own value for realm.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getRealm()
      throws CustomRegistryException,
             RemoteException;

  /**
   * Gets a list of users that match a pattern in the registry. 
   * The maximum number of users returned is defined by the limit
   * argument.
   * This method is called by administrative console and by scripting (command  
   * line) to make available the users in the registry for adding them (users)
   * to roles.
   *
   * @parameter pattern the pattern to match. (For example., a* will match all
   *   userSecurityNames starting with a)
   * @parameter limit the maximum number of users that should be returned.
   *  This is very useful in situations where there are thousands of
   *            users in the registry and getting all of them at once is not
   *            practical. A value of 0 implies get all the users and hence
   *            must be used with care. 
   * @return a Result object that contains the list of users
   *   requested and a flag to indicate if more users exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public Result getUsers(String pattern, int limit)
      throws CustomRegistryException,
             RemoteException;

  /**
   * Returns the display name for the user specified by userSecurityName.
   *
   * This method is called only when the user information displays  
   * (information purposes only, for example, in the administrative console) and not used 
   * in the actual authentication or authorization purposes. If there are no 
   * display names in the registry return null or empty string.
   *
   * In WebSphere Application Server Version 4.0 custom registry, if you had a display 
   * name for the user and  if it was different from the security name, the display name 
   * was returned for the EJB methods getCallerPrincipal() and the servlet methods 
   * getUserPrincipal() and  getRemoteUser().
   * In WebSphere Application Server Version 5.0 for the same methods the security  
   * name is returned by default. This is the recommended way as the display name 
   * is not unique and might create security holes.
   *
   * See the documentation for more information. 
   *
   * @parameter userSecurityName the name of the user.
   * @return the display name for the user. The display name
   *   is a registry-specific string that represents a descriptive, not
   *  necessarily unique, name for a user. If a display name does 
   *            not exist return null or empty string.
   * @exception EntryNotFoundException if userSecurityName does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getUserDisplayName(String userSecurityName)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Returns the unique ID for a userSecurityName. This method is called when
   * creating a credential for a user. 
   *
   * @parameter userSecurityName the name of the user.
   * @return the unique ID of the user. The unique ID for a user is
   *   the stringified form of some unique, registry-specific, data 
   *  that serves to represent the user.  For example, for the UNIX 
   *  user registry, the unique ID for a user can be the UID.
   * @exception EntryNotFoundException if userSecurityName does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getUniqueUserId(String userSecurityName)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Returns the name for a user given its unique ID.
   *
   * @parameter uniqueUserId the unique ID of the user.
   * @return the userSecurityName of the user.
   * @exception EntryNotFoundException if the uniqueUserID does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getUserSecurityName(String uniqueUserId)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Determines if the userSecurityName exists in the registry
   *
   * @parameter userSecurityName the name of the user
   * @return true if the user is valid. false otherwise
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public boolean isValidUser(String userSecurityName)
      throws CustomRegistryException,
             RemoteException;

  /**
   * Gets a list of groups that match a pattern in the registry. 
   * The maximum number of groups returned is defined by the limit
   * argument.
   * This method is called by the administrative console and scripting  
   * (command line) to make available the groups in the registry for adding  
   * them (groups) to roles.
   *
   * @parameter pattern the pattern to match. (For e.g., a* will match all
   *   groupSecurityNames starting with a)
   * @parameter limit the maximum number of groups to return.
   *  This is very useful in situations where there are thousands of
   *            groups in the registry and getting all of them at once is not
   *            practical. A value of 0 implies get all the groups and hence
   *            must be used with care. 
   * @return a Result object that contains the list of groups
   *   requested and a flag to indicate if more groups exist.
   * @exception CustomRegistryException if there is any registry-specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public Result getGroups(String pattern, int limit)
      throws CustomRegistryException,
             RemoteException;

  /**
   * Returns the display name for the group specified by groupSecurityName.
   *
   * This method may be called only when the group information displayed  
   * (for example, the administrative console) and not used in the actual 
   * authentication or authorization purposes. If there are no display names 
   * in the registry return null or empty string.
   *
   * @parameter groupSecurityName the name of the group.
   * @return the display name for the group. The display name
   *   is a registry-specific string that represents a descriptive, not
   *  necessarily unique, name for a group. If a display name does 
   *            not exist return null or empty string.
   * @exception EntryNotFoundException if groupSecurityName does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getGroupDisplayName(String groupSecurityName)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Returns the unique ID for a group.

   * @parameter groupSecurityName the name of the group.
   * @return the unique ID of the group. The unique ID for
   *  a group is the stringified form of some unique, 
   *  registry-specific, data that serves to represent the group.
   *  For example, for the UNIX user registry, the unique ID might 
   *  be the GID.
   * @exception EntryNotFoundException if groupSecurityName does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getUniqueGroupId(String groupSecurityName)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;


  /**
   * Returns the unique IDs for all the groups that contain the unique ID of
   * a user. 
   * Called during creation of a user's credential.
   *
   * @parameter uniqueUserId the unique ID of the user.
   * @return a list of all the group unique IDs that the unique user ID 
   *   belongs to. The unique ID for an entry is the stringified 
   *  form of some unique, registry-specific, data that serves 
   *  to represent the entry.  For example, for the
   *   UNIX user registry, the unique ID for a group could be the GID 
   *  and the unique ID for the user could be the UID.
   * @exception EntryNotFoundException if unique user ID does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public List getUniqueGroupIds(String uniqueUserId)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Returns the name for a group given its unique ID.
   *
   * @parameter uniqueGroupId the unique ID of the group.
   * @return the name of the group.
   * @exception EntryNotFoundException if the uniqueGroupId does not exist.
   * @exception CustomRegistryException if there is any registry-specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public String getGroupSecurityName(String uniqueGroupId)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Determines if the groupSecurityName exists in the registry
   *
   * @parameter groupSecurityName the name of the group
   * @return true if the groups exists, false otherwise
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public boolean isValidGroup(String groupSecurityName)
      throws CustomRegistryException,
             RemoteException;

  /**
   * Returns the securityNames of all the groups that contain the user
   *
   * This method is called by administrative console and scripting 
   * (command line) to verify the user entered for RunAsRole mapping belongs
   * to that role  in the roles to user mapping. Initially, the check is done 
   * to see if the role contains the user. If the role does not contain the user 
   * explicitly, this method is called to get the groups that this user
   * belongs to so that checks are made on the groups that the role contains.
   *
   * @parameter userSecurityName the name of the user
   * @return a List of all the group securityNames that the user 
   *   belongs to. 
   * @exception EntryNotFoundException if user does not exist.
   * @exception CustomRegistryException if there is any registry specific 
   *            problem
   * @exception RemoteException as this extends java.rmi.Remote
   **/
   public List getGroupsForUser(String userSecurityName)
      throws EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * Gets a list of users in a group.
   *
   * The maximum number of users returned is defined by the limit
   * argument.
   *
   * This method is used by the WebSphere Business Integration
   * Server Foundation process choreographer when staff assignments 
   * are modeled using groups.
   *
   
   * In rare situations where you are working with a user registry and it is not 
   * practical to get all of the users from any of your groups (for example if 
   * a large number of users exist) you can create the NotImplementedException
   * for those particular groups. Make sure that if the WebSphere Business 
   * Integration Server Foundation Process Choreographer is installed (or 
   * if installed later) that the users are not modeled using these particular groups. 
   * If no concern exists about the staff assignments returning the users from 
   * groups in the registry it is recommended that this method be implemented 
   * without throwing the NotImplemented exception.
   *
   * @parameter groupSecurityName that represents the name of the group
   * @parameter limit the maximum number of users to return.
   *            This option is very useful in situations where lots of
   *            users are in the registry and getting all of them at 
   *            once is not practical. A value of 0 means  get all of 
   *            the users and must be used with care.
   * @return    a Result object that contains the list of users
   *            requested and a flag to indicate if more users exist.
   * @deprecated This method will be deprecated in the future.
   * @exception NotImplementedException create this exception in rare situations
   *            if it is not practical to get this information for any of the
   *            groups from the registry.
   * @exception EntryNotFoundException if the group does not exist in
   *            the registry
   * @exception CustomRegistryException if any registry-specific
   *            problem occurs
   * @exception RemoteException as this extends java.rmi.Remote interface
   **/
   public Result getUsersForGroup(String groupSecurityName, int limit)
      throws NotImplementedException,
             EntryNotFoundException,
             CustomRegistryException,
             RemoteException;

  /**
   * This method is implemented internally by the WebSphere Application Server  
   * code in this release. This method is not called for the custom registry 
   * implementations for this release. Return null in the implementation.
   *
   * Note that because this method is not called you can also return the 
   * NotImplementedException as the previous documentation says.
   *
   **/
   public com.ibm.websphere.security.cred.WSCredential 
                                createCredential(String userSecurityName)
      throws NotImplementedException,
	     EntryNotFoundException,
             CustomRegistryException,
             RemoteException;
}

What to do next

If you enable security, make sure that you complete the remaining steps:
  1. Save and synchronize the configuration and restart all of the servers.
  2. Try accessing some J2EE resources to verify that the custom registry implementation is correct.



In this information ...


IBM Redbooks, demos, education, and more

(Index)

Use IBM Suggests to retrieve related content from ibm.com and beyond, identified for your convenience.

This feature requires Internet access.

Task topic    

Terms of Use | Feedback

Last updated: Sep 20, 2010 11:08:29 PM CDT
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=vela&product=was-nd-mp&topic=tsectbucs
File name: tsec_tbucs.html