19 Developing with the User and Role API

This chapter describes how to work with the APIs for user and role management. Prior to using this information, it is strongly recommended that you familiarize yourself with the context in which these APIs are used. For details, see:

It contains the topics:

19.1 Introduction to the User and Role API Framework

The User and Role API framework allows applications to access identity information (users and roles) in a uniform and portable manner regardless of the particular underlying identity repository. The repository could be an LDAP directory server such as Oracle Internet Directory, Active Directory (from Microsoft), or Sun Java System Directory Server (from Sun Microsystems), or could be a database, flat file, or some other custom repository.

This API framework provides a convenient way to access repositories programmatically in a portable way, freeing the application developer from the potentially difficult task of accounting for the intricacies of particular identity sources. The framework allows an application to work against different repositories seamlessly. An application can switch between various identity repositories without any code changes being required.

Supported operations include creating, updating, or deleting users and roles, or searching users and roles for attributes or information of interest. For example, you may want to search for the e-mail addresses of all users in a certain role.

Note:

These APIs are not meant for authentication or authorization functions, but for maintaining identity information.

You can use a basic usage model (without container integration) or a usage model with container integration that allows your code to be portable.

When the application is intended to run the context of an Oracle WebLogic Server container, the principal class should be cast to weblogic.security.principal.WLSUserImpl.

19.1.1 User and Role API and the Oracle WebLogic Server Authenticators

The User and Role API is automatically configured to use the first Oracle WebLogic Server authenticator and does not require any special configuration.

Note, however, that configuration is required if the User and Role API is going against other authenticators.

The API can access data only from the first LDAP authenticator listed in an Oracle WebLogic Server domain. Any LDAP authenticators below the first one on the list are not accessed.

19.2 Summary of Roles and Classes

Table 19-1 lists the classes and interfaces of the User and Role API.

Table 19-1 Classes and Interfaces in the User and Role API

Name Type Description

AuthenticationException

Class

This exception is thrown when an authentication error occurs while accessing the identity store. An authentication error can happen, for example, when the credentials supplied by the user program is invalid or otherwise fails to authenticate the user to the identity store.

AuthenticationWarningException

Class

This class extends IMException (see below).

ComplexSearchFilter

Interface

A complex search filter represents a complex logical expression that can be used to filter results from underlying identity repository. Complex search filter combines multiple SearchFilter instances together with a single logical operator (AND/OR). Each of these component SearchFilter can itself be a complex filter thus resulting in capability to form really complex nested search filter.

See the Javadoc (Section 19.9, "The User and Role API Reference") for an example of creating a complex search filter.

ConfigurationException

Class

This exception is thrown when there is a configuration problem. This can arise when configuration information required to access the service provider is malformed or missing.

Identity

Interface

This interface represents a basic identity in the identity repository.

IdentityStore

Interface

IdentityStore represents a handle to actual identity repository. This handle can be used to search, create, drop, and modify identities in the repository.

IdentityStoreFactory

Interface

IdentityStoreFactory is a programmatic representation of underlying identity repository. Actual handle to the identity repository can be obtained by calling getIdentityStoreInstance(Hashtable) on this object.

IdentityStoreFactoryBuilder

Class

This class builds the identity store factory.

IMException

Class

This exception is the super class of all the exceptions thrown by ADF identity management APIs. The nature of failure is described by the name of the subclass.

See the Javadoc (Section 19.9, "The User and Role API Reference") for a list of the direct known subclasses.

ModProperty

Class

This class represents the modification of a property object. ModProperty is called with property name, modified value(s) and type of modification. Modification type can be one of ADD, REMOVE, or REPLACE.

NoPermissionException

Class

This exception is thrown when attempting to perform an operation for which the API caller has no permission. The access control/permission model is dictated by the underlying identity store.

ObjectExistsException

Class

This exception is thrown when an identity with given name is already present in the underlying identity store. For example this exception is thrown when create user API call tries to create a user with name of an existing user.

ObjectNotFoundException

Class

This exception is thrown when a specified identity does not exist in the identity store.

OperationFailureException

Class

This exception is thrown when an operation fails during execution in the underlying identity store.

OperationNotSupportedException

Class

This exception is thrown by an service provider if it doesn't support an operation. For example this can be thrown by the service provider, in IdentityStore.getUserManager() call, if it doesn't provide support for UserManager.

PasswordPolicyException

Class

This class extends IMException (see above).

Property

Class

Property contains name-value information.

PropertySet

Class

A collection of property name and value pairs. Property class is used to represent the property name and value(s) pair. PropertySet guarantees that no two properties have same name.

Role

Interface

This interface represents a role in the identity store.

RoleManager

Interface

This interface represents a role manager that manages execution of various operations, involving roles, in the identity repository.

RoleProfile

Interface

This interface represents the detailed profile of a role.

SearchFilter

Interface

This interface represents a search filter to be used in searching the identity repository.

SearchParameters

Class

This class represents search parameters that need to be specified while performing searches on the identity store. These search parameters are

Search filter, Search identity type, page size, time limit, and count limit.

SearchResponse

Interface

This interface represents search results obtained after searching the identity store. Its implementation is service provider-specific.

SimpleSearchFilter

Interface

This interface represents a simple search filter to be used while searching the identity repository. Each simple search filter is a logical expression consisting of a search attribute/property, evaluation operator and value. This logical expression will be applied to underlying identity repository while searching and matching results will be filtered out.

See the Javadoc (Section 19.9, "The User and Role API Reference") for an example of a simple search filter.

StoreConfiguration

Interface

StoreConfiguration holds the configuration properties for a given IdentityStore instance. The behavior of this IdentityStore instance can be controlled by changing the properties in this configuration object. The actual configuration properties and their values are specific to the service provider. Some service providers may not support any configuration property at all.

SubjectParser

Interface

This interface provides utility methods for extracting out the user and role principals from the given Subject. Service provider needs to provide the implementation for this interface.

User

Interface

This interface represents a user in the identity store.

UserManager

Interface

This interface represents a user manager that manages execution of various operations, involving users, in the identity repository.

UserProfile

Interface

This interface represents the detailed profile of a user. It allows for user properties to be accessed in a generic manner.

You can read or modify any property of user with these APIs:

  • getProperty(java.lang.String)

  • getProperties(java.lang.String[])

  • setProperty(oracle.security.idm.ModProperty)

  • setProperties(oracle.security.idm.ModProperty[])


19.3 Working with Service Providers

In this section we describe basic provider concepts and life cycle, and explain how to set up, configure, and use the provider to work with user repositories in an Oracle Platform Security Services environment.

After ensuring the environment is properly set up, implementing the provider involves:

  • identifying the underlying repository and selecting the provider factory class appropriate to that repository

  • creating instances of the provider factory and the identity store

  • configuring the provider

This section contains these topics:

19.3.1 Understanding Service Providers

Although the User and Role API is called for user and role management, the API does not directly interact with the underlying identity repository. Instead, security applications make use of providers which carry out the actual communication with the underlying repository. This offers flexibility since the same code can be used with various underlying repositories, simply by modifying the provider/connection information.

19.3.2 Setting Up the Environment

Several jars must be present in your environment:

  • the provider jar file, which implements the desired underlying identity repository

  • the User and Role API jars

  • other component jars which the provider may need, including Toplink, jdbc, xdb, and so on

Ensure that your application classpath includes the relevant jars.

19.3.3 Selecting the Provider

Oracle Platform Security Services support a range of user repositories, including the following LDAP directories:

  • Microsoft Active Directory

  • Novell EDirectory

  • Sun Java System Directory Server Enterprise Edition

  • Oracle Internet Directory

  • Oracle Virtual Directory

  • OpenLDAP

  • Oracle WebLogic Server Embedded LDAP Directory

Your choice of identity store will dictate the provider class you utilize for the provider. The provider class must implement the interface specified by the User and Role API framework. Table 19-2 shows the available provider classes:

Table 19-2 LDAP Identity Provider Classes

Provider Factory Name

Microsoft Active Directory

oracle.security.idm.providers.ad.ADIdentityStoreFactory

Novell EDirectory

oracle.security.idm.providers.edir.EDIdentityStoreFactory

Sun Java System Directory Server

oracle.security.idm.providers.iplanet.IPIdentityStoreFactory

Oracle Internet Directory

oracle.security.idm.providers.oid.OIDIdentityStoreFactory

Oracle Virtual Directory

oracle.security.idm.providers.ovd.OVDIdentityStoreFactory

OpenLDAP

oracle.security.idm.providers.openldap.OLdapIdentityStoreFactory

Oracle WebLogic Server Embedded LDAP Directory

oracle.security.idm.providers.wlsldap.WLSLDAPIdentityStoreFactory


19.3.4 Creating the Provider Instance

Once the provider's class name is identified, you take these steps to create the provider:

  1. Use the getIdentityStoreFactory method of the IdentityStoreFactoryBuilder class to build a factory instance. The builder class API accepts:

    • the provider class name

    • the necessary environment properties from a hash table

  2. Use the getIdentityStoreInstance method of the IdentityStoreFactory class to create a store instance

The following example creates a factory instance for the Oracle Internet Directory store:

IdentityStoreFactoryBuilder builder = new 
   IdentityStoreFactoryBuilder ();
 
IdentityStoreFactory oidFactory = builder.getIdentityStoreFactory(
   “oracle.security.idm.providers.oid.OIDIdentityStoreFactory", factEnv); 

Now the store reference, which is the actual handle to the identity store, can be obtained:

oidStore = oidFactory.getIdentityStoreInstance(storeEnv);

Note that two hash-table objects are supplied in these examples:

  • the factEnv hash table provides the factory instance environment

  • the storeEnv hash table provides the store instance environment

19.3.5 Properties for Provider Configuration

Configuration is dependent on the user/role provider being used.

You can fine-tune the behavior of all types of LDAP-based identity store providers by configuring a number of properties for the factory instance and the store instance. The following properties are relevant for LDAP-based providers only:

  • URL

  • the port at which repository runs

  • the user and password to use in accessing the repository

For a list of LDAP-based providers, see Section 19.3.3, "Selecting the Provider".

19.3.5.1 Start-time and Run-time Configuration

The properties that can be configured fall into two categories:

  • Start-time configuration - the naming convention uses property names starting with ST_.

  • Run-time configuration - the naming convention uses property names starting with RT_.

Start-time Configuration Properties

Start-time configuration is performed only once, and once set, the configuration settings persist for the duration of the provider's lifetime.

With the exception of ST_SUBSCRIBER_NAME, the start-time properties are specified when creating the provider factory instance; ST_SUBSCRIBER_NAME is set when creating the store instance.

Table 19-3 lists the start-time configuration properties:

Table 19-3 Start-time Identity Provider Configuration Properties

Property Name Description

ST_BINARY_ATTRIBUTES

An array of Array of String objects containing the names of binary attributes stored in the underlying LDAP server. The provider will treat these attributes as binary while sending data to and receiving it from the LDAP server.

ST_CONNECTION_POOL

External connection pool, an instance of class oracle.idm.connection.ConnectionPool. If set, the provider uses this pool to acquire connections to the LDAP server, and the properties ST_SECURITY_PRINCIPAL, ST_SECURITY_CREDENTIALS, and ST_LDAP_URL are ignored.

ST_USER_NAME_ATTR

The attribute used to determine the user name of the user in the identity repository.

ST_GROUP_NAME_ATTR

The attribute used to determine the role name in the identity repository.

ST_USER_LOGIN_ATTR

The attribute used to determine the login ID of the user in the identity repository.

ST_SECURITY_PRINCIPAL

The user (principal).

ST_SECURITY_CREDENTIALS

The credentials necessary to log in to the identity repository.

ST_LDAP_URL

The URL of the identity repository.

ST_MAX_SEARCHFILTER_LENGTH

The maximum length of the search filter allowed by the LDAP server.

ST_LOGGER

The logger object that is to be used by the API.

ST_SUBSCRIBER_NAME

The base DN of operations in the LDAP server. This property is specified while creating the IdentityStore instance and is used to determine default values for remaining properties. This property must be specified while creating the IdentityStore instance; however, subsequent changes to its value have no effect on IdentityStore behavior.

ST_CONNECTION_POOL_CLASS

The fully-qualified Connection Pool implementation class name.

ST_INITIAL_CONTEXT_FACTORY

The fully-qualified class name of the initial context factory that will create the initial context.


Run-time Configuration Properties

Properties that you set at runtime affect all subsequent operations executed by the provider and control the behavior of the IdentityStore instance of the provider.

You configure runtime properties by specifying the appropriate parameters and values on the StoreConfiguration object obtained from the IdentityStore instance. All runtime properties have default values when the IdentityStore instance is created, and can be subsequently changed.

Table 19-3 lists the run-time configuration properties:

Table 19-4 Runtime Identity Provider Configuration Properties

Property Name Description

RT_USER_OBJECT_CLASSES

array of object classes required to create a user in the LDAP server

RT_USER_MANDATORY_ATTRS

attribute names that must be specified while creating a user

RT_USER_CREATE_BASES

Base DNs in the LDAP server where a new user can be created

RT_USER_SEARCH_BASES

 

RT_USER_SEARCH_BASES

the base DNs in the LDAP server that can be searched for users

RT_USER_FILTER_OBJECT_CLASSES

array of object classes to use when searching for a user in the LDAP server

RT_GROUP_OBJECT_CLASSES

array of object classes required to create a role in the LDAP server

RT_GROUP_MANDATORY_ATTRS

attribute names that must be specified when creating a role

RT_GROUP_CREATE_BASES

the base DNs in the LDAP server where a new role can be created

RT_GROUP_SEARCH_BASES

the base DNs in the LDAP server that can be searched for a role

RT_GROUP_MEMBER_ATTRS

An array of member attribute(s) in a role. All members of a role have value(s) for the attribute(s).

RT_GROUP_FILTER_OBJECT_CLASSES

an array of object classes to use when searching for a role in the LDAP server

RT_USER_SELECTED_CREATE_BASE

The currently selected user create base. The user will be created in this base DN upon execution of the createUser() call. If the selected create base is null and the ST_SUBSCRIBER_NAME is not specified, the first supplied value of the RT_USER_CREATE_BASE is used. If the ST_SUBSCRIBER_NAME is specified, the default value is relative to the subscriber name based on the identity store type.

RT_GROUP_SELECTED_CREATE_BASE

The currently selected role create base. This role will be created in this base DN upon execution of the createRole() call. If the selected create base is null and the ST_SUBSCRIBER_NAME is not specified, the first supplied value of the RT_GROUP_CREATE_BASE is used. If the ST_SUBSCRIBER_NAME is specified, the default value is relative to the subscriber name based on the identity store type.

RT_GROUP_GENERIC_SEARCH_BASE

A generic role search base to use in searching the roles related to a given identity. For example while searching all granted roles for a user, or all managed roles for a user, we need a search base under which all the required groups would reside; this helps in optimizing the searches. This search base is usually a common parent. By default in all LDAP providers this value is set to the subscriber name if provider, else it uses the first group search base.

RT_SEARCH_TYPE

determines whether a search on the LDAP server should be of type SIMPLE, PAGED, or VIRTUAL_LIST_VIEW


19.3.5.2 When to Pass Configuration Values

You can specify configuration data:

19.3.6 Configuring the Provider when Creating a Factory Instance

This section contains topics related to configuring the provider during factory instance creation.

Configuration at this stage affects the entire factory object as well as objects created using this specific factory instance. Many start-time properties are set at this time, including these common properties:

  • ST_LDAP_URL - the URL of the LDAP repository

  • ST_SECURITY_PRINCIPAL - the user name

  • ST_SECURITY_CREDENTIAL - the user credentials required to connect to the repository

19.3.6.1 Oracle Internet Directory Provider

In this example, the provider is configured when setting up an Oracle Internet Directory (OID) factory:

IdentityStoreFactoryBuilder builder = new 
   IdentityStoreFactoryBuilder();
IdentityStoreFactory oidFactory = null;
Hashtable factEnv = new Hashtable();

// Creating the factory instance
factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_PRINCIPAL,
   "<User DN>");
factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_CREDENTIALS,
   "<User password>");
factEnv.put(OIDIdentityStoreFactory.ST_LDAP_URL,
   "ldap://ldaphost:port/");
oidFactory = builder.getIdentityStoreFactory(
   "oracle.security.idm.providers.oid.
   OIDIdentityStoreFactory", factEnv);

Note:

The values in italics must be replaced with appropriate values prior to execution.

19.3.6.2 Using Existing Logger Objects

You can supply named logger objects to the User and Role API. The API uses the specified logger to log messages. You must supply the external logger's name as an environment variable during the factory creation.

Here is an example:

Logger mylogr = Logger.getLogger("mylogger.abc.com");
FileHandler fh = new FileHandler("userroleapi.log");
mylogr.addHandler(fh);
 
…
 
factEnv.put(OIDIdentityStoreFactory.ST_LOGGER_NAME, 
"mylogger.abc.com");
oidFactory = builder.getIdentityStoreFactory(
   "oracle.security.idm.providers.oid.
   OIDIdentityStoreFactory", factEnv);

This code directs that all the log messages should be redirected to the log file named userroleapi.log.

19.3.6.3 Supplying Constant Values

You can overwrite constants or pre-supply values for missing constants by supplying the map in the ST_PROPERTY_ATTRIBUTE_MAPPING property during factory creation.

This example code sets the mapping of RoleProfile.OWNER to the "myowner" attribute. In this way, all operations related to the owner, such as getOwners(), getOwnedRoles(), and so on, are performed using this attribute.

factEnv.put
   (IPIdentityStoreFactory.ST_SECURITY_PRINCIPAL, "<User DN>");
factEnv.put
   (IPIdentityStoreFactory.ST_SECURITY_CREDENTIALS, "<User password>");
factEnv.put(IPIdentityStoreFactory.ST_LDAP_URL,
   "ldap://ldaphost:port/");
      
Map m = new Hashtable();
m.put(RoleProfile.OWNER, "myowner");
 
factEnv.put
   (IPIdentityStoreFactory.ST_PROPERTY_ATTRIBUTE_MAPPING, m);
 
ipFactory = builder.getIdentityStoreFactory(
   "oracle.security.idm.providers.iplanet.IPIdentityStoreFactory",
   factEnv);

19.3.6.4 Configuring Connection Parameters

You can configure the connection pool parameters for minimum/maximum connections using ST_CONNECTION_POOL_MIN_CONNECTIONS and ST_CONNECTION_POOL_MAX_CONNECTIONS respectively. By default, the values for these parameters are "0" and "10" respectively. There is an additional restriction that:

(ST_CONNECTION_POOL_MAX_CONNECTIONS  - ST_CONNECTION_POOL_MIN_CONNECTIONS) >= 10

Here is an example:

factEnv.put
   (LDIdentityStoreFactory.ST_CONNECTION_POOL_MIN_CONNECTIONS,  "3");
 
factEnv.put
   (LDIdentityStoreFactory.ST_CONNECTION_POOL_MAX_CONNECTIONS, "16");

19.3.6.5 Configuring a Custom Connection Pool Class

This section explains how to provide a custom connection pool class.

To use a custom connection pool, you must provide the fully qualified class name of the custom connection pool class, as follows:

factEnv.put(OIDIdentityStoreFactory.ST_CONNECTION_POOL_CLASS,
"oracle.security.idm.providers.stdldap.JNDIPool");

19.3.7 Configuring the Provider when Creating a Store Instance

The IdentityStore configuration affects the store object and all objects that are created using this store instance. A configuration parameter commonly used with the store is ST_SUBSCRIBER_NAME, which is the only start-time property accepted here. (All the runtime properties can be supplied during identity store creation.)

Continuing with the earlier example in Section 19.3.6, "Configuring the Provider when Creating a Factory Instance" which created a factory instance, this code creates a handle instance to the store.

IdentityStore oidStore = null;
Hashtable storeEnv = new Hashtable();
 
// Creating the store instance
storeEnv.put(OIDIdentityStoreFactory.ST_SUBSCRIBER_NAME,
   "dc=us,dc=oracle,dc=com");
oidStore = oidFactory.getIdentityStoreInstance(storeEnv);

Note:

Directories require that you supply a valid subscriber name.

For Oracle Internet Directory, you can supply the STsubscriber name as either a proper DN or as the nickname of the realm.

19.3.8 Runtime Configuration

Earlier, in Section 19.3.6, "Configuring the Provider when Creating a Factory Instance" and Section 19.3.7, "Configuring the Provider when Creating a Store Instance", we demonstrated how to perform configuration during instance creation. To facilitate adding and modifying properties at runtime the User and Role APIs also provide a Configuration class.

The Configuration instance can be obtained from the store instance using the IdentityStore.getStoreConfiguration() API call. Properties can be modified using the configuration object.

Only runtime properties can be modified using this approach, and the effect is visible only at runtime.

This example sets the RT_USER_SEARCH_BASES property:

StoreConfiguration conf = oidStore.getStoreConfiguration();
conf.setProperty(“RT_USER_SEARCH_BASES”, “dc=us,dc=oracle,dc=com”);

19.3.9 Programming Considerations

This section contains tips for working with providers and provider artifacts.

19.3.9.1 Provider Portability Considerations

To ensure that your application is portable when switching providers (say, from fusiondb provider to Oracle Internet Directory provider or the converse), follow these guidelines when working with the User and Role APIs:

  1. Use only the corresponding oracle.security.idm.UserProfile constants to refer to user properties. Avoid using native names which are not portable across identity repositories. For example, if the application needs to obtain a user's login name, fetch it using the UserProfile.USER_NAME constant:

    Property prop = usrprofile.getProperty(UserProfile.USER_NAME);
    
  2. For obvious reasons, UserProfile constants are provided for most standard user properties but not for all possible properties. If the application needs to obtain all the properties of a user generically, use the following code:

    UserProfile upf = null;
     
    // Obtain the user profile from user object. User object can be obtained using search 
    
    // get the properties supported for given user in currently configured repository
    List proplst = store.getUserPropertyNames();
    
    String[] proparr = (String[]) proplst.toArray(new String[proplst.size()]);
    
    // get all properties of the user
    PropertySet pset = upf.getProperties(proparr);
    
  3. When creating search filters, do not use native wild card characters directly in your search filter string. Instead, use the SimpleSearchFilter.getWildCardCharacter() API. This will fetch the correct wild character based upon the underlying provider. For example, the API will return % for the FusionDB provider and return * for the Oracle Internet Directory (OID) provider.

    SmpleSearchFilter sf = m_identityStore.getSimpleSearchFilter(
       attrName, SimpleSearchFilter.TYPE_EQUAL, null); 
    
    sf.setValue( filterStringWithoutWildcard+sf.getWildCardChar());
    
  4. If your application accepts user-supplied filter strings with a predefined wild card character, apply the following conversion on the filter while generating the User and Role API filter:

    //User supplied filter which assumes “%” as the wildcard character
    
    String userDefinedFilter = .................
    
    SmpleSearchFilter sf = m_identityStore.getSimpleSearchFilter(
       attrName, SimpleSearchFilter.TYPE_EQUAL, null);
    
    userDefinedFilter = 
       userDefinedFilter.replaceall("%", sf.getWildCardChar());
    
    sf.setValue(  userDefinedFilter); 
    

    The line in bold converts the user-supplied filter to the generic User and Role API filter format.

19.3.9.2 Considerations when Using IdentityStore Objects

Thread Safety

The current IdentityStore implementations are not thread-safe. The User and Role API assumes that the store instances are not generally shared among threads. If the store instance is shared among threads, the application code must take care to handle any required thread safety issues.

There are trade-offs between thread safety and performance. Use cases that need to implement thread safety must be willing to consider the performance implications of doing so.

One Store Instance per Session

In applications such as DAS, each session (corresponding to one logged-in user) can change its own create/search bases and various other runtime settings; these are defined as runtime properties in User and Role APIs. The IdentityStore object encapsulates all these settings and changes its runtime behavior accordingly. For this reason the rule of one IdentityStore instance per session is enforced.

19.3.10 Provider Life cycle

A given provider exists for the lifetime of the factory instance created for that provider. The life of a factory instance ends whenever the close() API is called on that instance. When the provider instance ends, all the objects that were created using that instance become invalid, and subsequent API calls on those objects would return unanticipated output.

Similar considerations apply to IdentityStore instances.

Note:

  • Factory instances are thread-safe while this is not the case with IdentityStore instances.

  • It is best practice to cascade close server connections and explicitly delete objects and instances no longer in use.

19.4 Searching the Repository

The User and Role API provides two types of query functions:

  • APIs that return a single identity

  • APIs that return a list of identities

This section describes searches and related tasks you can accomplish with the APIs, and provides details on specifying search parameters:

19.4.1 Searching for a Specific Identity

You can query the identity store directly for a specific user or role using the searchUser and searchRole APIs:

IdentityStore.searchUser(String name);
 
IdentityStore.searchUser(Principal principal);
 
IdentityStore.searchUser(int searchType, String name); 
 

where searchType can be:

  • SEARCH_BY_NAME

  • SEARCH_BY_UNIQUE_NAME

IdentityStore.searchRole(int searchType, Sting value);

These APIs facilitate simple queries where a particular user/role identity is known to exist in the store, and you simply need the object reference to that identity. These API's are minimal in that:

  • they accept only string values

  • they do not support regular expressions

These functions raise an exception if multiple entities having the same value exist in the store.

19.4.2 Searching for Multiple Identities

The User and Role APIs contain several functions that can perform searches to return multiple identities:

IdentityStore.search(SearchParams params);
IdentityStore.searchUsers(SearchParams params);
IdentityStore.searchRoles(int searchType, SearchParams params);
IdentityStore.searchProfiles(SearchParams params);

Each function accepts a search object and returns a search response object.

19.4.3 Specifying Search Parameters

The SearchParams Object

The SearchParams object contains the following information:

  • Search Filter - this is discussed below

  • Search Identity of type - you can search identities of type Roles or Users

  • Page Size - By default the paging option is turned off. If the query needs paging, set the page size to a relevant positive value.

  • Timeout limit – Timeout is specified in seconds

  • Count Limit – Limits the number of results returned by the query

The SearchResponse Object

SearchResponse is a data structure that is used when retrieving multiple identities. Your code can iterate through the identities contained in this structure using these functions:

  • hasNext() - returns true if more elements are present, false otherwise

  • next() – returns the next element if it is available, an exception otherwise

19.4.4 Using Search Filters

The User and Role APIs include different types of search filters to facilitate a variety of search operations. This section t explains key facts about the use of search filters:

19.4.4.1 Operators in Search Filters

Observe these rules when using search filter operators.

Supported Operators

The standard LDAP store accepts only "=" (equals operator), "<" (less-than operator), ">" (greater-than operator), "&" (AND operator), "|" (OR operator) and "!" (NOT operator). IdentityStore provides two more operators to make usage simpler, namely "<=" (less than or equal to) and ">=" (greater than or equal to).

The operators "=", "<",">", "<=" and ">=" are used to create simple search filters while the "&" and "|" operators are used to combine two or more search strings to make a complex search filter.

NOT Operator

You can use the NOT operator in both the simple search filter and complex search filters. This operator is used to negate the state of the filter, that is, the state of the filter is changed to accept the entities which were earlier rejected by the filter (or the converse).

The NOT operator is accessible using the following SearchFilter API:

  • void negate();

  • boolean isNegated();

19.4.4.2 Handling Special Characters when Using Search Filters

According to RFC-2254 (String Representation of LDAP Search Filters), "*", "(", ")","\" and NULL characters are to be handled separately. The User and Role API handles "(", ")" and "\" operators but does not handle the "*" operator, which is also a wild-card character for LDAP stores. The API user is not required to separately handle these characters as the User and Role API framework handles these characters.

19.4.4.3 Examples of Using Search Filters

Several usage examples are presented.

Example 1: Simple Filter to Retrieve Users by Name

The implementation of the simple search filter depends on the underlying store; you can obtain an instance of the search filter through the store instance.

In this example, the filter allows all entries with a non-null value for the "name" field:

SimpleSearchFilter sf = 
   oidStore.getSimpleSearchFilter(UserProfile.NAME, 
   SimpleSearchFilter.TYPE_EQUAL, null);
sf.setValue(sf.getWildCardChar());

Example 2: Simple Filter to Find Users by Language Preference

This example retrieves users whose preferred language is not English:

SimpleSearchFilter sf = 
   oidStore.getSimpleSearchFilter(
      UserProfile.PREFERRED_LANGUAGE,          
      SimpleSearchFilter.TYPE_EQUAL,
      "english");
sf.negate();

Example 3: Complex Filter for Names by Starting Letter

This complex filter combines multiple search filters with operators "&" or "|". It searches for users whose name starts with a letter between "a" and "j":

SimpleSearchFilter sf1 = 
   oidStore.getSimpleSearchFilter(
      UserProfile.NAME,
      SimpleSearchFilter.TYPE_GREATER,
      null);
 
sf1.setValue("a"+sf1.getWildCardChar());
SimpleSearchFilter sf2 = 
   oidStore.getSimpleSearchFilter(UserProfile.NAME, 
      SimpleSearchFilter.TYPE_LESS, null);
sf2.setValue("j"+sf2.getWildCardChar());
SimpleSearchFilter sfArray[] = new SimpleSearchFilter[] {sf1, sf2};
ComplexSearchFilter cf1 = 
store.getComplexSearchFilter(sfArray, ComplexSearchFilter.TYPE_AND); 

Example 4: Complex Filter with Restrictions on Starting Letter

In this example, complex filters are nested to enable a search for users whose name starts with a letter between "a" and "j" but not with the letter "i":

[continue from Example 3]

SimpleSearchFilter sf3 = 
   oidStore.getSimpleSearchFilter(
      UserProfile.NAME,                                  
      SimpleSearchFilter.TYPE_EQUAL, 
      null);
 
sf3.setValue(“i”+sf3.getWildCardChar());
sf3.negate();
 
SearchFilter sfArray2[] = new SearchFilter[] {cf1, sf3};
ComplexSearchFilter cf2 = 
   store.getComplexSearchFilter(sfArray2, ComplexSearchFilter.TYPE_AND); 

Example 5: Complete Search with Output

This code filters names starting with the letter "a" and outputs the return values:

// search filter (cn=a*)
SimpleSearchFilter sf = oidStore.getSimpleSearchFilter(
      UserProfile.NAME, 
      SimpleSearchFilter.TYPE_EQUAL, 
      null);
sf.setValue("a"+sf.getWildCardChar());
      
SearchParameters params = new SearchParameters();
params.setFilter(sf);
 
// Searching for users
SearchResponse resp = oidStore.searchUsers(params);
System.out.println("Searched users are:");
while (resp.hasNext()) {
   Identity idy = resp.next();
   System.out.println("Unique name: "+idy.getUniqueName());
}

19.4.5 Searching by GUID

In this example, GUID values obtained from the User and Role API can be directly used in the search:

// up = user.getUserProfile();
String guid = up.getGUID();
SimpleSearchFilter sf1 = oidStore.getSimpleSearchFilter(
   UserProfile.GUID, 
   SimpleSearchFilter.TYPE_EQUAL, guid);
SearchParameters params = new SearchParameters();
params.setFilter(sf1);
SearchResponse resp = oidStore.search(params);
while (resp.hasNext())
   System.out.println("user for guid : " + guid + ","+ resp.next());

19.5 User Authentication

For verification purposes, you can use the User and Role APIs for password-based authentication of users.

The authenticateUser API accepts a user login name and attempts to authenticate the user with the specified password. If authentication is successful, it returns the user object.

Here is an example of password-based authentication:

store.getUserManager().authenticateUser(“testuser”,”password”);

19.6 Creating and Modifying Entries in the Identity Store

The User and Role API facilitates adding new identities to the identity store and modifying identities in the store. The UserManager and RoleManager classes address the user- and role-specific data creation, modification and deletion operations.

UserManager and RoleManager instances can be obtained from the store instance as follows:

UserManager um = oidStore.getUserManager();
RoleManager rm = oidStore.getRoleManager();

Topics in this section include:

19.6.1 Handling Special Characters when Creating Identities

RFC-2253 defines the string representation of Distinguished Names for LDAP v3. This means that all the characters specified in the RFC are handled. The User and Role API user does not need to escape/de-escape those special characters; attempting to do so will cause erroneous results.

There could be a problem when creating identities with empty properties. In this case, the "RDN name" is used to fill in the values of various mandatory attributes. Some of these attributes could have stricter validation rules. In this case, the creation of the identity fails and an exception is raised.

19.6.2 Creating an Identity

Two APIs in the UserManager class facilitate creating a user:

  • createUser(java.lang.String name, char[] password)
    

    creates a user with the specified name and password in the underlying repository.

    When the identity store designates that some attributes are mandatory, all such fields will be populated with the "name" value.

  • createUser(java.lang.String name, char[] password, PropertySet suppliedProps)
    

    Properties are set using the supplied property values. If any mandatory attribute values are not supplied, the missing attributes will use the "name" value as the default.

Likewise, RoleManager APIs are used to create roles.

Roles are organized into two categories:

  • application scope

  • enterprise scope

When you invoke RoleManager to create a role, by default the role is created in the enterprise scope unless you specify otherwise.

RoleManager APIs supporting role creation are:

createRole(String roleName);
createRole(String roleName, int roleScope);

The procedure for creating a role is similar to that for creating a user, and all mandatory attributes must be supplied with roleName.

19.6.3 Modifying an Identity

In order to modify an identity, you need a reference to the identity. The User, UserProfile, Role, and RoleProfile classes provide the following APIs to facilitate modifying identities:

user.setProperty(ModProperty prop);
 
user.setProperties(ModProperty [] props);

ModProperty structure consists of:

  • the field name

  • its new value(s)

  • the modifying operator

Valid operators are:

ModProperty.ADD
ModProperty.REMOVE
ModProperty.REPLACE

In this example, a display name is replaced:

UserProfile usrprofile = usr.getUserProfile();
 
ModProperty mprop = new ModProperty(UserProfile.DISPLAY_NAME,
   "modified display name",
   ModProperty.REPLACE);
 
usrprofile.setProperty(mprop);

Modifying a particular value in a multi-valued attribute is a two-step process; first remove the value, then add the new value.

19.6.4 Deleting an Identity

You drop an identity with the dropUser and dropRole APIs.

You need both user and role references in your code when dropping an identity.

Here is an example:

User usr;
Role role;
…
…
usrmanager.dropUser(usr);
rolemanager.dropRole(role);

19.7 Examples of User and Role API Usage

This section contains two examples illustrating practical applications of the User and Role APIs:

19.7.1 Example 1: Searching for Users

In this example the identity store is Oracle Internet Directory, and a simple search filter is set up to search for users:

import oracle.security.idm.*;
import oracle.security.idm.providers.oid.*;
import java.util.*;
import java.io.*;
 
public class SearchUsersOID
{
  public static void main(String args[])
  {
    IdentityStoreFactoryBuilder builder = new    
IdentityStoreFactoryBuilder();
    IdentityStoreFactory oidFactory = null;
    IdentityStore oidStore = null;
 
    try
    {
 
      Hashtable factEnv = new Hashtable();
      Hashtable storeEnv = new Hashtable();
 
      // creating the factory instance
      factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_PRINCIPAL,
                   "<User DN>");
      factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_CREDENTIALS, 
                   "<User password>");
      factEnv.put(OIDIdentityStoreFactory.ST_LDAP_URL,
                  "ldap://ldaphost:port/");
oidFactory =  builder.getIdentityStoreFactory(
              "oracle.security.idm.providers.oid.OIDIdentityStoreFactory", 
              factEnv);
      
      // creating the store instance
         storeEnv.put(OIDIdentityStoreFactory.RT_SUBSCRIBER_NAME,
         "<Subscriber name>");
      oidStore = oidFactory.getIdentityStoreInstance(storeEnv);
 
      // search filter (cn=a*)
      SimpleSearchFilter sf = oidStore.getSimpleSearchFilter(
                    UserProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, null);
      sf.setValue("a"+sf.getWildCardChar());
// sf2 search filter (!(cn=*a)) 
SimpleSearchFilter sf2 = oidStore.getSimpleSearchFilter(
                    UserProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, null);
sf2.setValue(sf.getWildCardChar()+"a");
sf2.negate();
      
SimpleSearchFilter sfArray[] = new SimpleSearchFilter[] {sf,sf2};
ComplexSearchFilter cf1 = oidStore.getComplexSearchFilter(sfArray,
ComplexSearchFilter.TYPE_AND);
     
SearchParameters params = new SearchParameters();
params.setFilter(cf1);
 
 // Searching for users
SearchResponse resp = oidStore.searchUsers(params);
System.out.println("Searched users are:");
while (resp.hasNext()) {
    Identity idy = resp.next();
    System.out.println("Unique name: "+idy.getUniqueName());
}
    }catch (IMException e)
    {
      e.printStackTrace();
    }
  }
}

19.7.2 Example 2: User Management in an Oracle Internet Directory Store

In this example several user management tasks such as creating, modifying, and dropping an identity are performed in an Oracle Internet Directory store:

  • creating a user

  • modifying the user's display name

  • dropping the user

public class CreateModifyDeleteUser
{
  public static void main(String args[])
  {
    IdentityStoreFactoryBuilder builder = new 
IdentityStoreFactoryBuilder();
    IdentityStoreFactory oidFactory = null;
    IdentityStore oidStore = null;
 
    try
    {
 
      Hashtable factEnv = new Hashtable();
      Hashtable storeEnv = new Hashtable();
 
      // creating the factory instance
      factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_PRINCIPAL,
                   "<User DN>");
      factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_CREDENTIALS, 
                   "<User password>");
      factEnv.put(OIDIdentityStoreFactory.ST_LDAP_URL,
                  "ldap://ldaphost:port/");
      oidFactory =  builder.getIdentityStoreFactory(
                  "oracle.security.idm.providers.oid.
OIDIdentityStoreFactory", 
               factEnv);
      
      // creating the store instance
      storeEnv.put(OIDIdentityStoreFactory.RT_SUBSCRIBER_NAME, 
                   "dc=us,dc=oracle,dc=com");
      oidStore = oidFactory.getIdentityStoreInstance(storeEnv);
 
      //get UserManager
      UserManager usrmanager = oidStore.getUserManager();
 
      // create user
      String usrname = "testuser";
      // delete user if already exists
      try
      {
        User usr = oidStore.searchUser(usrname);
        usrmanager.dropUser(usr);
      }catch(IMException ime){}
 
      System.out.println("creating user "+usrname);
      User usr = 
usrmanager.createUser(usrname,"passwd1".toCharArray());
      System.out.println("user (" +usr.getUniqueName() + ") created");
 
      // modifying user properties
      System.out.println("modifying property 
UserProfile.DISPLAY_NAME");
      UserProfile usrprofile = usr.getUserProfile();
      ModProperty mprop = new ModProperty(
UserProfile.DISPLAY_NAME,
                        "modified display name",
                        ModProperty.REPLACE);
 
      usrprofile.setProperty(mprop);
      
      System.out.println("get property values 
UserProfile.DISPLAY_NAME");
      Property prop = usrprofile.getProperty(UserProfile.DISPLAY_NAME);
      List values = prop.getValues();
      Iterator itr = values.iterator();
      while(itr.hasNext()) {
        System.out.println(UserProfile.DISPLAY_NAME+": "+ itr.next());
      }
      System.out.println();
 
      // drop user
      System.out.println("Now dropping user "+usrname);
      usrmanager.dropUser(usr);
      System.out.println("user dropped");
 
    }catch (IMException e)
    {
      e.printStackTrace();
    }
  }
}

19.7.3 Example 3: User Management in a Microsoft Active Directory Store

In this example several user management tasks such as creating, modifying, and dropping an identity are performed in a Microsoft Active Directory store:

  • creating a user

  • modifying the user's display name

  • dropping the user

package oracle.security.idm.samples;
 
import oracle.security.idm.*;
import oracle.security.idm.providers.ad.*;
import java.util.*;
import java.io.*;
 
public class CreateModifyDeleteUserAD
{
  public static void main(String args[])
  {
    IdentityStoreFactoryBuilder builder = new IdentityStoreFactoryBuilder();
    IdentityStoreFactory adFactory = null;
    IdentityStore adStore = null;
 
    try
    {
 
      Hashtable factEnv = new Hashtable();
      Hashtable storeEnv = new Hashtable();
 
      String keystore = "/home/bhusingh/client_keystore.jks";
      System.setProperty("javax.net.ssl.trustStore",keystore);
      System.setProperty("javax.net.ssl.trustStorePassword","welcome1");
 
      // creating the factory instance
      factEnv.put(ADIdentityStoreFactory.ST_SECURITY_PRINCIPAL,
                  "sramaset@upad.us.oracle.com");
      factEnv.put(ADIdentityStoreFactory.ST_SECURITY_CREDENTIALS, 
                   "ntrtntrt");
      factEnv.put(ADIdentityStoreFactory.ST_LDAP_URL,
                  "ldaps://mynode.us.mycorp.com:123/");
      factEnv.put("java.naming.security.protocol","SSL");
      
 
      adFactory =  builder.getIdentityStoreFactory(
                    "oracle.security.idm.providers.ad.ADIdentityStoreFactory",
                    factEnv);
 
      // creating the store instance
      storeEnv.put(ADIdentityStoreFactory.ST_SUBSCRIBER_NAME, 
                   "dc=upad,dc=us,dc=oracle,dc=com");
      adStore = adFactory.getIdentityStoreInstance(storeEnv);
 
      //get UserManager
      UserManager usrmanager = adStore.getUserManager();
 
      // create user
      String usrname = "amyd";
      // delete user if already exists
      try
      {
        User usr = adStore.searchUser(usrname);
        usrmanager.dropUser(usr);
      }catch(IMException ime){}
 
      System.out.println("creating user "+usrname);
      char[] password = {'w', 'e', 'l', 'c', 'o', 'm','e','3'};
      User usr = usrmanager.createUser(usrname, password);
      System.out.println("user (" +usr.getUniqueName() + ") created with guid="+usr.getGUID());
      System.out.println("user name = "+usr.getName() );
 
      // modifying user properties
      System.out.println("DISPLAY_NAME="+usr.getDisplayName());
      System.out.println("modifying property UserProfile.DISPLAY_NAME");
      UserProfile usrprofile = usr.getUserProfile();
      ModProperty mprop = new ModProperty(UserProfile.DISPLAY_NAME,
                                          "modified display name",
                                          ModProperty.REPLACE);
      usrprofile.setProperty(mprop);
      
      System.out.println("get property values UserProfile.DISPLAY_NAME");
      Property prop = usrprofile.getProperty(UserProfile.DISPLAY_NAME);
      List values = prop.getValues();
      Iterator itr = values.iterator();
      while(itr.hasNext())
      {
        System.out.println(UserProfile.DISPLAY_NAME+": "+ itr.next());
      }
      System.out.println();
 
      System.out.println("now verifying the password");
      boolean pass = false;
      try
      {
        usrmanager.authenticateUser(usrname, password);
        pass= true;
      }catch (oracle.security.idm.AuthenticationException e) 
      {
        System.out.println(e);
        e.printStackTrace();
      }
      if (pass)
        System.out.println("password verification SUCCESS !!");
      else
        System.out.println("password verification FAILED !!");
 
      SimpleSearchFilter sf = adStore.getSimpleSearchFilter(
                    UserProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, usrname);
      
      SearchParameters params = new SearchParameters();
      params.setFilter(sf);
 
      // Searching for users
      SearchResponse resp = adStore.searchUsers(params);
      System.out.println("Searched users are:");
      while (resp.hasNext())
      {
        Identity idy = resp.next();
        System.out.println("name: "+idy.getName()+"\tUnique name: "+idy.getUniqueName());
      }
 
 
      // drop user
      System.out.println("Now dropping user "+usrname);
      usrmanager.dropUser(usr);
      System.out.println("user dropped");
 
    }catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}

19.8 SSL Configuration for LDAP-based User and Role API Providers

This section describes SSL support for the User and RoleAPIs. It contains these topics:

19.8.1 Out-of-the-box Support for SSL

LDAP-based providers for User and Role APIs rely on the Sun Java Secure Sockets Extension (JSSE) to provide secure SSL communication with LDAP-based identity stores. JSSE is part of JDK 1.4 and higher.

These providers are:

  • Microsoft Active Directory

  • Novell eDirectory

  • Sun Java System Directory Server

  • Oracle Internet Directory

  • OpenLDAP

  • Oracle WebLogic Server Embedded LDAP Directory

19.8.1.1 System Properties

To support SSL you need to provide the following information in the form of system properties:

javax.net.ssl.keyStore
 
javax.net.ssl.keyStorePassword
 
javax.net.ssl.trustStore
 
javax.net.ssl.trustStorePassword

Refer to Sun Microsystems' documentation on JSSE for details.

19.8.1.2 SSL configuration

You need to provide SSL configuration details during User and Role API configuration.

Provide your keystore location and password as system properties to the JVM:

String keystore = "<key store location>";
String keypasswd = "<key store password>";
System.setProperty("javax.net.ssl.trustStore",keystore);
System.setProperty("javax.net.ssl.trustStorePassword", keypasswd);

Specify following properties in the environment when creating the IdentityStoreFactory instance:

  1. Set the SSL URL of the LDAP server, as in this example:

    factEnv.put(ADIdentityStoreFactory.ST_LDAP_URL,
     "ldaps://ldaphost:sslport/");
    
  2. Set the security protocol to SSL:

    factEnv.put("java.naming.security.protocol","SSL");
    

19.8.2 Customizing SSL Support for the User and Role API

You can customize SSL support by providing a customized SSLSocketFactory to the User and Role API provider.

19.8.2.1 SSL configuration

Specify the following properties when creating the IdentityStoreFactory instance:

  1. Specify the custom SSL socket factory name:

    factEnv.put("java.naming.ldap.factory.socket", 
    "fully qualified custom socket factory name");
    
  2. Set the SSL URL of the LDAP server, as in this example:

    factEnv.put(ADIdentityStoreFactory.ST_LDAP_URL,
     "ldaps://ldaphost:sslport/");
    
  3. Set the security protocol to SSL:

    factEnv.put("java.naming.security.protocol","SSL");
    

19.9 The User and Role API Reference

The User and Role API reference (Javadoc) is available at:

Oracle Fusion Middleware User and Role Java API Reference for Oracle Platform Security Services