Skip Headers
Oracle® Containers for J2EE Security Guide
10g Release 3 (10.1.3)
B14429-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

8 Login Modules

This chapter discusses how to configure the default login module, or how to implement, install, and configure a custom login module. The following topics are covered:


Notes:

  • Note the setting provider="XML" is used for custom providers (custom login modules) as well as for the file-based provider.

  • Be aware that when you use a custom login module, role comparisons for authorization are not case-sensitive unless you add the following property setting to the <jazn> element in orion-application.xml:

    <property name="role.compare.ignorecase" value="false" />
    
    
  • Because the JAAS specification does not cover user management, when you configure your application to use a custom login module, the use of the UserManager API within your application is not supported. The J2EE API, however, will continue to function within your application.

  • OC4J provides a login module, LDAPLoginModule, for use with external LDAP providers, as noted in "External LDAP Provider Settings in system-jazn-data.xml".

  • OC4J provides a login module, CoreIDLoginModule, for use with Oracle COREid Access and Identity, as discussed in "Configure the COREid JAAS Login Module".


Configuring RealmLoginModule

The RealmLoginModule class is the default login module, for use with the file-based provider or Oracle Identity Management, and is configured through the system-jazn-data.xml file. The RealmLoginModule class authenticates user login credentials before the user can access J2EE applications. Authentication is performed using OC4J container-based authentication (HTTP basic, form-based, and so on).

You can configure RealmLoginModule by using Application Server Control or the OracleAS JAAS Provider Admintool.

The <login-module> element, under the <jazn-loginconfig> element in system-jazn-data.xml, supports the options shown in Table 8-1 for RealmLoginModule (through <name> and <value> subelements of an <option> element).


Notes:

  • You do not need to enable the RealmLoginModule class if your application uses OracleAS Single Sign-On authentication.

  • The use of RealmLoginModule as a custom login module—in other words, as a custom security provider—is not supported. However, as already noted, it is used by default as the login module when an application is configured to use the file-based provider (using system-jazn-data.xml or jazn-data.xml as the user repository) or Oracle Identity Management (using Oracle Internet Directory as the user repository).


Table 8-1 RealmLoginModule Options

Name Meaning Default

debug

If set to true, debugging messages are printed.

false

addRoles

If set to true, the RealmLoginModule adds all directly granted roles of the user to the subject after successful authentication.

true

addAllRoles

If set to true, the RealmLoginModule adds all directly or indirectly granted roles of the user to the subject after successful authentication.

true

storePrivateCredentials

If set to true, the RealmLoginModule adds all private credentials (for example, password credentials) to the subject after successful authentication.

false

supportCSIv2

If set to true, the RealmLoginModule supports CSIv2.

See Also: Chapter 15, "Common Secure Interoperability Protocol" for details.

false

supportNullPassword

(Oracle Identity Management only) If set to true, the RealmLoginModule does not check to see if the supplied password is null or empty. If set to false, authentication fails if the supplied password is null or empty.

false


Here is sample configuration of RealmLoginModule, in system-jazn-data.xml. (We recommend that you not alter RealmLoginModule configuration manually; this example is just for illustrative purposes.)

<jazn-loginconfig>
   <application>
      <name>oracle.security.jazn.tools.Admintool</name>
      <login-modules>
         <login-module>
            <class>oracle.security.jazn.realm.RealmLoginModule</class>
            <control-flag>required</control-flag>
            <options>
               <option>
                  <name>debug</name>
                  <value>false</value>
               </option>
               <option>
                  <name>addAllRoles</name>
                  <value>true</value>
               </option>
            </options>
         </login-module>
      </login-modules>
   </application>
   <application>
      <name>oracle.security.jazn.oc4j.JAZNUserManager</name>
      <login-modules>
         <login-module>
            <class>oracle.security.jazn.realm.RealmLoginModule</class>
            <control-flag>required</control-flag>
            <options>
               <option>
                  <name>addAllRoles</name>
                  <value>true</value>
               </option>
            </options>
         </login-module>
      </login-modules>
   </application>
</jazn-loginconfig>

Introducing Custom JAAS Login Modules

Because OC4J support for JAAS fully complies with the JAAS 1.0 specification, users can plug in any JAAS-compliant LoginModule implementation, if desired. (OC4J includes the RealmLoginModule class as its default login module implementation. This class combines J2EE security constraints with either the file-based provider or Oracle Identity Management.)

A custom login module may be desirable, for example, when users and roles are defined in an external repository. When you create a custom login module, consider the following preliminary questions:

When you associate a custom login module with an application, the subject and the principals it contains are used as the sole basis for all authorization tasks, including evaluating J2EE security constraints. To ensure that all relevant principals are considered during authorization, the login module must add the relevant principals, including all roles that the authenticated user participates in, to the subject during the commit phase of the authentication process. (The role.mapping.dynamic property, discussed in "Settings in <jazn> for Login Modules", is related to subject-based authorization.)

The custom login module framework supports the J2EE declarative security model. This means that subject-based authorization enforces the J2EE security constraints declared in application deployment descriptors (web.xml and ejb-jar.xml, for example).

Custom login modules are configured through the OC4J system-jazn-data.xml file, which can be updated automatically through use of tools such as Application Server Control Console and OracleAS JAAS Provider Admintool.


See Also:


Packaging and Deploying Login Modules

If you are using one or more of the default login modules provided with the J2SE (such as com.sun.security.auth.module.Krb5LoginModule), then no additional configuration is needed. The OracleAS JAAS Provider can locate the default login modules.

If you are deploying your application with one or more custom login modules, then you must deploy the login modules and configure the OracleAS JAAS Provider properly so that the module can be found at runtime. The following sections discuss ways to accomplish this:

The remainder of this section discusses these options in greater detail.

Deploying Login Modules within the J2EE Application

If your login modules are used by only a single J2EE application, then you can simply package the login modules as part of your application by including the login module JAR file in the application EAR file.

The login modules must be configured through <jazn-loginconfig> settings, in one of two places:

Using the Application Server Control Console, you can configure custom login modules as you deploy an application, or later if you change the security provider to custom. This results in system-jazn-data.xml being updated automatically.

Administering custom login modules through the OracleAS JAAS Provider Admintool will also update system-jazn-data.xml settings for you.


Note:

If a different application needs the same login module, you must repackage the login module and any relevant classes with the new application.

Deploying Login Modules as Optional Packages

If you deploy your login modules as an optional package (formerly known as a "standard extension"), the OracleAS JAAS Provider will be able to find them. No additional configuration is necessary. Deploying login modules as an optional package allows multiple applications to share them.

There are two ways to use the optional package mechanism:

  • Use the login module classes as an installed optional package. Place the login module JAR file in jre/lib/ext directory. Classes in JAR files in this directory can be used by applications without having to be included in the classpath.

  • Use the login module classes as a download optional package. Specify the login module JAR file in the Class-Path header field in the manifest of other JAR files, as desired. In this way, classes in the login module JAR file can be used by classes in the other JAR files that reference it.

The login modules must also be configured in system-jazn-data.xml, as discussed in "Login Module Settings in system-jazn-data.xml".


See Also:


Using Login Modules as OC4J Shared Libraries

The OracleAS JAAS Provider is integrated with the OC4J class loading architecture. Because of this, you can make login modules available to applications by loading them as OC4J shared libraries. There are two main steps to this (considering functionality of the Application Server Control Console in particular):

  1. Load the library as an OC4J shared library. From the Application Server Control Console Administration tab for the OC4J instance, use the Shared Libraries task.

    This results in configuration such as the following in the OC4J server.xml file:

    <application-server ... >
       ...
       <shared-library name="mylib.lib" version="1.0" library-compatible="true">
          <code-source path="../mypath" /> 
       </shared-library>
       ...
    </application-server>
    
    
  2. Import the library into your application. In deploying an application through Application Server Control, when you reach the Deploy: Deployment Settings page (as discussed in "Deploying an Application through Application Server Control"), you have the opportunity to import shared libraries.

    This results in configuration such as the following in your application orion-application.xml file:

    <orion-application ... >
       ...
       <imported-shared-libraries>
          <import-shared-library name="mylib.lib" /> 
          ...
       </imported-shared-libraries>
       ...
    </orion-application>
    

Note:

The <library> element and ORACLE_HOME/j2ee/home/applib location are still supported for OC4J shared libraries, but are discouraged.


See Also:


Configuring the Custom Security Provider in Application Server Control

This section discusses the following administration tasks for login modules using the Application Server Control Console:


Note:

Procedures discussed throughout this section assume you are logged in to Application Server Control as a user with required administrative permissions (as oc4jadmin, for example).

Specifying and Configuring a Custom Security Provider during Deployment

When you plan to use the custom security provider and you deploy an application through Application Server Control, you have the opportunity to configure your custom login modules during deployment.

From the Deploy: Deployment Settings page (see "Deploying an Application through Application Server Control" for how to get to this page):

  1. Go to the Select Security Provider task.

  2. In the resulting Deployment Settings: Select Security Provider page, choose Custom from the Security Provider dropdown list.

  3. Under "Configuration of Custom Security Provider" (which appears after you choose Custom), you can edit or delete any custom login module that is found with your application, or add a new custom login module.

  4. Still in the Deployment Settings: Select Security Provider page, choose OK to finish the security provider selection.

  5. Back in the Deploy: Deployment Settings page, choose Deploy to complete the deployment, or choose another task, as desired. The list of tasks is noted in "Deploying an Application through Application Server Control".

Deploying with a custom login module results in the following automatic settings in the orion-application.xml file:

<jazn provider="XML">
   <property name="role.mapping.dynamic" value="true" />
   <property name="custom.loginmodule.provider" value="true" />
</jazn>

Notes:

  • Grants for custom login modules, which are stored in system-jazn-data.xml, cannot be configured through Application Server Control Console.

  • Custom login modules, as well as the file-based provider, use a setting of provider="XML".

  • Custom login module configuration settings are reflected under the <jazn-loginconfig> element in the system-jazn-data.xml file, as shown in "Login Module Settings in system-jazn-data.xml"

  • The properties role.mapping.dynamic and custom.loginmodule.provider must be set to true for any application that uses custom login modules.



See Also:


Editing a Custom Login Module Configuration during Deployment

To edit a custom login module while deploying an application using the Custom Security Provider, take the following steps, starting under "Configuration of Custom Security Provider" in the Deployment Settings: Select Security Provider page (see "Specifying and Configuring a Custom Security Provider during Deployment" for how to get to this point):

  1. Choose the Edit task for the appropriate login module in the list of login module classes.

  2. In the Deployment Settings: Select Security Provider: Edit Login Module page:

    • Specify a value for the login module control flag (from the dropdown list): Required, Requisite, Optional, or Sufficient. Table 8-2 describes these settings.

    • As desired, choose Add Another Row to create properties.

    • As desired, edit the name or value of any property in the Properties list.

    • As desired, use the Delete task for a property to remove that property.

    • Choose Continue to go back to the Deployment Settings: Select Security Provider page to continue the deployment steps in "Specifying and Configuring a Custom Security Provider during Deployment".

Table 8-2 Login Module Control Flags

Flag Meaning

Required

The login module must succeed. Whether or not it succeeds, authentication proceeds down the login module list.

Requisite

The login module must succeed. If it succeeds, authentication continues down the login module list. If it fails, control immediately returns to the application (authentication does not continue down the login module list).

Sufficient

The login module is not required to succeed. If it succeeds, control immediately returns to the application and authentication does not proceed down the login module list. If it fails, authentication continues down the login module list.

Optional

The login module is not required to succeed. Whether or not it succeeds, authentication proceeds down the login module list.


Adding a Custom Login Module during Deployment

To add a custom login module while deploying an application using the Custom Security Provider, take the following steps, starting under "Configuration of Custom Security Provider" in the Deployment Settings: Select Security Provider page (see "Specifying and Configuring a Custom Security Provider during Deployment" for how to get to this point):

  1. Choose Add Login Module.

  2. In the Deployment Settings: Select Security Provider: Add Login Module page:

    • Specify your login module package and class name.

    • Specify a value for the login module control flag (from the dropdown list): Required, Requisite, Optional, or Sufficient. See the preceding section, "Editing a Custom Login Module Configuration during Deployment", for information about these settings.

    • As desired, choose Add Another Row to create properties.

    • As desired, edit the name or value of any property in the Properties list.

    • As desired, use the Delete task for a property to remove that property.

    • Choose Continue to go back to the Deployment Settings: Select Security Provider page to continue the deployment steps in "Specifying and Configuring a Custom Security Provider during Deployment".

Changing to a Custom Security Provider after Deployment

You can select a security provider for your application at deployment time, as described above. You can also change to a different security provider after deployment. You can change to a custom security provider as follows:

  1. Go to the Security Provider page for your application, as described in "Navigating to the Security Provider Page for Your Application".

  2. In the Security Provider page, choose "Change Security Provider".

  3. In the Change Security Provider page, select "Custom Security Provider" from the dropdown.

  4. Under "Login Modules" (which appears after you select Custom Security Provider in the dropdown), specify the first login module to be used, as follows. Later you can go back to the Security Provider to add more login modules, as described in the next section, "Adding a Login Module to the Custom Security Provider".

    • Specify your login module package and class name.

    • Specify a value for the login module control flag (from the dropdown list)—Required, Requisite, Optional, or Sufficient. See "Editing a Custom Login Module Configuration during Deployment" for information about these settings.

    • As desired, choose Add Another Row to create properties.

    • As desired, edit the name or value of any property in the Properties list.

    • As desired, use the Delete task for a property to remove that property.

    • Choose OK to finish the change.

This takes you back to the Security Provider page, where you can examine the settings.

Adding a Login Module to the Custom Security Provider

Once you have established a custom security provider, either during or after deployment, you can add custom login modules as follows:

  1. Go to the Security Provider page for your application, as described in "Navigating to the Security Provider Page for Your Application".

  2. In the Security Provider page, under "Login Modules", choose Create.

  3. In the Add Login Module page:

    • Specify your login module package and class name.

    • Specify a value for the login module control flag (from the dropdown list): Required, Requisite, Optional, or Sufficient. See "Editing a Custom Login Module Configuration during Deployment" for information about these settings.

    • As desired, choose Add Another Row to create properties.

    • As desired, edit the name or value of any property in the Properties list.

    • As desired, use the Delete task for a property to remove that property.

    • Choose OK to finish the change.

This takes you back to the Security Provider page, where you can examine the settings.

Updating a Login Module in the Custom Security Provider

Once you have established a custom security provider, either during or after deployment, you can update custom login modules as follows:

  1. Go to the Security Provider page for your application, as described in "Navigating to the Security Provider Page for Your Application".

  2. In the Security Provider page, in the list of login module classes, choose the Edit task for the login module you want to update.

  3. In the Edit Login Module page:

    • As desired, update the value for the login module control flag (from the dropdown list): Required, Requisite, Optional, or Sufficient. See "Editing a Custom Login Module Configuration during Deployment" for information about these settings.

    • As desired, choose Add Another Row to create properties.

    • As desired, edit the name or value of any property in the Properties list.

    • As desired, use the Delete task for a property to remove that property.

    • Choose Apply to finish the change.

This leaves you in the Edit Login Module page. You can use the breadcrumbs at the top of the page to go back to the Security Provider page.

Deleting a Login Module in the Custom Security Provider

Once you have established a custom security provider, either during or after deployment, you can delete custom login modules as follows:

  1. Go to the Security Provider page for your application, as described in "Navigating to the Security Provider Page for Your Application".

  2. In the Security Provider page, in the list of login module classes, choose the Delete task for the login module you want to delete.

  3. Choose Yes in the Confirmation page.

This takes you back to the Security Provider page, where you can see that the login module was deleted.

Configuring Login Modules through the Admintool

Although Application Server Control is the preferred and recommended tool for adding and configuring custom login modules, it is also possible to use the OracleAS JAAS Provider Admintool. The following information is presented for reference:

You can also execute these commands from the Admintool shell.

Also note that to access an EJB using a custom login module, you must grant "login" permission to the user (JDOE_ENDUSER, for example). To grant login permission to the user through the Admintool:

% java -jar jazn.jar -grantperm login -user JDOE_ENDUSER com.evermind.server.rmi.RMIPermission

Important:

Restart OC4J for changes to take effect.

Login Module Configuration in OC4J Configuration Files

This section discusses files that contain configuration for custom login modules:

Login Module Settings in system-jazn-data.xml

The system-jazn-data.xml file is the repository for login module configuration.

Note that settings in system-jazn-data.xml are updated automatically when you administer login modules through Application Server Control or the OracleAS JAAS Provider Admintool.


Note:

Where there are multiple OC4J instances, login module configuration is added to the instance-specific system-jazn-data.xml file, not ORACLE_HOME/j2ee/home/system-jazn-data.xml.

The <jazn-loginconfig> element contains information that associates applications with login modules.

If this information is in the orion-application.xml file during deployment, as discussed in "Settings in <jazn-loginconfig> in orion-application.xml", the system-jazn-data.xml file will be updated accordingly.

Example 8-1 Example jazn-loginconfig element

<jazn-loginconfig>
  <application>
    <name>sampleLM</name>
    <login-modules>
      <login-module>
        <class>oracle.security.jazn.samples.SampleLoginModule</class>
        <control-flag>required</control-flag>
        <options>
          <option>
            <name>debug</name>
            <value>true</value>
          </option>
        </options>
      </login-module>
    </login-modules>
  </application>
</jazn-loginconfig> 

This fragment associates the application sampleLM with the login module sample.SampleLoginModule.


Note:

Do not remove login configuration information for RealmLoginModule from the system-jazn-data.xml file.

Login Modules Settings in orion-application.xml

This section discusses particular settings for login modules in the OC4J application-level descriptor orion-application.xml. The following topics are covered:


Note:

This section discusses only elements relevant to security. For a full discussion of this file, see the Oracle Containers for J2EE Developer's Guide.

Settings in <jazn-loginconfig> in orion-application.xml

Settings in the <jazn-loginconfig> element in system-jazn-data.xml were documented earlier, in "Login Module Settings in system-jazn-data.xml". You can add this element to orion-application.xml for deployment, and the settings will be written to the system-jazn-data.xml file automatically.

In addition, when you undeploy the application, the <jazn-loginconfig> settings will be removed from system-jazn-data.xml automatically.

Settings in <jazn> for Login Modules

The following <jazn> properties are specific to login module configuration:

  • role.mapping.dynamic

    This property, when set to true, instructs the OracleAS JAAS Provider to base authorization checks on the authenticated subject instead of basing checks on the users and roles defined in system-jazn-data.xml or the application-specific jazn-data.xml file.

    A LoginModule instance must ensure that the appropriate principals (users or roles) are associated with the Subject instance during the commit phase of the authentication process, in order for the principals to be taken into consideration during the authorization process. This association of principals to the subject is typically implemented using the standard JAAS API.

  • custom.loginmodule.provider

    This property, when set to true, instructs Application Server Control that the security provider is the custom provider. Without this setting, because the custom security provider uses the setting provider="XML", Application Server Control would mistakenly report that the security provider is the file-based provider (although custom login modules you provide in your EAR file would still work).

These properties are automatically set to "true" in orion-application.xml, as shown in the following example, when you have a <jazn-loginconfig> element in orion-application.xml.

<jazn provider="XML" ... >
   <property name="role.mapping.dynamic" value="true" />
   <property name="custom.loginmodule.provider" value="true" />
</jazn>

Settings in <namespace-access> for Login Modules

To access an EJB using a custom login module, you must also grant namespace access to the user in orion-application.xml, as in the following example for JDOE_ENDUSER:

<namespace-access> 
  <read-access> 
    <namespace-resource root="">
      <security-role-mapping>
        <user name="JDOE_ENDUSER" />
      </security-role-mapping> 
    </namespace-resource>
  </read-access> 
</namespace-access>

Configuring oc4j-ra.xml for Login Modules (J2EE Connector Architecture)

When you configure resource adapters, each <connector-factory> element in the oc4j-ra.xml file can specify a different JAAS login module, as in the following example. This also shows <config-property> setup to connect to a database through Oracle JDBC.

  <connector-factory connector-name="myBlackbox" location="eis/myEIS1"> 
     <config-property name="connectionURL"
                      value="jdbc:oracle:thin:@localhost:5521/myservice" />
     <security-config use="jaas-module">
        <jaas-module>
           <jaas-application-name>JAASModuleDemo</jaas-application-name>
        </jaas-module>
     </security-config>
  </connector-factory>

Simple Login Module J2EE Integration

Developing a simple login module follows the standard development, packaging, and deployment cycle. The following sections discuss each step in the cycle.

Development of Simple Login Module

Develop a JAAS-compliant LoginModule implementation according to the JAAS service provider interface.


See Also:


Packaging of Simple Login Module

Package your login module classes in one of the ways described in "Packaging and Deploying Login Modules".

Deployment of Simple Login Module

Configuration for login modules is specified in the system-jazn-data.xml file:

  1. Register your application login module. This occurs automatically when you deploy an application through Application Server Control.

    The following fragment from system-jazn-data.xml shows the registration of the login module oracle.security.jazn.samples.SampleLoginModule, to be used for authenticating users accessing the sampleLM application.

      <jazn-loginconfig>
         <application>
             <name>sampleLM</name>
             <login-modules>
                <login-module>
                   <class>oracle.security.jazn.samples.SampleLoginModule</class>
                   <control-flag>required</control-flag>
                   <options>
                      <option>
                         <name>debug</name>
                         <value>true</value>
                      </option>
                   </options>
                </login-module>
             </login-modules>
          </application>
          ...
       </jazn-loginconfig>
    
    
  2. Optional. Grant relevant permissions to your users and roles. You can use the OracleAS JAAS Provider Admintool to accomplish this. For example, if the principal developer needs EJB access, then you must grant the permission com.evermind.server.rmi.RMIPermission to developer.

    This results in configuration such as the following in system-jazn-data.xml:

    <jazn-policy>
      <grant>
        <grantee>
          <principals>
            <principal>
              <class>oracle.security.jazn.samples.SampleUser</class>
              <name>developer</name>
            </principal>
          </principals>
        </grantee>
        <permissions>
          <permission>
            <class>com.evermind.server.rmi.RMIPermission</class>
            <name>login</name>
          </permission>
        </permissions>
      </grant>
      ...
    </jazn-policy>
    
    

To deploy your login module, ensure the following settings are in the orion-application.xml file:

  1. The <jazn> properties role.mapping.dynamic and custom.loginmodule.provider (described in "Settings in <jazn> for Login Modules") are set to "true":

    <jazn provider="XML" ... >
       <property name="role.mapping.dynamic" value="true" />
       <property name="custom.loginmodule.provider" value="true" />
    </jazn>
    
    

    This occurs automatically if there is a <jazn-loginconfig> element in orion-application.xml.

  2. Appropriate <security-role-mapping> entries exist:

    <security-role-mapping name="sr_developer">
      <user name="developer" />
    </security-role-mapping>
    <security-role-mapping name="sr_manager">
      <group name="managers" />
    </security-role-mapping>
    
    

    You can set these mappings through Application Server Control.

Custom Login Module Example

This section gives source code for a simple custom login module to be used by the CallerInfo example.

Example 8-2 SampleLoginModule.java

package oracle.security.jazn.samples;
 
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
import java.security.Principal;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
 
public class SampleLoginModule implements LoginModule {
 
    // initial state
    protected Subject _subject;
    protected CallbackHandler _callbackHandler;
    protected Map _sharedState;
    protected Map _options;
 
    // configuration options
    protected boolean _debug; 
 
    // the authentication status
    protected boolean _succeeded;
    protected boolean _commitSucceeded;
 
    // username and password
    protected String _name;
    protected char[] _password;
 
    protected Principal[] _authPrincipals;
 
 
    /**
     * Initialize this <code>LoginModule</code>.
     * <p/>
     * <p/>
     *
     * @param subject         the <code>Subject</code> to be authenticated. <p>
     * @param callbackHandler a <code>CallbackHandler</code> for communicating
     *                        with the end user (prompting for usernames and
     *                        passwords, for example). <p>
     * @param sharedState     shared <code>LoginModule</code> state. <p>
     * @param options         options specified in the login
     *                        <code>Configuration</code> for this particular
     *                        <code>LoginModule</code>.
     */
    public void initialize(Subject subject,
                           CallbackHandler callbackHandler,
                           Map sharedState,
                           Map options) {
        this._subject = subject;
        this._callbackHandler = callbackHandler;
        this._sharedState = sharedState;
        this._options = options;
 
        // initialize any configured options
        _debug = "true".equalsIgnoreCase((String) _options.get("debug"));
 
        if (debug()) {
            printConfiguration(this);
        }
    }
 
 
    final public boolean debug() {
        return _debug;
    }
 
 
    protected Principal[] getAuthPrincipals() {
        return _authPrincipals;
    }
 
 
    /**
     * Authenticate the user by prompting for a username and password.
     * <p/>
     * <p/>
     *
     * @return true if the authentication succeeded, or false if this
     *         <code>LoginModule</code> should be ignored.
     * @throws FailedLoginException if the authentication fails. <p>
     * @throws LoginException       if this <code>LoginModule</code>
     *                              is unable to perform the authentication.
     */
    public boolean login() throws LoginException {
        if (debug())
            System.out.println("\t\t[SampleLoginModule] login");
 
        if (_callbackHandler == null)
            throw new LoginException("Error: no CallbackHandler available " +
                    "to garner authentication information from the user");
 
        // Setup default callback handlers.
        Callback[] callbacks = new Callback[] {
            new NameCallback("Username: "),
            new PasswordCallback("Password: ", false)
        };
 
        try {
            _callbackHandler.handle(callbacks);
        } catch (Exception e) {
            _succeeded = false;
            throw new LoginException(e.getMessage());
        }
 
 
        String username = ((NameCallback)callbacks[0]).getName();
        String password = new
                          String(((PasswordCallback)callbacks[1]).getPassword());
        if (debug())
        {
            System.out.println("\t\t[SampleLoginModule] username : " + username);
        }
 
        // Authenticate the user. On successfull authentication add principals 
        // to the Subject. The name of the principal is used for authorization by
        // OC4J by mapping it to the value of the name attribute of the group 
        // tag in the security-role-mapping for the application.
        if(username.equals("developer") && password.equals("welcome")) 
        {
            _succeeded = true;
            _name = "developer";
            _password = password.toCharArray();
            _authPrincipals = new SamplePrincipal[2];
            //Adding username as principal to the subject
            _authPrincipals[0] = new SamplePrincipal("developer");
            //Adding role developers to the subject
            _authPrincipals[1] = new SamplePrincipal("developers");
        }
 
        if(username.equals("manager") && password.equals("welcome")) 
        {
            _succeeded = true;
            _name = "manager";
            _password = password.toCharArray();
            _authPrincipals = new SamplePrincipal[3];
            //Adding username as principal to the subject
            _authPrincipals[0] = new SamplePrincipal("manager");
            //Adding roles developers and managers to the subject
            _authPrincipals[1] = new SamplePrincipal("developers");
            _authPrincipals[2] = new SamplePrincipal("managers");
        }
 
 
        ((PasswordCallback)callbacks[1]).clearPassword();
        callbacks[0] = null;
        callbacks[1] = null;
 
        if (debug())
        {
            System.out.println("\t\t[SampleLoginModule] success : " + _succeeded);
        }
 
        if (!_succeeded)
            throw new LoginException
                           ("Authentication failed: Password does not match");
 
        return true; 
    }
 
 
    /**
     * <p> This method is called if the LoginContext's
     * overall authentication succeeded
     * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
     * succeeded).
     * <p/>
     * <p> If this LoginModule's own authentication attempt
     * succeeded (checked by retrieving the private state saved by the
     * <code>login</code> method), then this method associates a
     * <code>Principal</code>
     * with the <code>Subject</code> located in the
     * <code>LoginModule</code>.  If this LoginModule's own
     * authentication attempted failed, then this method removes
     * any state that was originally saved.
     * <p/>
     * <p/>
     *
     * @return true if this LoginModule's own login and commit
     *         attempts succeeded, or false otherwise.
     * @throws LoginException if the commit fails.
     */
    public boolean commit()
            throws LoginException {
        try {
 
            if (_succeeded == false) {
                return false;
            }
 
            if (_subject.isReadOnly()) {
                throw new LoginException("Subject is ReadOnly");
            }
 
            // add authenticated principals to the Subject
            if (getAuthPrincipals() != null) {
                for (int i = 0; i < getAuthPrincipals().length; i++) {
                    if(!_subject.getPrincipals().contains(getAuthPrincipals()[i])) {
                        _subject.getPrincipals().add(getAuthPrincipals()[i]);
                    }
                }
            }
 
            // in any case, clean out state
            cleanup();
            if (debug()) {
                printSubject(_subject);
            }
 
            _commitSucceeded = true;
            return true;
 
        } catch (Throwable t) {
            if (debug()) {
                System.out.println(t.getMessage());
                t.printStackTrace();
            }
            throw new LoginException(t.toString());
        }
    }
 
 
    /**
     * <p> This method is called if the LoginContext's
     * overall authentication failed.
     * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
     * did not succeed).
     * <p/>
     * <p> If this LoginModule's own authentication attempt
     * succeeded (checked by retrieving the private state saved by the
     * <code>login</code> and <code>commit</code> methods),
     * then this method cleans up any state that was originally saved.
     * <p/>
     * <p/>
     *
     * @return false if this LoginModule's own login and/or commit attempts
     *         failed, and true otherwise.
     * @throws LoginException if the abort fails.
     */
    public boolean abort() throws LoginException {
        if (debug()) {
            System.out.println
                   ("\t\t[SampleLoginModule] aborted authentication attempt.");
        }
 
        if (_succeeded == false) {
            cleanup();
            return false;
        } else if (_succeeded == true && _commitSucceeded == false) {
            // login succeeded but overall authentication failed
            _succeeded = false;
            cleanup();
        } else {
            // overall authentication succeeded and commit succeeded,
            // but someone else's commit failed
            logout();
        }
        return true;
    }
 
 
    protected void cleanup() {
        _name = null;
        if (_password != null) {
            for (int i = 0; i < _password.length; i++) {
                _password[i] = ' ';
            }
            _password = null;
        }
    }
 
 
    protected void cleanupAll() {
        cleanup();
 
        if (getAuthPrincipals() != null) {
            for (int i = 0; i < getAuthPrincipals().length; i++) {
                _subject.getPrincipals().remove(getAuthPrincipals()[i]);
            }
        }
    }
 
 
    /**
     * Logout the user.
     * <p/>
     * <p> This method removes the <code>Principal</code>
     * that was added by the <code>commit</code> method.
     * <p/>
     * <p/>
     *
     * @return true in all cases since this <code>LoginModule</code>
     *         should not be ignored.
     * @throws LoginException if the logout fails.
     */
    public boolean logout() throws LoginException {
        _succeeded = false;
        _commitSucceeded = false;
        cleanupAll();
        return true;
    }
 
    // helper methods //
 
    protected static void printConfiguration(SampleLoginModule slm) {
        if (slm == null) {
            return;
        }
        System.out.println("\t\t[SampleLoginModule] configuration options:");
        if (slm.debug()) {
            System.out.println("\t\t\tdebug = " + slm.debug());
        }
    }
 
 
    protected static void printSet(Set s) {
        try {
            Iterator principalIterator = s.iterator();
            while (principalIterator.hasNext()) {
                Principal p = (Principal) principalIterator.next();
                System.out.println("\t\t\t" + p.toString());
            }
        } catch (Throwable t) {
        }
    }
 
 
    protected static void printSubject(Subject subject) {
        try {
            if (subject == null) {
                return;
            }
            Set s = subject.getPrincipals();
            if ((s != null) && (s.size() != 0)) {
                System.out.println
                      ("\t\t[SampleLoginModule] added the following Principals:");
                printSet(s);
            }
 
            s = subject.getPublicCredentials();
            if ((s != null) && (s.size() != 0)) {
                System.out.println
             ("\t\t[SampleLoginModule] added the following Public Credentials:");
                printSet(s);
            }
        } catch (Throwable t) {
        }
    }
}

The Principal that this LoginModule uses is in Example 8-3.

Example 8-3 SamplePrincipal example

package oracle.security.jazn.samples;
 
import java.security.Principal;
 
public class SamplePrincipal implements Principal {
 
    private String _name = null;
        
 
    public SamplePrincipal(String name) {
        _name = name;
    }
 
    
    public boolean equals(Object another) {
        return ((SamplePrincipal)another).getName().equals(_name);
    }
 
 
    public String getName() {
        return _name;
    }
 
 
    public int hashCode() {
        return _name.hashCode();
    }
 
 
    public String toString() {
        return "[SamplePrincipal] : " + _name;
    }
 }