Skip Headers
Oracle® Containers for J2EE Security Guide
10g (10.1.3.1.0)

Part Number B28957-01
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
View PDF

9 Login Modules

This chapter discusses login modules supplied with OC4J, as well as how to implement, install, and configure a custom login module. The following topics are covered:

Initial Login Module Considerations

This section covers the following:

Specification of the Oracle Login Configuration Provider

By default, OC4J specifies usage of the OracleAS JAAS Provider login configuration provider (oracle.security.jazn.spi.LoginConfigProvider) by the OC4J JVM, overriding usage of the Sun Microsystems default JAAS login configuration provider.

This is accomplished through the following configuration in the file ORACLE_HOME/j2ee/home/config/jazn.security.props:

login.configuration.provider=oracle.security.jazn.spi.LoginConfigProvider

The Oracle login configuration provider uses the system-jazn-data.xml file for login module configuration.

Login Module Notes and Tips

Be aware of the following notes regarding the use of login modules with OC4J:

  • By convention, a setting of provider="XML" is required for an application using custom login modules (custom security provider). See related information about the custom.loginmodule.provider property in "Settings in <jazn> for Login Modules".

  • When using custom login modules, it is possible to instruct 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. See related information about the role.mapping.dynamic property in "Settings in <jazn> for Login Modules".

    To ensure that all relevant principals are taken into consideration during authorization, the login module must add the relevant principals (including any roles that the authenticated user belongs to) to the subject during the commit phase of the authentication process.

  • Login module configuration (under the <jazn-loginconfig> element) cannot be in an application-specific jazn-data.xml file; it must be in system-jazn-data.xml. Configuration will be written to system-jazn-data.xml automatically if you configure login modules through Application Server Control or in your orion-application.xml file. (Also see "Settings in <jazn-loginconfig> in orion-application.xml".)

  • If you use any identity repository other than the file-based provider or Oracle Internet Directory, you must define an administrative user account and administrator roles, grant the roles to the user, and grant necessary permissions to the roles, as discussed in "Creating the Administrative User and Roles and Granting RMI Permission".

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

  • See "OracleAS JAAS Provider Policy Management" regarding subject-based policy management when using a custom login module. The policy configuration must be in system-jazn-data.xml.

  • "Using the File-Based Provider Across an OC4J Group" discusses how to maintain system-jazn-data.xml settings across multiple OC4J instances. This functionality also applies to login modules, using MBean operations such as setLoginModule, remLoginModule, and getLoginModuleControlFlagTypes.


Troubleshooting Tips:

  • If an application is configured to use a custom login module but the login module is not found in the classpath, a "class not found" exception is thrown with a message such as the following: "WARNING unable to find LoginModule class: Missing class: Xxxxxx..." See "Summary of Choices for Packaging Login Modules" for related information.

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

Login Modules Supplied with OC4J

OC4J supplies the set of login modules, including standard J2EE login modules, listed in Table 9-1.

Table 9-1 Login Modules Supplied with OC4J

Login Module Description

oracle.security.jazn.login.module. RealmLoginModule

OC4J login module for the file-based provider or Oracle Identity Management. (Additional information follows.)

oracle.security.jazn.login.module.db. DBTableOraDataSourceLoginModule

OC4J login module for user data in a database. (Additional information follows.)

oracle.security.jazn.login.module. LDAPLoginModule

OC4J login module for external LDAP providers.

See Also: Chapter 10, "External LDAP Security Providers"

oracle.security.jazn.login.module.coreid. CoreIDLoginModule

OC4J login module for Oracle Access Manager.

See Also: Chapter 11, "Oracle Access Manager"



Notes:

  • This table does not show additional login modules internal to OC4J.

  • Oracle does not currently validate Sun login modules for use with OC4J. (These login modules, in package com.sun.security.auth.module, are not currently part of the JDK.)


This rest of this section offers additional information about the following login modules:

RealmLoginModule

The RealmLoginModule class is the default login module, for use with the file-based provider or Oracle Identity Management, and is configured when you configure these security providers through Application Server Control. This configuration is reflected in a <login-module> element under <jazn-loginconfig> in 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).

RealmLoginModule supports the options shown in Table 9-2 (reflected in <name> and <value> subelements of an <option> element under <login-module>).

Table 9-2 RealmLoginModule Options

Option Description 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

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



Notes:

  • RealmLoginModule does not have to be enabled if your application uses Oracle Single Sign-On authentication.

  • RealmLoginModule is used only with declarative security, not programmatic security.

  • The use of RealmLoginModule as a custom login module—in other words, as a custom security provider—is not supported.


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>

DBTableOraDataSourceLoginModule

The OC4J 10.1.3.1 implementation supplies a login module you can use if you have a user identity store in a database:

oracle.security.jazn.login.module.db.DBTableOraDataSourceLoginModule

This replaces previous functionality of the com.evermind.sql.DataSourceUserManager class, now deprecated (but still supported for backward compatibility, and still documented at the end of this section for completeness). It also replaces some authentication functionality of the deprecated com.evermind.security.User class.

Once you have created your database schema and an Oracle data source to connect to the database (as described in the data sources chapter of the Oracle Containers for J2EE Services Guide), you are ready to configure the login module.

DBTableOraDataSourceLoginModule supports a number of options for specifying such items as data location (table and column names) and password encryption. You can set these options through Application Server Control or the OracleAS JAAS Provider Admintool, with the settings being reflected in the <jazn-loginconfig> element of the system-jazn-data.xml file.

This section covers the following topics:


Note:

DBTableOraDataSourceLoginModule is available with the OC4J product and automatically included in the classpath.

DBTableOraDataSourceLoginModule Options

Table 9-3 summarizes the options supported by DBTableOraDataSourceLoginModule, noting which options are required, and including default values as applicable and examples as appropriate. There is no configuration of this login module in OC4J as shipped; refer to the sections that follow, "Configuring DBTableOraDataSourceLoginModule in Application Server Control" and "Configuring DBTableOraDataSourceLoginModule in the Admintool", for information about tools you can use in configuring the login module.

Note that DBTableOraDataSourceLoginModule supports encrypted passwords in the database table, and you can use custom password encryption algorithms. To use this feature, you must use an implementation of the following interface, discussed in "Implementing DBLoginModuleEncodingInterface for Password Encryption":

oracle.security.jazn.login.module.db.DBLoginModuleEncodingInterface

Oracle supplies implementations for the SHA1 and MD5 algorithms.

Table 9-3 DBTableOraDataSourceLoginModule Options

Option Description

data_source_name (required)

Name of the data source for the database, as configured in the data-sources.xml file.

Default: n/a

Example: jdbc/OracleDS

table (required)

Name of the database table containing user authentication information (user names, passwords, and so on).

Default: n/a

Example: userinfo

groupMembershipTableName (required)

Name of the database table containing role information.

Default: n/a

Example: groupinfo

usernameField (required)

Name of the column containing user names, in the table specified in the table option.

Default: n/a

Example: userName

passwordField (required)

Name of the column containing passwords, in the table specified in the table option.

Default: n/a

Example: passWord

pw_encoding_class

Name of your password encryption class, if you use password encryption. (See the discussion immediately preceding this table.)

Default: oracle.security.jazn.login.module.db.util. DBLoginModuleClearTextEncoder (no encryption)

Example: oracle.security.jazn.login.module.db.util. DBLoginModuleSHA1Encoder

See Also: "Implementing DBLoginModuleEncodingInterface for Password Encryption"

pw_key

The password encryption key, if you use password encryption. This key is accessed by the class specified in the pw_encoding_class option.

Default: n/a

Example: xyz

groupMembershipGroupFieldName (required)

Name of the column containing role names, in the table specified in the groupMembershipTableName option.

user_pk_column

Column name for the primary key in the table specified in the table option.

Default: Value of the usernameField option.

Example: userName

roles_fk_column

Column name for the foreign key in the table specified in the groupMembershipTableName option.

Default: Value of the usernameField option.

Example: userName

casing

The case-sensitivity when comparing login user names to names in the database. Use sensitive to require case-sensitive comparisons, toupper to convert the login user name to all-uppercase, or tolower to convert the login user name to all-lowercase. (If anything other than these three values is specified, the default value will be used.)

Default: sensitive

Example: toupper



Notes:

  • It is permissible to use the same table for user information and role information; in other words, to specify the same table for the table and groupMembershipTableName options. Notice that in this scenario, however, each user can have only one role. It is typical, and advisable, to use separate tables.

  • DBTableOraDataSourceLoginModule does not support null or empty passwords.

  • If you use password encryption, passwords are compared according to their encrypted values, not the unencrypted strings. When a user logging in types the password, it is encrypted according to the encrypting method of the class you specify in the pw_encoding_class option, and compared to the encrypted password stored in the database. No attempt is made to decrypt the password stored in the database.


Configuring DBTableOraDataSourceLoginModule in Application Server Control

"Configuring the Custom Security Provider in Application Server Control" discusses how to specify and configure a custom login module during deployment, change to a custom login module after deployment, add a login module, or update a login module. You can use these procedures to configure DBTableOraDataSourceLoginModule. The Application Server Control Console login module configuration page enables you to specify the login module class, and to specify names and values for any number of properties corresponding to the options documented in the preceding section, "DBTableOraDataSourceLoginModule Options".

Configuring DBTableOraDataSourceLoginModule in the Admintool

As an alternative to using the Application Server Control Console, you can configure DBTableOraDataSourceLoginModule through the OracleAS JAAS Provider Admintool. Use of the Admintool for login modules is discussed in "Using Admintool to Configure Login Modules and Grant RMI Permission".

Here is an example:

java -jar jazn.jar -addloginmodule application_name \
     oracle.security.jazn.login.module.db.DBTableOraDataSourceLoginModule \
     required data_source_name="jdbc/OracleDS" roles_fk_column="username" \
     table="userinfo"  groupMembershipTableName="groupinfo" \
     groupMembershipGroupFieldName="role" usernameField="username" \
     user_pk_column="username" passwordField="password" casing="sensitive"

Sample DBTableOraDataSourceLoginModule Settings in system-jazn-data.xml

As with any login module, option settings and other configuration are stored within the <jazn-loginconfig> element of the system-jazn-data.xml file. Here is an example:

<jazn-loginconfig>
   <application>
      <name>application_name</name>
      <login-modules>
         <login-module>
            <class>
              oracle.security.jazn.login.module.db.DBTableOraDataSourceLoginModule
            </class>
            <control-flag>required</control-flag>
            <options>
               <option>
                  <name>data_source_name</name>
                  <value>jdbc/OracleDS</value>
               </option>
               <option>
                  <name>table</name>
                  <value>userinfo</value>
               </option>
               <option>
                  <name>roles_fk_column</name>
                  <value>userName</value>
               </option>
               <option>
                  <name>groupMembershipGroupFieldName</name>
                  <value>role</value>
               </option>
               <option>
                  <name>user_pk_column</name>
                  <value>userName</value>
               </option>
               <option>
                  <name>passwordField</name>
                  <value>passWord</value>
               </option>
               <option>
                  <name>groupMembershipTableName</name>
                  <value>groupinfo</value>
               </option>
               <option>
                  <name>usernameField</name>
                  <value>userName</value>
               </option>
               <option>
                  <name>casing</name>
                  <value>sensitive</value>
               </option>
            </options>
         </login-module>
      </login-modules>
   </application>
   ...
</jazn-loginconfig>

Principals for DBTableOraDataSourceLoginModule

DBTableOraDataSourceLoginModule uses the following principals:

  • oracle.security.jazn.login.module.db.principals.DBUserPrincipal (for users)

  • oracle.security.jazn.login.module.db.principals.DBRolePrincipal (for roles)

A subject passed to the DBTableOraDataSourceLoginModule is populated with instances of these principal types.

For a user name in the user table (a name in the column indicated by the usernameField option, in the table indicated by the table option), there would be a corresponding DBUserPrincipal instance in the subject.

For a role name in the role table (a name in the column indicated by the groupMembershipGroupFieldName option, in the table indicated by the groupMembershipTableName option), there would be a corresponding DBRolePrincipal instance in the subject.

You can use the Admintool to grant permissions to a user or role, as follows:

% java -jar jazn.jar -grantperm \
       oracle.security.jazn.login.module.db.principals.DBUserPrincipal name \
       permissionclass [permission_parameters] 

% java -jar jazn.jar -grantperm \
       oracle.security.jazn.login.module.db.principals.DBRolePrincipal name \
       permissionclass [permission_parameters] 

In this syntax, name is the name of the DBUserPrincipal or DBRolePrincipal instance, permissionclass is the fully qualified name of the permission class for the permission you are granting, and permission_parameters are any appropriate parameters of the permission class (login for RMIPermission, for example).


Important:

Ensure that permission classes are in the classpath.

Implementing DBLoginModuleEncodingInterface for Password Encryption

To use password encryption with DBTableOraDataSourceLoginModule, you must use an implementation of the following interface to perform the encryption:

oracle.security.jazn.login.module.db.DBLoginModuleEncodingInterface

The implementing class must implement the following method, which is called by the login module:

  • String getKeyDigestString(String text, String key)

This method takes a text string to encrypt (such as a password) and a string that specifies a key, as set in the pw_key option for the login module (if applicable). The method would then encrypt the text string with any desired algorithm (with the key if specified), and preferably also formats the post-encryption binary data using any desired encoding standard (Base64Encoding, for example). It outputs the encrypted digest string.

For algorithms that do not use a key, such as MD5 or SHA1, any key passed could be ignored. If the pw_key option is not set, then its value is null and null is passed.

Oracle provides the following implementations in the oracle.security.jazn.login.module.db.util package:

  • DBLoginModuleSHA1Encoder

    This class generates a hash value for the given password string using the SHA1 algorithm, and encodes the binary hash using Base64Encoding. The binary hash of the password must be stored in the database using Base64Encoding.

  • DBLoginModuleMD5Encoder

    This class generates a hash value for the given password string using the MD5 algorithm, and encodes the binary hash using Base64Encoding. The binary hash of the password must be stored in the database using Base64Encoding.

  • DBLoginModuleClearTextEncoder

    If you do not specify an encryption class, DBLoginModuleClearTextEncoder is used, resulting in no encryption. This class simply passes the password string as it is given.

Previous Functionality: DataSourceUserManager (Deprecated)

Prior to implementation of DBTableOraDataSourceLoginModule in the OC4J 10.1.3.1 implementation, equivalent functionality was available through the com.evermind.sql.DataSourceUserManager class. While this feature is currently still supported for backward compatibility, it is deprecated and will be desupported in future releases. You should use DBTableOraDataSourceLoginModule instead.

However, for completeness, we include the following documentation for the DataSourceUserManager feature.


Notes:

  • The database you use must be specified as a data source, for which you provide a JNDI location in your configuration. The configuration also specifies the relevant database tables and fields.

  • In OC4J 10.1.3.x implementations, DataSourceUserManager obtains group information only from the database, which differs from the behavior in previous implementations. Therefore, you must map groups to users in the database, as applicable.


When you configure DataSourceUserManager (as described shortly), you can specify values for the properties described in Table 9-4, as appropriate. The DataSourceUserManager instance uses these properties to access the user-defined database table that lists the current users and their associated credentials.

Table 9-4 DataSourceUserManager Properties

Property Description

dataSource

A JNDI location for the installed data source (database) to use.

table

Name of the database table containing user data.

usernameField

Name of the column for user names in the database table.

passwordField

Name of the column for passwords in the database table.

certificateIssuerField

An identifier for the certificate issuer, if applicable.

certificateSerialField

The serial ID of the certificate issuer, if applicable.

localeField

The locale, if applicable.

defaultGroups

Comma-delimited list of groups that the users are members of.

groupMembershipTableName

Name of an optional database table that maps users to groups, if the use of defaultGroups is not sufficient.

groupMembershipUserNameFieldName

Name of the column for user names in the group membership database table, if applicable.

groupMembershipGroupFieldName

Name of the column for group names in the group membership database table, if applicable.

staleness

Number of milliseconds for which a fetched set of user data will be valid. The default setting is -1 (forever).

casing

Flag that controls how DataSourceUserManager handles character case for user names (but not group names) when trying to match a name against the list of known users in the database.

The default "sensitive" setting results in case-sensitive matching. For the "toupper" and "tolower" settings, the name is converted to all uppercase or all lowercase, respectively, for purposes of matching.

debug

Flag to enable output of debug information.


To use DataSourceUserManager, configure it in a <user-manager> element in your orion-application.xml file. This is a subelement of <orion-application>, and must be configured manually. There is no UserManager support in Application Server Control 10.1.3.x implementations.

Specify the DataSourceUserManager fully qualified name in the class attribute of <user-manager>. Use a <property> subelement to specify the name and value of each property you want to set.

Here is an example:

<orion-application ... >
   ...
   <user-manager class="com.evermind.sql.DataSourceUserManager">
      <property name="dataSource" value="jdbc/OracleCoreDS" />
      <property name="table" value="j2ee_users" />
      <property name="usernameField" value="username" />
      <property name="passwordField" value="password" />
      <property name="groupMembershipTableName" value="second_table" />
      <property name="groupMembershipGroupFieldName" value="group" />
      <property name="groupMembershipUserNameFieldName" value="userId" />
   </user-manager>
   ...
</orion-application>

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 (through configuration, as shown later), 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. You can also configure login modules through orion-application.xml, in which case the configuration is copied to system-jazn-data.xml.


See Also:


Summary of Choices for Packaging Login Modules

If you are using one or more of the default login modules provided with OC4J or the J2SE, 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.


Important:

If an application is configured to use a custom login module but the login module is not found in the classpath, a "class not found" exception is thrown with a message such as the following: "WARNING unable to find LoginModule class: Missing class: Xxxxxx..."

Packaging 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, or make it available as an optional package or shared library.

Providing 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 the 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:


Providing 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, as documented in "Tasks to Share a Library".

Configuring the Custom Security Provider in Application Server Control

This section discusses the following administration tasks for the custom security provider (custom login modules) using the Application Server Control Console:


Notes:

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

  • Any login module you specify must be in the classpath at runtime. (One option is to load it as a shared library, as described in "Tasks to Share a Library".)


Specifying and Configuring a Custom Security Provider during Deployment

When you plan to use a 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 or configuring a custom login module through Application Server Control results in the following required settings being inserted automatically 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.

  • By convention, there is a <jazn> setting of provider="XML" when you use custom login modules.

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



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 earlier in "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 9-5 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 9-5 Login Module Control Flags

Flag Meaning

Required

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

Requisite

The login module nominally 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.


These control flag settings are used according to standard functionality of the javax.security.auth.login.Configuration class. The overall authentication succeeds only if all "required" and "requisite" login modules succeed, possibly unless a "sufficient" login module is configured and succeeds—in that case, only the required and requisite login modules prior to the sufficient login module in the login module list must succeed.

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 earlier in "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 Table 9-5, "Login Module Control Flags" in the preceding section 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 Table 9-5, "Login Module Control Flags" 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 are prompted to restart your application for the changes to take effect.

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 Table 9-5, "Login Module Control Flags" 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 Table 9-5, "Login Module Control Flags" 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.

Using Admintool to Configure Login Modules and Grant RMI Permission

This section describes how to use the OracleAS JAAS Provider Admintool in the following ways:

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:

  • -addloginmodule: Configures a new login module for the named application. This includes specifying a control flag: one of required, requisite, sufficient or optional, as specified by javax.security.auth.login.Configuration and in Table 9-5, "Login Module Control Flags".

    If the login module supports options, specify each option and its value as an optionname=value pair. Each login module has its own individual set of options.

    For example, to add MyLoginModule, which we will assume supports a debug option, to the application myapp as a required module with debug set to true:

    % java -jar jazn.jar -addloginmodule myapp MyLoginModule required debug=true
    
    
  • -remloginmodule: Removes the specified login module.

    To remove MyLoginModule from myapp:

    % java -jar jazn.jar -remloginmodule myapp MyLoginModule
    
    
  • -listloginmodules: Displays all login modules for a specified application, or, if no application name is specified, displays login modules for all applications. Specifying a login module class after the application name displays information on only the specified class within the application.

    For example, to display all login modules for the application myapp:

    % java -jar jazn.jar -listloginmodules myapp
    
    

You can also execute these commands from the Admintool shell.


Important:

Restart OC4J for changes to take effect.

Granting RMI Permission through the Admintool

In case your application includes EJBs, note that to access an EJB through RMI, you must grant RMI permission "login" to the appropriate user, role, or principal. You can accomplish this through the Admintool, as in the following examples:

% java -jar jazn.jar -grantperm myrealm -role managers \
       com.evermind.server.rmi.RMIPermission login

% java -jar jazn.jar -grantperm oracle.security.jazn.samples.SamplePrincipal \
       managers com.evermind.server.rmi.RMIPermission login

(Always specify a realm when granting permissions to a user or role, but not when granting permissions to a principal.)

If you are in an Oracle Application Server environment with multiple OC4J instances, then you must specify the appropriate instance name (and hence the appropriate home directory) for the applicable OC4J instance, so that the system-jazn-data.xml file for the appropriate OC4J instance is updated. Set %oracleas.oc4j.instance% appropriately for your environment.

% java -jar -Doracle.j2ee.home=%ORACLE_HOME%/j2ee/%oracleas.oc4j.instance% \
       jazn.jar -grantperm myrealm -role managers \
       com.evermind.server.rmi.RMIPermission login 

% java -jar -Doracle.j2ee.home=%ORACLE_HOME%/j2ee/%oracleas.oc4j.instance% \
       jazn.jar -grantperm oracle.security.jazn.samples.SamplePrincipal managers \
       com.evermind.server.rmi.RMIPermission login 

Important:

Restart OC4J for changes to take effect.

Summary of 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 9-1 Example jazn-loginconfig element

<jazn-data>
  ..
  <jazn-loginconfig>
    <application>
      <name>myapp</name>
      <login-modules>
        <login-module>
          <class>mypath.MyLoginModule</class>
          <control-flag>required</control-flag>
          <options>
            <option>
              <name>myoptionname</name>
              <value>myoptionvalue</value>
            </option>
          </options>
        </login-module>
      </login-modules>
    </application>
  </jazn-loginconfig> 
  ..
</jazn-data>

This fragment associates the login module MyLoginModule with the application myapp.


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:


See Also:


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

Settings in the <jazn-loginconfig> element in system-jazn-data.xml were documented in "Login Module Settings in system-jazn-data.xml". You can add this element to orion-application.xml prior to 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, or when you deploy and configure your custom login module using the Application Server Control Console as discussed in "Specifying and Configuring a Custom Security Provider during Deployment".

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

Settings in <namespace-access> for Access to JNDI Context

If an application contains an EJB, remote clients must be given namespace access to read (look up) and write (bind) objects as required on the server-side JNDI context of the application.

The following example, which would appear in orion-application.xml, shows how the namespace access is granted for read operations to roles named managers and developers.

<orion-application ... >
   ...
   <namespace-access>
      <read-access>
         <namespace-resource root="">
            <security-role-mapping name="sr_developer">
               <group name="developers"/>
            </security-role-mapping>
            <security-role-mapping name="sr_manager">
               <group name="managers"/>
            </security-role-mapping>
         </namespace-resource>
      </read-access>
   </namespace-access>
   ...
</orion-application>

This assumes the indicated role mappings had already been set up elsewhere in orion-application.xml.

Login Module Settings in oc4j-ra.xml (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.

<oc4j-connector-factories ... >
  ...
  <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>
  ...
</oc4j-connector-factories>

See Also:


Step by Step: Integrating a Custom Login Module with OC4J

Developing a login module follows the standard development, packaging, and deployment cycle. For applications with EJBs, you must also grant RMI permission and configure namespace access as necessary. The following sections discuss each step in the cycle:

  1. Develop the Login Module

  2. Configure and Package the Login Module

  3. Configure Namespace Access and Role Mappings (as applicable)

  4. Deploy the Login Module

  5. Grant RMI Permission (as applicable)

  6. Set JNDI Properties (as applicable)

Develop the Login Module

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

When a login module is associated with an application (which occurs in the <jazn-loginconfig> configuration shown earlier), OC4J uses the principals set in the subject to determine if the client has access to the requested J2EE resource. Thus, it is imperative that the login module correctly set all the roles the user is a member of.

In the following example, the login module authenticates the developer user. After the user is successfully authenticated, a principal corresponding to the roles associated with the user is added to the current authenticated subject. Assume the developer user is a member of the developers role.

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");
}

See Also:


Configure and Package the Login Module

"Summary of Choices for Packaging Login Modules" summarizes the various ways you can package a login module so that it is accessible to your application. The choices are:

  • Package the login module with the application.

  • Provide the login module as an optional package.

  • Provide the login module as an OC4J shared library.

There are also choices for how you can specify the configuration of a login module:

The following sections highlight key configuration details.

Configuration to Enable Login Module Usage

OC4J requires the following configuration in the orion-application.xml file in order to use a custom login module to perform security checks. This occurs automatically when you specify login module configuration through Application Server Control or in orion-application.xml.

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

You can examine the orion-application.xml file after deployment to confirm this.

Configuration of the Login Module

The following configuration is for the sample login module shown in "Custom Login Module Example".

<!-- Configuring a Login Module in an Application EAR file.  -->
<jazn-loginconfig>
  <application>
    <name>cutomjaas</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>

You could manually put this configuration into the orion-application.xml file before deployment, or set the parameters (class name, control flag, and option names and values) as prompted during deployment when you deploy your application through Application Server Control. In either case, the configuration will automatically be written to system-jazn-data.xml.

Configure Namespace Access and Role Mappings (as applicable)

Configure namespace access in orion-application.xml if the application includes any EJBs. This is to allow remote client access to JNDI bindings for read (lookup) or write (bind) operations as required on objects in the server-side JNDI context of the application. The following example shows how the namespace access is granted to roles named managers and developers.

<orion-application ... >
   ...
   <namespace-access>
      <read-access>
         <namespace-resource root="">
            <security-role-mapping name="sr_developer">
               <group name="developers"/>
            </security-role-mapping>
            <security-role-mapping name="sr_manager">
               <group name="managers"/>
            </security-role-mapping>
         </namespace-resource>
      </read-access>
   </namespace-access>
   ...
</orion-application>

This assumes the role mappings—mapping logical roles defined in the application to roles supported by the custom login module—have been properly defined, as in the following example from orion-application.xml:

<orion-application ... >
   ...
   <!-- Mapping the logical roles to the container roles -->
   <security-role-mapping name="sr_manager">
      <group name="managers" />
   </security-role-mapping>
   <security-role-mapping name="sr_developer">
      <group name="developers" />
   </security-role-mapping>
   ...
</orion-application>

You can specify role mappings through Application Server Control, as discussed in "Mapping Security Roles". This results in the orion-application.xml entries being added automatically.

Deploy the Login Module

"Summary of Choices for Packaging Login Modules" discusses how you can deploy your login module either with your application or separately (as an optional package or shared library).

"Specifying and Configuring a Custom Security Provider during Deployment" discusses how to configure and deploy your login module through Application Server Control when you deploy your application.

Grant RMI Permission (as applicable)

If your application includes EJBs, be aware that to access an EJB through RMI, you must grant RMI permission "login" to the appropriate users, roles, and principals. You can accomplish this through the Admintool, as shown in "Granting RMI Permission through the Admintool".

Set JNDI Properties (as applicable)

To access resources through JNDI, you must configure the jndi.properties file to set properties such as the provider URL, principal, and credential, as appropriate for your environment. Here is an example:

java.naming.factory.initial=
                    oracle.j2ee.naming.ApplicationClientInitialContextFactory
java.naming.provider.url=ormi://localhost:23791/customjaas
#java.naming.provider.url=opmn:ormi://localhost:6003:home/customjaas
java.naming.security.principal=manager
java.naming.security.credentials=welcome

(The ormi protocol is for standalone OC4J, while the opmn:ormi protocol is for an Oracle Application Server environment. Uncomment the appropriate one.)

Custom Login Module Example

This section shows the login module code and principal code for an OC4J "how-to" example at the following location:

http://www.oracle.com/technology/tech/java/oc4j/1013/how_to/index.html

Look for the login module how-to under "J2EE Security / JAAS".

SampleLoginModule Code

This section contains the code for the sample login module.

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 LoginModule.
     *
     * subject         the Subject to be authenticated.
     * callbackHandler a CallbackHandler for communicating
     *                 with the end user (prompting for usernames and
     *                 passwords, for example).
     * sharedState     shared LoginModule state.
     * options         options specified in the login
     *                 Configuration for this particular
     *                 LoginModule.
     */
    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.
     *
     * return true if the authentication succeeded, or false if this
     *        LoginModule should be ignored.
     * throws FailedLoginException if the authentication fails.
     * throws LoginException       if this LoginModule
     *                             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 
        // element 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");
        }
 
      if (username.equals("sirish") && password.equals("sirish"))
      {
            _succeeded = true;
            _password = password.toCharArray();
            _name = "sirish";
            _authPrincipals = new SamplePrincipal[1];
            _authPrincipals[0] = new SamplePrincipal("sirish");
       }
 
        ((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; 
    }
 
    /*
     * This method is called if the LoginContext's
     * overall authentication succeeded
     * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
     * succeeded).
     * 
     * If this LoginModule's own authentication attempt
     * succeeded (checked by retrieving the private state saved by the
     * login method, then this method associates a
     * Principal with the Subject located in the
     * LoginModule.  If this LoginModule's own
     * authentication attempted failed, then this method removes
     * any state that was originally saved.
     *
     * 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());
        }
    }
 
    /*
     * This method is called if the LoginContext's
     * overall authentication failed.
     * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
     * did not succeed).
     * 
     * If this LoginModule's own authentication attempt
     * succeeded (checked by retrieving the private state saved by the
     * login and commit methods),
     * then this method cleans up any state that was originally saved.
     *
     * 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.
     * 
     * This method removes the Principal
     * that was added by the commit method.
     *
     * return true in all cases since this LoginModule
     *        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) {
        }
    }
}

SamplePrincipal Code

This section contains the code for the sample principal.

The login module sets the SamplePrincipal instance in the current Subject instance. To create the SamplePrincipal instance, the login module directly invokes the SamplePrincipal constructor, so the constructor is defined as public.

package oracle.security.jazn.samples;
 
import java.security.Principal;
 
/*
 * This class implements the Principal interface
 * and represents a Sample user.
 *
 * Principals such as this SamplePrincipal
 * may be associated with a particular Subject
 * to augment that Subject with an additional
 * identity.  Authorization decisions can then be based upon 
 * the Principals associated with a Subject.
 * 
 */ 
public class SamplePrincipal implements Principal {
 
    private String _name = null;
        
 
    /*
     * Create a SamplePrincipal with a Sample username.
     *
     */ 
    public SamplePrincipal(String name) {
       if (name == null) 
       throw new NullPointerException("name cannot be null");
        _name = name;
    }
 
    /*
     * Return a string representation of this SamplePrincipal.
     *
     */
    public String getName() {
        return _name;
    }
 
    /*
     * Return a hash code for this SamplePrincipal.
     *
     */
    public int hashCode() {
        return _name.hashCode();
    }
 
    /*
     * Return a string representation of this SamplePrincipal.
     *
     */
    public String toString() {
        return "[SamplePrincipal] : " + _name;
    }
 
    /*
     * Compares the specified Object with this SamplePrincipal
     * for equality.  Returns true if the given object is also a
     * SamplePrincipal and the two SamplePrincipals
     * have the same username.
     *
     */
    public boolean equals(Object o) {
      if (o == null)
          return false;
 
        if (this == o)
            return true;
 
        if (!(o instanceof SamplePrincipal))
            return false;
        SamplePrincipal that = (SamplePrincipal)o;
 
      if (this.getName().equals(that.getName()))
          return true;
      return false;
    }
}