Oracle® Containers for J2EE Security Guide 10g (10.1.3.1.0) Part Number B28957-01 |
|
|
View PDF |
OC4J 10.1.3.x implementations provide a new pluggable identity management API framework for accessing user and role information from disparate identity management repositories. To avoid confusion with the pluggable identity management framework discussed in Chapter 13, which is independent, we will simply refer to the APIs discussed here as the "user and role APIs".
These APIs include functionality to replace the deprecated UserManager
, User
, and Group
classes of the com.evermind.security
package.
This chapter covers the following topics:
Overview of User and Role (Identity Management) API Framework
User and Role API Features to Replace UserManager, User, Group
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 underlying 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. These APIs are not for authentication or authorization functions.
You can use a basic usage model (without OC4J integration) or a usage model with OC4J integration that allows your code to be portable.
The user and role APIs include features to replace functionality of the deprecated com.evermind.security.UserManager
, User
, and Group
classes, as follows:
User and role API features to create, modify, or retrieve users and roles in the identity repository replace UserManager
functionality to create and retrieve users and roles.
User and role API features to retrieve or modify user roles (such as assigning a user to a role) replace User
functionality to retrieve or modify user roles. (Authentication features of the User
class are replaced by DBTableOraDataSourceLoginModule
, discussed in "DBTableOraDataSourceLoginModule".)
User and role API features to retrieve a role replace Group
functionality to retrieve a role. (Features of the Group
class to grant permissions to a role are replaced by functionality of the OracleAS JAAS Provider policy management APIs, discussed in "OracleAS JAAS Provider APIs for Granting or Revoking Permissions".)
The user and role APIs are based on a framework and provider model similar to JNDI.
The framework specifies a generic mechanism for accessing identity information, and consists only of Java interfaces. It does not provide implementation details.
The "providers" (included with OC4J) each implement the framework interfaces, with specific implementation classes for accessing information from particular repositories—for example, to read identity information from Active Directory. Each type of identity repository has a corresponding provider.
The application developer creates code based on the generic framework. Later, during a configuration step, the application is plugged in to the appropriate provider for the desired identity repository. Subsequently, the application can be updated to use a different repository by simply reconfiguring it to use the corresponding provider. No changes are required to the application code.
OC4J comes with providers for Oracle Internet Directory, Active Directory, Sun Java System Directory Server (formerly iPlanet), Novell eDirectory, and OpenLDAP (an open source LDAP directory). Figure 12-1 following depicts the framework with respect to a few particular providers.
Figure 12-1 User and Role API Framework Model
This section summarizes interfaces and classes of the user and role API package, oracle.security.idm
.
This section summarizes interfaces in the oracle.security.idm
package.
There are the following interfaces for identity repositories:
IdentityStore
: An IdentityStore
instance represents a handle to an identity repository. Methods are specified for the following functions:
Get a user manager or role manager.
Search for users, roles, or their profiles.
Get a search filter or the list of searchable attributes for the identity repository.
IdentityStoreFactory
: An IdentityStoreFactory
instance represents the underlying identity repository, and includes a method to get an IdentityStore
instance, taking as input a hashtable consisting of properties specific to the provider that are required in order to create the instance.
There are the following interfaces for user entries in the identity repository:
User
: A User
instance represents a user in the identity store. This is a subinterface of Identity
, and specifies a method to get a user profile. It is also a superinterface of UserProfile
.
UserProfile
: A UserProfile
instance represents detailed information about a user and includes constants for commonly accessed properties such as name, title, employee number, manager, postal address, e-mail address, phone number, fax number, wireless number, and many more. This is a subinterface of User
. It specifies methods to get and set any of these common properties, as well as the more general methods getProperty()
, getProperties()
, setProperty()
, and setProperties()
. The setProperty()
and setProperties()
methods take instances of the oracle.security.idm.ModProperty
class (described below).
UserManager
: A UserManager
instance is used to manage the user population within the repository, including the execution of operations involving users. This includes creating, authenticating, or dropping a user.
There are the following interfaces for roles in the identity repository:
Role
: A Role
instance represents a role in the identity store. This is a subinterface of Identity
, and specifies a method to get a role profile. It is also a superinterface of RoleProfile
.
RoleProfile
: A RoleProfile
instance represents detailed information about a role. This is a subinterface of Role
, and specifies methods to add, remove, or get owners of the role; get all the grantees that are directly or indirectly granted the role; and determine whether this is an application role or an enterprise role.
RoleManager
: A RoleManager
instance is used to manage the role population within the repository, including the execution of operations involving roles. This includes creating a role, dropping a role, granting a role to a specified principal, or revoking a role from a specified principal.
This section summarizes a key class in the oracle.security.idm
package.
IdentityStoreFactoryBuilder
: Use an instance of this class to build an identity store factory. It includes the overloaded getIdentityStoreFactory()
method to get an IdentityStoreFactory
instance.
This section supplies step-by-step instructions and samples for using the basic API framework and OC4J integration features, covering the following topics:
This section describes steps to use the basic API framework. Steps 1 and 2 are primarily related to configuration, determining the provider to be used and its configuration. The code in these two steps would change for a different identity repository and provider. The operations performed on the repository in step 3 are generic in nature. Changing to a different repository would not affect this code.
See Also:
|
Obtain an IdentityStoreFactory
instance. This factory instance will represent the identity repository and is created using a getIdentityStoreFactory()
call on an IdentityStoreFactoryBuilder
instance. This call accepts the name of the provider to be used for connecting to the particular identity repository. It also accepts any configuration information required by the provider.
For example, assume the application must connect to Oracle Internet Directory. The following is the provider name for Oracle Internet Directory:
oracle.security.idm.providers.oid.OIDIdentityStoreFactory
An LDAP provider, such as Oracle Internet Directory, will require configuration information including the LDAP URL, security principal, and credentials. For example:
IdentityStoreFactoryBuilder builder = new IdentityStoreFactoryBuilder(); IdentityStoreFactory oidFactory = null; Hashtable factEnv = new Hashtable(); // creating the factory instance // set the configuration information factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_PRINCIPAL, "cn=orcladmin"); factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_CREDENTIALS, "welcome1"); factEnv.put(OIDIdentityStoreFactory.ST_LDAP_URL, "ldap://ilinabc10.us.oracle.com:3060/"); factEnv.put(OIDIdentityStoreFactory.ST_LOGGING,"false"); factEnv.put(OIDIdentityStoreFactory.ST_LOG_LEVEL, java.util.logging.Level.ALL); oidFactory = builder.getIdentityStoreFactory( "oracle.security.idm.providers.oid.OIDIdentityStoreFactory", factEnv);
Obtain an IdentityStore
instance to carry out operations on the repository. This is obtained using a getIdentityStoreInstance()
call on the IdentityStoreFactory
instance. This call can accept configuration information required for creation of the identity store instance. For example, for Oracle Internet Directory you must specify the subscriber or realm name upon which the operations are to be performed, as shown in the following sample:
Hashtable storeEnv = new Hashtable(); // creating the store instance storeEnv.put(OIDIdentityStoreFactory.ST_SUBSCRIBER_NAME, "dc=us,dc=oracle,dc=com"); oidStore = oidFactory.getIdentityStoreInstance(storeEnv);
Using the IdentityStore
instance, perform any operations of interest on the identity repository, such as searching, updating, creating, or deleting entries. For example, the following code will search for all users whose name begins with "john
":
// search filter for users whose name begins with "john" SimpleSearchFilter sf = oidStore.getSimpleSearchFilter( UserProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, null); // Add the wildcard character sf.setValue("john"+sf.getWildCardChar()); // generate the search parameter instance and set the search filter SearchParameters params = new SearchParameters(); params.setFilter(sf); // Searching for users // search on the IdentityStore instance SearchResponse resp = oidStore.searchUsers(params); System.out.println("Searched users are:"); // Iterate on the search results while (resp.hasNext() { User usr = (User) resp.next(); System.out.println("Name: "+usr.getName()); }
As explained in the preceding section, "Step by Step: Basic Usage Model", the configuration-related code is tied to the identity repository and its associated provider, and thus is subject to change whenever the application changes to use a different identity repository.
To make your code portable, you can use the OC4J integration feature of the API framework. This feature uses security provider information present in the OC4J login module of the application, so that the application itself need not specify any configuration for the repository and provider. The application code becomes generic, and the application can change to a different identity source simply by changing the security provider information in the login module configuration.
Important: The OC4J integration feature is a security-sensitive operation and requires the application to have necessary permissions. See the next section, "Permission Requirements for the OC4J Integration Feature", forjava2.policy requirements. |
Use the OC4J integration feature as follows:
The user and role framework requires a path to a user/role properties file (typically called userrole.properties
by convention), specified as a Java system property, as follows:
System.setProperty("oracle.userrole.properties", "/home/jdoe/userrole.properties");
The properties file contains settings required by the framework to access OC4J login module information. The properties file format is shown in "User and Role Properties File".
Creating the IdentityStoreFactory
instance is a privileged operation and must be carried out within an AccessController.doPrivileged()
block, as follows:
IdentityStoreFactory factory = null; try { factory = (IdentityStoreFactory) AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws IMException { IdentityStoreFactoryBuilder builder = new IdentityStoreFactoryBuilder(); return builder.getIdentityStoreFactory(); } }); }catch (PrivilegedActionException e) { e.getException().printStackTrace(out); } catch (Exception e) { e.printStackTrace(out); }
Obtaining the IdentityStore
instance is convenient:
IdentityStore store = factory.getIdentityStoreInstance();
Perform operations on the identity store as shown in the previous section,"Step by Step: Basic Usage Model".
Because the OC4J integration feature is a security-sensitive operation, the application code must have certain permissions. In particular, the getIdentityStoreFactory()
method of the IdentityStoreFactoryBuilder
class makes API calls that require certain permissions.
In the OC4J java2.policy
file, grant the following permissions to the application codebase:
grant codebase "file:${oracle.home}/application_code_base"
{
permission oracle.security.jazn.JAZNPermission "*";
};
Be aware that in order to use Java 2 policies, you must specifically enable a security manager, as discussed in "Specifying a Java 2 Security Manager and Policy File".
To use the OC4J integration feature, the API framework must know the path to the user/role properties file, expressed as a Java system property. The properties file contains the properties required by the framework to access required OC4J login module information. The file can have any name you choose, but must have the following file format:
# This line should not be changed. configurationsourceclass=oracle.security.idm.util.OC4JConfigurationSource # This property specifies the JMX Mbean URL for the OC4J container in which the # application is deployed. # For OPMN-managed OC4J, uncomment the URL that follows; comment out all others. # format: service:jmx:rmi:///opmn://opmnhost[:opmnport]/oc4jInstance jmxserviceurl=service:jmx:rmi:///opmn://localhost:6008/home # For standalone OC4J, uncomment the URL that follows; comment out all others. # format: service:jmx:rmi:///opmn://oc4jhost:rmiport/oc4jContextRoot #jmxserviceurl=service:jmx:rmi://localhost:23791/oc4j/
See Also:
|
This section supplies the complete example corresponding to the steps discussed in "Step by Step: Basic Usage Model".
import oracle.security.idm.*; import oracle.security.idm.providers.oid.*; import java.util.*; import java.io.*; public class BasicSampleOID { 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, "cn=user,...."); factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_CREDENTIALS, "password"); factEnv.put(OIDIdentityStoreFactory.ST_LDAP_URL, "ldap://johnmc.us.oracle.com:3060/"); factEnv.put(OIDIdentityStoreFactory.ST_LOGGING,"false"); factEnv.put(OIDIdentityStoreFactory.ST_LOG_LEVEL, java.util.logging.Level.ALL); oidFactory = builder.getIdentityStoreFactory( "oracle.security.idm.providers.oid.OIDIdentityStoreFactory", factEnv); // creating the store instance storeEnv.put(OIDIdentityStoreFactory.ST_SUBSCRIBER_NAME, "dc=us,dc=oracle,dc=com"); oidStore = oidFactory.getIdentityStoreInstance(storeEnv); // search filter (cn=a*) SimpleSearchFilter sf = oidStore.getSimpleSearchFilter( UserProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, null); sf.setValue("john"+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()) { User usr = (User) resp.next(); System.out.println("Name: "+usr.getName()); } }catch (IMException e) { e.printStackTrace(); } } }
This section supplies the complete example corresponding to the steps discussed in "Step by Step: OC4J Integration Usage Model".
import java.io.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; // Packages for Servlets import javax.servlet.*; import javax.servlet.http.*; import oracle.security.idm.*; public class UserSearch extends HttpServlet { private String USERROLEPROPFILE = "UserRolePropFile"; IdentityStore store = null; public void init(ServletConfig config) throws ServletException { super.init(config); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = ""; String searchType = "usersearch"; try { name = request.getParameter("name"); searchType = request.getParameter("searchtype"); } catch (Exception e) { e.printStackTrace(); } String filter = (name != null)? name: ""; response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>UserSearch</title></head>"); out.println("<body>"); out.println( "<label for=\"fld\"><b>User name begining with</b></label>"); out.println( "<form action=\"usersearch\">"+ "<P><select name=\"searchtype\" size=\"1\">"+ "<option value=\"usersearch\">Search Users</option>"+ "<option value=\"rolesearch\">Search Roles</option>"+ "<option value=\"membershipsearch\">Search Membership details"+ "<option value=\"membersearch\">Searchs Members of role"+ "</option></select></P>"+ "<input name=\"name\" id=\"fld\" value=\"" + filter + "\"type=\"text\"/><input type=\"SUBMIT\" value=\"Search\"/></form>"); out.println("<br><br><br>"); // Create the IdentityStore instance required for searching configureAPI(out); // Carries out the actual search using IdentityStore instance obtained // above doSearch(out, searchType, name); out.println("</body></html>"); out.close(); } public void configureAPI(PrintWriter out) { IdentityStoreFactoryBuilder builder = new IdentityStoreFactoryBuilder(); // Set the following system property to specify the location of // "userrole.properties" file. This file is used by user-role apis for // reading the configuration from OC4J // Get the file location from the servlet init parameters System.setProperty("oracle.userrole.properties", getServletConfig().getInitParameter(USERROLEPROPFILE)); IdentityStoreFactory factory = null; try { factory = (IdentityStoreFactory) AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws IMException { IdentityStoreFactoryBuilder builder = new IdentityStoreFactoryBuilder(); return builder.getIdentityStoreFactory(); } }); store = factory.getIdentityStoreInstance(); }catch (PrivilegedActionException e) { e.getException().printStackTrace(out); } catch (Exception e) { e.printStackTrace(out); } } public void doSearch(PrintWriter out, String searchType, String name) { System.out.println("Inside doSearch"); if (name == null) return; if (searchType.equals("usersearch")) searchUsers(out, name); else if (searchType.equals("rolesearch")) searchRoles(out, name); else if (searchType.equals("membershipsearch")) searchMembership(out, name); else if (searchType.equals("membersearch")) searchMembers(out, name); } public void searchMembers(PrintWriter out, String name) { System.out.println("Inside searchMembers"); if (name == null) return; out.println("Results: <br>"); try { Role rle = store.searchRole(IdentityStore.SEARCH_BY_NAME, name); out.println("Members of role \""+rle.getName()+ "\" are:<br>"); SearchResponse resp = rle.getRoleProfile().getGrantees(null, false); while (resp.hasNext()) { Identity idy = resp.next(); out.println("Unique name: " + idy.getUniqueName() + "<br>"); } } catch (IMException e) { e.printStackTrace(out); } } public void searchMembership(PrintWriter out, String name) { System.out.println("Inside searchMembership"); if (name == null) return; out.println("Results: <br>"); try { User usr = store.searchUser(name); out.println("Membership details for user \""+usr.getName()+ "\" are:<br>"); SearchResponse resp = store.getRoleManager().getGrantedRoles(usr.getPrincipal(), false); while (resp.hasNext()) { Identity idy = resp.next(); out.println("Unique name: " + idy.getUniqueName() + "<br>"); } } catch (IMException e) { e.printStackTrace(out); } } public void searchRoles(PrintWriter out, String name) { System.out.println("Inside searchRoles"); if (name == null) return; out.println("Results: <br>"); try { SimpleSearchFilter sf = store.getSimpleSearchFilter( RoleProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, null); sf.setValue(name + sf.getWildCardChar()); SearchParameters params = new SearchParameters(); params.setFilter(sf); // Searching for users SearchResponse resp = store.searchRoles(0, params); out.println("Searched roles are:<br>"); while (resp.hasNext()) { Identity idy = resp.next(); out.println("Unique name: " + idy.getUniqueName() + "<br>"); } } catch (IMException e) { e.printStackTrace(out); } } public void searchUsers(PrintWriter out, String name) { System.out.println("Inside searchUsers"); if (name == null) return; out.println("Results: <br>"); try { SimpleSearchFilter sf = store.getSimpleSearchFilter( UserProfile.NAME, SimpleSearchFilter.TYPE_EQUAL, null); sf.setValue(name + sf.getWildCardChar()); SearchParameters params = new SearchParameters(); params.setFilter(sf); // Searching for users SearchResponse resp = store.searchUsers(params); out.println("Searched users are:<br>"); while (resp.hasNext()) { Identity idy = resp.next(); out.println("Unique name: " + idy.getUniqueName() + "<br>"); } } catch (IMException e) { e.printStackTrace(out); } } }