Skip Headers
Oracle® Fusion Middleware Application Security Guide
11g Release 1 (11.1.1)

Part Number E10043-09
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

25 Developing with the User and Role API

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

This chapter contains these topics:

Note:

The User and Role API is deprecated and may be withdrawn in a future release. Your new applications should be developed on the Identity Governance Framework. Plan to migrate existing applications to the Identity Governance Framework in a future release.

For details, see the Oracle Fusion Middleware Identity Governance Framework ArisID API Developer's Guide.

25.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 Oracle Directory Server Enterprise Edition, 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 in the context of an Oracle WebLogic Server container, the principal class should be cast to weblogic.security.principal.WLSUserImpl.

Note:

The following are required to invoke the User and Role API:
  • The identity store is LDAP-based

  • The domain administration server is up and running

A Note about Using the User and Role API

As a general rule of thumb, authentication should only be performed by authentication providers, not through the User and Role API.

Additionally, it is recommended that authentication providers be configured with the connect DN of a user that does not have write privileges.

25.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. F

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. When more than one authenticator is present, the precedence is determined by their control flag priority. If both have the same priority, the first one is picked. Any LDAP authenticators below the first one on the list are not accessed.

About Concurrent Use of WebLogic APIs

Your application should not try to use both the User and Role API and the WebLogic LDAPAuthenticator API (such as EmbeddedLDAPAuthenticator, OracleInternetDirectoryAuthenticator, OracleVirturalDirectoryAuthenticator) to work on entries in the same LDAP server concurrently. To understand why, consider two LDAP clients, both with caching enabled, that access the same LDAP server; one is deleting entries, and the other tries to use the deleted entries.

The conflict caused by the two clients cannot be resolved unless caching capability is disabled, and the LDAP operations are coordinated among the clients.

25.2 Summary of Roles and Classes

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

Table 25-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, enabling you to form a complex nested search filter.

See the Javadoc (Section 25.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 superclass 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 25.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 the 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 does not support an operation. For example this can be thrown by the service provider, in IdentityStore.getUserManager() call, if it does not 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 the underlying identity repository while searching and matching results will be filtered out.

See the Javadoc (Section 25.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[])


25.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:

This section contains these topics:

25.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.

25.3.2 Setting Up the Environment

Jar Configuration

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.

User Classes in jps-config.xml (Oracle Virtual Directory only)

Note:

Make this change only for the Oracle Virtual Directory authenticator.

For efficiency when fetching user attributes, add the following entry in jps-config.xml to specify the user object classes for the search:

.
.
     <serviceInstance name="idstore.ldap" provider="idstore.ldap.provider">
            <property name="idstore.config.provider"
value="oracle.security.jps.wls.internal.idstore.WlsLdapIdStoreConfigProvider"/
>
            <property name="CONNECTION_POOL_CLASS"
value="oracle.security.idm.providers.stdldap.JNDIPool"/>
          <extendedProperty>
            <name>user.object.classes</name>
            <values>
               <value>top</value>
               <value>person</value>
               <value>inetorgperson</value>
               <value>organizationalperson</value>
               <value>otherActiveDirectorySpecificClasses</value>
               ...
            </values>
          </extendedProperty>
.
.

25.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

  • Oracle Directory Server Enterprise Edition

  • Oracle Internet Directory

  • Oracle Virtual Directory

  • OpenLDAP

  • Oracle WebLogic Server Embedded LDAP Directory

  • Microsoft ADAM

  • IBM Tivoli

The choice of identity repository dictates the provider class to use with the provider. The provider class must implement the interface specified by the User and Role API framework. Table 25-2 shows the available provider classes:

Table 25-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

Oracle Directory Server Enterprise Edition

oracle.security.idm.providers.iplanet.IPIdentityStoreFactory

Oracle Internet Directory

oracle.security.idm.providers.oid.OIDIdentityStoreFactory

OpenLDAP

oracle.security.idm.providers.openldap.OLdapIdentityStoreFactory

Oracle WebLogic Server Embedded LDAP Directory

oracle.security.idm.providers.wlsldap.WLSLDAPIdentityStoreFactory

Oracle Virtual Directory

oracle.security.idm.providers.ovd.OVDIdentityStoreFactory

Microsoft ADAM

oracle.security.idm.providers.ad.ADIdentityStoreFactory

IBM Tivoli

oracle.security.idm.providers.openldap.OLdapIdentityStoreFactory


25.3.4 Creating the Provider Instance

Once the provider's class name is identified, 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 obtain the store reference, which is the actual handle to the identity store:

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

25.3.5 Properties for Provider Configuration

Configuration is dependent on the identity store 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 the repository runs

  • the user and password to use in accessing the repository

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

This section explains the following provider configuration topics:

25.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 25-3 lists the start-time configuration properties:

Table 25-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 username 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 set at runtime affect all subsequent operations executed by the provider and control the behavior of the IdentityStore instance of the provider.

Runtime properties are configured by specifying the appropriate parameters and values for 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 25-3 lists the run-time configuration properties:

Table 25-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


25.3.5.2 ECID Propagation

By default, ECID support is disabled in the User and Role API.

When initializing the API, set the ST_ECID_ENABLED property to true for ECID support, as illustrated in the following example:

factEnv.put(OVDIdentityStoreFactory.ST_ECID_ENABLED, "true");

Note:

This action is necessary only if either Oracle Internet Directory or Oracle Virtual Directory is used as the back-end identity store. It is not necessary if using other repositories such as Microsoft Active Directory or Novell eDirectory.

25.3.5.3 When to Pass Configuration Values

You can specify configuration data:

25.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

25.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.

25.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.

25.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);

25.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");

25.3.6.5 Configuring 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");

For related information, see Section L.6, "Failure to Connect to the Embedded LDAP Authenticator."

25.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 25.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.

25.3.8 Runtime Configuration

Earlier, in Section 25.3.6, "Configuring the Provider when Creating a Factory Instance" and Section 25.3.7, "Configuring the Provider when Creating a Store Instance", we demonstrated how to perform configuration when creating an instance. 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”);

25.3.9 Programming Considerations

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

25.3.9.1 Provider Portability Considerations

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

  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.getWildCardChar() method. This will fetch the correct wild character based upon the underlying provider. For example, the API will return % for say a database provider and return * for the Oracle Internet Directory 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.

25.3.9.2 Considerations when Using IdentityStore Objects

Keep the following considerations in mind when coding your applications.

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 Delegated Administration Server, 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 the User and Role API. 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.

25.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 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.

25.4 Searching the Repository

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

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

25.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 functions 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. The functions are minimal in that:

  • they accept only string values

  • they do not support regular expressions

The functions raise an exception if multiple entities with the same value exist in the store.

25.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.

25.4.3 Specifying Search Parameters

The SearchParams Object

The SearchParams object contains the following information:

  • Search Filter - this is discussed in Section 25.4.4, "Using Search Filters"

  • 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 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

25.4.4 Using Search Filters

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

25.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 simplify usage, 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();

25.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.

25.4.4.3 Examples of Using Search Filters

Several usage examples are presented below.

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 example 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());
}

25.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());

25.5 User Authentication

For verification purposes, you can use the User and Role API for password-based authentication of users. (As mentioned earlier, the API is not meant for authentication and authorization.)

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”);

25.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:

25.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.

25.6.2 Creating an Identity

Two functions 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.

25.6.3 Modifying an Identity

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.

25.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);

25.7 Examples of User and Role API Usage

This section contains some examples illustrating practical applications of the User and Role API:

25.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();
    }
  }
}

Searching for Users and Searching for Groups

When searching for users, you invoke UserProfile, as in the above example with SimpleSearchFilter. When searching for groups, however, you use RoleProfile instead.

25.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();
    }
  }
}

25.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();
    }
  }
}

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

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

25.8.1 Out-of-the-box Support for SSL

LDAP-based providers for the User and Role API 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 LDAP providers are:

  • Microsoft Active Directory

  • Novell eDirectory

  • Oracle Directory Server Enterprise Edition

  • Oracle Internet Directory

  • OpenLDAP

  • Oracle WebLogic Server Embedded LDAP Directory

25.8.1.1 System Properties

To support SSL you must 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.

25.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");
    

25.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.

25.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");
    

25.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

25.10 Developing Custom User and Role Providers

This section explains how to develop custom providers that security developers can use to manage identities (users and roles). It contains these topics:

25.10.1 SPI Overview

The User and Role API is accompanied by a service provider interface (SPI) that makes it possible to develop custom user/role providers. You can use the service provider interface to develop a custom provider for any identity data repository.

The SPI is bundled as the oracle.security.idm.spi package, which is a set of abstract classes. Custom User and Role providers are created by extending this SPI to fit your requirements.

25.10.2 Types of User and Role Providers

The User and Role API offers functions for both search and Create/Read/Update/Delete (CRUD) operations. A User and Role provider based on read-only functions supports only search operations. A full-featured provider supports both search operations and CRUD operations. In other words, the full-featured provider is a superset of a read-only provider.

As a developer you have the choice of creating either read-only or full-functionality providers depending upon the requirements.

It is reasonable to develop a read-only provider in the following situations:

  • if the underlying identity repository operates in read-only mode

  • if applications consuming the User and Role API do not make any CRUD API calls

For example, it makes sense to develop a read-only provider for use with the SOA identity service.

25.10.3 Developing a Read-Only Provider

This section describes the classes used to implement a provider. Topics include:

25.10.3.1 SPI Classes Requiring Extension

Table 25-5 shows that SPI classes that must be extended to implement a read-only provider:

Note:

All abstract methods must be implemented.

Table 25-5 SPI Classes to Extend for Custom Provider

Class Usage Notes

oracle.security.idm.spi.AbstractIdentityStoreFactory

The extending class must include a default constructor and a constructor accepting a java.util.Hashtable object.

oracle.security.idm.spi.AbstractIdentityStore

 

oracle.security.idm.spi.AbstractRoleManager

 

oracle.security.idm.spi.AbstractUserManager

 

oracle.security.idm.spi.AbstractRoleProfile

 

oracle.security.idm.spi.AbstractUserProfile

 

oracle.security.idm.spi.AbstractSimpleSearchFilter

The constructor of the extending class must call the constructor of the abstract (super) class.

oracle.security.idm.spi.AbstractComplexSearchFilter

The constructor of the extending class must call the constructor of the abstract (super) class.

oracle.security.idm.spi.AbstractSearchResponse

 

Additional requirements and notes for each class are provided below.

25.10.3.2 oracle.security.idm.spi.AbstractIdentityStoreFactory

The class extending this SPI class must have following constructors:

  1. The default constructor (one which has no arguments).

  2. A constructor that accepts a java.util.Hashtable object as an argument. You can use the hash table to accept any configuration properties required by the provider.

    The configuration properties are passed to this constructor during the user and role configuration phase. The properties are key-value pairs passed in the Hashtable argument:

    • The key must be java.lang.String.

    • The value can be java.lang.Object.

It is recommended that the value be of type String. This guarantees that the property can be specified in jps-config.xml, which is a text file.

See Also:

"The User and Role SPI Reference" for details about the methods that need to be implemented in this class. All listed methods must be implemented.

25.10.3.3 oracle.security.idm.spi.AbstractIdentityStore

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Note that:

  • Method getStoreConfiguration() is optional and can throw OperationNotSupportedException.

  • Method getSubjectParser() can return null.

When there are no search results to be returned, all search APIs should throw:

oracle.security.idm.ObjectNotFoundException 

Never return an empty SearchResponse.

25.10.3.4 oracle.security.idm.spi.AbstractRoleManager

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Note that only the following methods need concrete/actual implementations:

  • getGrantedRoles()

  • getOwnedRoles()

  • getManagedRoles()

  • isGranted()

  • isManagedBy()

  • isOwnedBy()

  • isDropRoleSupported() – should always return false

  • isCreateRoleSupported() – should always return false

  • isModifyRoleSupported() – should always return false

The remaining methods must throw the following in their respective implementations:

oracle.security.idm.OperationNotSupportedException 

25.10.3.5 oracle.security.idm.spi.AbstractUserManager

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Only the following methods need concrete/actual implementations:

  • authenticateUser(User, char[])

  • authenticateUser(String, char[])

  • isDropUserSupported() – should always return false

  • isCreateUserSupported() – should always return false

  • isModifyUserSupported() – should always return false

The remaining methods must throw the following in their respective implementations:

oracle.security.idm.OperationNotSupportedException 

25.10.3.6 oracle.security.idm.spi.AbstractRoleProfile

oracle.security.idm.spi.AbstractRoleProfile is an abstract class that can be used to return a detailed role profile.

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Only the following methods need concrete/actual implementations:

  • getDisplayName()

  • getGUID()

  • getName()

  • getUniqueName()

  • getPrincipal()

  • getDescription()

  • getGrantees()

  • getManagers()

  • getOwners()

  • getProperty() - If requested property is not set/valid for corresponding role then null should be returned as value.

  • isApplicationRole() - must always return false

  • isEnterpriseRole() - must always return false

  • isSeeded() - must always return false

  • getRoleProfile() – should return reference to current object.

The remaining methods must throw the following in their respective implementations:

oracle.security.idm.OperationNotSupportedException 

25.10.3.7 oracle.security.idm.spi.AbstractUserProfile

oracle.security.idm.spi.AbstractUserProfile is an abstract class that can be used to return a detailed user profile.

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Only the following methods need concrete/actual implementations:

  • getDisplayName()

  • getGUID()

  • getName()

  • getUniqueName()

  • getPrincipal()

  • getProperty() - If the requested property is not set/valid for corresponding role then a null value must be returned.

  • getProperties() – If the requested property is not set/valid for the corresponding user, then a null value must be returned.

  • getAllUserProperties() – Only the properties set for the corresponding user should be returned.

  • getReportees()

  • getManagementChain()

  • getUserProfile() – must return reference to current object.

These two methods:

  • setProperty()

  • setProperties()

must throw the following in their implementation:

oracle.security.idm.OperationNotSupportedException 

25.10.3.8 oracle.security.idm.spi.AbstractSimpleSearchFilter

oracle.security.idm.spi.AbstractSimpleSearchFilter is an abstract class that can be extended to implement a simple search filter.

The implementing class must have a constructor that calls the constructor of the abstract class:

AbstractSimpleSearchFilter (
   String attrname, int type, Object value)

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Only the following methods need concrete/actual implementations:

  • getNativeRepresentation() – convert filter into the native representation to be used with the underlying identity repository.

  • getWildCardChar() – wild card character, for example "*", to be used in searches. The specific character depends on the underlying identity repository.

25.10.3.9 oracle.security.idm.spi.AbstractComplexSearchFilter

oracle.security.idm.spi.AbstractComplexSearchFilter is an abstract class that can be extended to implement a search filter of any complexity.

The implementing class must have a constructor that calls the constructor of the abstract class:

AbstractComplexSearchFilter (
   oracle.security.idm.SearchFilter[] filters, int oper_type)

"The User and Role SPI Reference" provides details about the methods that need to be implemented in this class. Only the following methods need concrete/actual implementations:

  • getNativeRepresentation() – convert the filter into the native representation to be used with the underlying identity repository.

25.10.3.10 oracle.security.idm.spi.AbstractSearchResponse

The SearchResponse object contains search results being returned from a repository. Each result entry corresponds to one user or role in the underlying identity repository, represented by the corresponding UserProfile/RoleProfile class implementation.

The SearchResponse object must return one or more results. This means that the hasNext() method must return TRUE at least once.

Do not use if there are zero results to return. When no results are to be returned, the corresponding search API should throw the following exception:

oracle.security.idm.ObjectNotFoundException

25.10.4 Developing a Full-Featured Provider

The full-featured provider implements all the functionality supported by a read-only provider, and additionally supports CRUD operations. This requires that the CRUD APIs be implemented in the SPI implementation classes.

In the read-only provider, these APIs were implemented simply by throwing an OperationNotSupportedException (see the class descriptions in Section 25.10.3, "Developing a Read-Only Provider").

For a full-featured provider, this needs to be replaced by concrete/actual implementation of the corresponding CRUD operations.

25.10.5 Development Guidelines

This section provides some guidelines for developing providers.

Mapping of Names

Be aware of the usage of naming constants such as UserProfile.NAME, UNIQUE_NAME, UserProfile.USER_NAME, UserProfile.USER_ID.

  • NAME – name of the user or role in the underlying repository.

  • UNIQUE_NAME – Complete name with which the user or role is represented in the underlying repository.

  • USER_NAME – login ID of the user in the underlying repository.

  • USER_ID – always same as USER_NAME constant mapping.

Depending on the identity repository, these constants might map to the same underlying identity repository attribute or they might map to different attributes. If the underlying repository is an LDAP v3 server, the mappings are as follows:

  • NAME – mapped to naming attribute of user/group entry, for example "cn"

  • UNIQUE_NAME - mapped to "DN" of user/group entry

  • USER_NAME/USER_ID – mapped to login attribute, for example "uid" or "mail"

Thread Safety

The following objects are likely to be shared among multiple threads:

  • IdentityStoreFactory,

  • IdentityStore,

  • UserManager,

  • RoleManager

You should ensure that there are no thread safety-related issues in the corresponding implementation classes of your provider.

25.10.6 Testing and Verification

The User and Role API ships with a test suite to enable you to test the basic operations of providers that you develop.

The test suite can be used to test both read-only and full-featured providers.

Usage

java oracle.security.idm.tests.SPITest propertiesfile

where propertiesfile contains the provider class name and any configuration data for the provider. It also contains information about the tests to be run. You need to edit this file and update it with correct information before running the tests; the file contents are self-explanatory. One such file (ffprovider.properties) is available with the sample provider discussed in Section 25.10.7.1, "About the Sample Provider".

Results

The test will produce the results on-screen. All providers that you develop must pass the "Lookup tests", "Role membership tests" and "Profile tests" in the test suite. Full-featured providers must pass all the tests in the suite including Create/Drop tests.

The log of test results will be output to the file results.out in current working directory.

25.10.7 Example: Implementing an Identity Provider

The distribution includes a sample identity provider that you can use to understand how custom providers are built.

This section describes how to access the sample provider, and explains the steps needed to implement a custom provider. The steps rely on the sample for illustration.

25.10.7.1 About the Sample Provider

The sample provider is bundled in sampleprovider.zip. Unzip the file. It should generate the following structure:

sampleprovider/
      build.xml - ant build file
      ffprovider.properties - properties file required for testing
      jlib - provider jar file location
      out -  location of generated class files
      samples - Folder for samples
      src - provider source code

Run ant help for instructions on building and testing this provider.

The provider relies on an ad-hoc identity repository for fetching identity information and has been tested with Oracle SOA Suite. It is not intended for production use without appropriate testing for your environment.

25.10.7.2 Overview of Implementation

The sample identity provider used in this example is a custom Identity/Authentication provider that uses an RDBMS as the underlying store. It can be used as both an identity provider and an authentication provider.

Note:

The sample provider is intended solely for demonstration purposes, and it is not advisable to use this provider in production without exhaustive testing.

These steps are required to set up the sample provider:

  1. Implement the User and Role APIs to access the database repository serving as the identity store. This involves:

    1. Building the sample provider. Run ant help for instructions.

    2. Creating the identity store schema in the database.

  2. Configure the sample provider as the identity store, as shown in Section 25.10.7.3, "Configure jps-config.xml to use the Sample Identity Provider".

  3. Set up Weblogic Authenticator to use this provider as SQLAuthenticator, as explained in Section 25.10.7.4, "Configure Oracle WebLogic Server".

25.10.7.3 Configure jps-config.xml to use the Sample Identity Provider

Configure jps-config.xml as follows to enable the sample identity provider to be used as the identity store:

  1. Add a new provider in the service providers list:

    <serviceProviders>
          ............
         <serviceProvider type="IDENTITY_STORE" name="custom.provider"  class="oracle.security.jps.internal.idstore.generic.GenericIdentityStoreProvider">
              <description>Custom IdStore Provider</description>
        </serviceProvider>
    </serviceProviders>
    
  2. Add the service instance:

    <serviceInstances>
    ........
        <serviceInstance name="idstore.custom" provider="custom.provider"           location="dumb">
           <description>Custom Identity Store Service Instance</description>
           <property name="idstore.type" value="CUSTOM"/>
           <property name="ADF_IM_FACTORY_CLASS" 
             value="custom_provider_identityStoreFactoryClassName"/>
           <property name="DB_SERVER_NAME" value="db_server_name"/>                     <property name="DB_SERVER_PORT" value="db_port"/>
           <property name="DB_DATABASE_NAME" value="db_service_name"/>
           <property name="ST_SECURITY_PRINCIPAL" value="user_name"/> 
           <property name="ST_SECURITY_CREDENTIALS" value="password"/> 
       </serviceInstance>
    ........
    <serviceInstances>
    

    Note:

    custom_provider_identityStoreFactoryClassName for the sample provider is org.sample.providers.db.DBIdentityStoreFactory
  3. Ensure that the default jpsContext points to the identity store service instance added in Step 2 above:

    <jpsContext name="default">
        <serviceInstanceRef ref="credstore"/>
        <serviceInstanceRef ref="keystore"/>
        <serviceInstanceRef ref="policystore.xml"/>
        <serviceInstanceRef ref="audit"/>
        <serviceInstanceRef ref="idstore.custom"/>
    </jpsContext>
    
  4. Add the path of the custom provider jar to the classpath.

  5. Restart the server.

25.10.7.4 Configure Oracle WebLogic Server

The final task is to configure Oracle WebLogic Server to use SQLAuthenticator. The steps are as follows:

  1. Log in to the Oracle WebLogic Server console. Select Security Realms, then myrealm, then Providers. Click New to add a new provider.

  2. Enter a name for the provider and select SQLAuthenticator as the authenticator type.

  3. On the Providers page, click on the newly created authenticator.

  4. Set the Control Flag to SUFFICIENT. Click Save.

  5. Set the control flag to sufficient for all authenticators in the list.

  6. Click on the "Provider Specific" tab to enter the details for the authenticator server. Enter the DataSource name that was used to create the schema for the provider. Click Save.

  7. Return to the Providers tab and reorder the providers so that SQLAuthenticator is at the top of the list.


The User and Role SPI Reference

This section contains the User and Role SPI reference (Javadoc), describing each abstract class in the SPI with package name oracle.security.idm.spi. The classes are:


oracle.security.idm.spi.AbstractUserProfile

This class represents a detailed user profile and enables you to set or obtain attributes of the user profile.

Constructors

public AbstractUserProfile() 

Methods

public void setPassword(  char[] oldPasswd,         char[] newPasswd) 
public byte[] getUserCertificate() 
public void setUserCertificate( byte[] cert) 
public java.lang.String getEmployeeNumber() 
public void setEmployeeNumber(  String employeeNumber) 
public java.lang.String getBusinessPostalAddr() 
public void setBusinessPostalAddr(      String addr) 
public java.lang.String getBusinessPOBox() 
public void setBusinessPOBox(   String pobox) 
public byte[] getJPEGPhoto() 
public void setJPEGPhoto(       String imgpath) 
public java.lang.String getTimeZone() 
public void setTimeZone(        String zone) 
public java.lang.String getDescription() 
public void setDescription(     String desc) 
public java.lang.String getDepartmentNumber() 
public void setDepartmentNumber(        String departmentnumber) 
public java.lang.String getGivenName() 
public void setGivenName(       String givenname) 
public java.lang.String getBusinessEmail() 
public void setBusinessEmail(   String email) 
public java.lang.String getBusinessPager() 
public void setBusinessPager(   String pager) 
public java.lang.String getOrganization() 
public void setOrganization(    String org) 
public void setName(    String name) 
public java.lang.String getBusinessCity() 
public void setBusinessCity(    String city) 
public java.lang.String getMaidenName() 
public void setMaidenName(      String maidenname) 
public java.lang.String getDepartment() 
public void setDepartment(      String dept) 
public java.lang.String getBusinessFax() 
public void setBusinessFax(     String fax) 
public java.lang.String getUserName() 
public void setUserName(        String uname) 
public java.lang.String getBusinessMobile() 
public void setBusinessMobile(  String mobile) 
public java.lang.String getDateofHire() 
public void setDateofHire(      String hiredate) 
public java.lang.String getTitle() 
public void setTitle(   String title) 
public java.lang.String getNameSuffix() 
public void setNameSuffix(      String suffix) 
public java.lang.String getMiddleName() 
public void setMiddleName(      String middlename) 
public java.lang.String getHomePhone() 
public void setHomePhone(       String homephone) 
public void setDisplayName(     String dispname) 
public java.lang.String getEmployeeType() 
public void setEmployeeType(    String emptype) 
public java.lang.String getLastName() 
public void setLastName(        String lastname) 
public java.lang.String getDateofBirth() 
public void setDateofBirth(     String dob) 
public java.lang.String getManager() 
public void setManager( String manager) 
public java.lang.String getBusinessState() 
public void setBusinessState(   String state) 
public java.lang.String getHomeAddress() 
public void setHomeAddress(     String homeaddr) 
public java.lang.String getBusinessStreet() 
public void setBusinessStreet(  String street) 
public java.lang.String getBusinessPostalCode() 
public void setBusinessPostalCode(      String postalcode) 
public java.lang.String getInitials() 
public void setInitials(        String initials) 
public java.lang.String getUserID() 
public void setUserID(  String userid) 
public java.lang.String getFirstName() 
public void setFirstName(       String firstname) 
public java.lang.String getDefaultGroup() 
public void setDefaultGroup(    String defgroup) 
public java.lang.String getOrganiztionalUnit() 
public void setOrganizationalUnit(      String ouUnit) 
public java.lang.String getWirelessAcctNumber() 
public void setWirelessAcctNumber(      String wirelessacct) 
public java.lang.String getBusinessPhone() 
public void setBusinessPhone(   String phone) 
public java.lang.String getBusinessCountry() 
public void setBusinessCountry( String country) 
public java.lang.String getPreferredLanguage() 
public void setPreferredLanguage(       String language) 
public java.lang.String getUIAccessMode() 
public void setUIAccessMode(    String accessMode) 
public java.lang.Object getPropertyVal( String prop) 
public oracle.security.idm.SearchResponse getReportees( boolean direct) 
public java.util.List getManagementChain(       int max,        String upToManagerName,         String upToTitle) 
public oracle.security.idm.PropertySet getAllUserProperties() 



oracle.security.idm.spi.AbstractUserManager

This class represents a user manager and includes basic authentication methods.

Constructors

public AbstractUserManager() 

Methods

public oracle.security.idm.User authenticateUser(
   String user_id, String authProperty, char[] passwd)
 
public oracle.security.idm.User authenticateUser(
   User user, char[] passwd) 

oracle.security.idm.spi.AbstractUser

This class represents a user.

Constructors

public AbstractUser() 

Methods

None.


oracle.security.idm.spi.AbstractSubjectParser

This abstract class provides a constructor for a subject parser.

Constructors

public AbstractSubjectParser() 

Methods

None


oracle.security.idm.spi.AbstractStoreConfiguration

This abstract class provides a constructor for identity store configuration.

Constructors

public AbstractStoreConfiguration() 

Methods

None


oracle.security.idm.spi. AbstractSimpleSearchFilter

This abstract class represents a simple search filter that can be used to search the identity store. Each simple filter consists of a search attribute, matching operator type, and value. Search results are filtered based on this condition. This class is abstract as its actual underlying representation (provided by method @link #getNativeRepresentation()) is implementation-specific. A service provider can extend this class by setting up a specific implementation of that method.

Constructors

public AbstractSimpleSearchFilter(
   String attrname, int type, Object value) 

Methods

Table 25-6 lists the methods of AbstractSimpleSearchFilter.

Table 25-6 Methods of AbstractSimpleSearchFilter

Method Description
public void setAttribute( String name) 

Set attribute name. .

public void setType(int type) 

Set filter type.

public void setValue(Object value) 

Set attribute value.

public java.lang.String getAttributeName() 

Retrieve attribute name.

public java.lang.Object getValue() 

Retrieve attribute value.

public int getType() 

Retrieve filter type.

public void setNegate() 

Negate the current NOT state of the search filter. Behaves like a toggle switch.

public void negate() 

Negate the current NOT state of the search filter. Behaves like a toggle switch.

public boolean isNegated() 

Return the current NOT state of the search filter. Returns true if the NOT operator is set; false otherwise.





oracle.security.idm.spi.AbstractSearchResponse

This is an abstract class that represents search response results.

Constructors

public AbstractSearchResponse() 

Methods

None.


oracle.security.idm.spi.AbstractRoleProfile

This class represents the detailed profile of a role.

Constructors

public AbstractRoleProfile() 

Methods

public oracle.security.idm.SearchResponse getManagers(
   SearchFilter filter,    boolean direct) 

public oracle.security.idm.SearchResponse getManagers(
   SearchFilter filter) 

public oracle.security.idm.SearchResponse getOwners(
   SearchFilter filter, boolean direct) 

public oracle.security.idm.SearchResponse getOwners(
   SearchFilter filter) 

public void addManager(
   Principal principal) 

public void removeManager(
   Principal principal) 

public void addOwner(
   Principal principal) 

public void removeOwner(
   Principal principal) 

public boolean isOwnedBy(
   Principal principal) 

public boolean isManagedBy(
   Principal principal) 

public void addOwner(
   User user) 

public void removeOwner(
   User user) 

public void setDisplayName(
   String displayName) 

public void setDescription(
   String discription) 

public java.lang.String getDescription() 

public oracle.security.idm.Property getProperty(
   String propName) 

oracle.security.idm.spi.AbstractRoleManager

This class is an abstract representation of a role manager.

Constructors

public AbstractRoleManager() 

Methods

public boolean isOwnedBy(
   Role role, Principal principal) 

public boolean isManagedBy(
   Role role, Principal principal) 

public oracle.security.idm.SearchResponse getOwnedRoles(
   Principal principal, boolean direct) 

public oracle.security.idm.SearchResponse getManagedRoles(
   Principal principal, boolean direct)

oracle.security.idm.spi.AbstractRole

This class provides a constructor for a role.

Constructors

public AbstractRole() 

Methods

None


oracle.security.idm.spi.AbstractIdentityStoreFactory

This class represents an identity store factory.

See Also:

"IdentityStoreFactory" in Table 25-1.

Constructors

public AbstractIdentityStoreFactory() 

Methods

public oracle.security.idm.IdentityStore getIdentityStoreInstance() 

oracle.security.idm.spi.AbstractIdentityStore

This abstract class represents an identity store.

Constructors

public AbstractIdentityStore() 

Methods

public oracle.security.idm.RoleManager getRoleManager() public oracle.security.idm.UserManager getUserManager() public java.util.List getMandatoryUserPropertyNames() public java.util.List getUserPropertySchema() 

oracle.security.idm.spi.AbstractComplexSearchFilter

This class represents a complex search filter. This type of search filter is used to combine multiple SearchFilter instances with a single boolean AND or OR operator. Each of the component search filters can itself be a complex filter, enabling you to form nested search filters with a high degree of complexity.

This class is abstract in that its actual underlying representation, provided by the @link #getNativeRepresentation() method, is implementation-specific.

A service provider can extend this class by creating a specific implementation of this method.

Constructors

public AbstractComplexSearchFilter(       SearchFilter[] filters,   int oper_type) 

Methods

Table 25-7 Methods of Complex Search Filter

Method Description

public void addFilterComponent( SearchFilter filter)

Add the SearchFilter component to this complex filter's list.

public void setNegate()

Negate the current NOT state of the search filter. Behaves like a toggle switch.

public void negate()

Negate the current NOT state of the search filter. Behaves like a toggle switch.

public boolean isNegated()

Return the current NOT state of the search filter. Returns true if the NOT operator is set; false otherwise.

public int getOperatorType()

Logical operator type which binds together the SearchFilter components.