Declarative J2EE authentication and authorization with JAAS

An Oracle JDeveloper How To Document
Written by Frank Nimphius and Duncan Mills, Oracle Corporation
July, 2005

Content

Introduction

Container-managed security, which is also referred to as J2EE declarative security, and the Java Authentication and Authorization Services (JAAS) are the security technologies for authentication and authorization in the Java 2 Enterprise Edition (J2EE) release 1.4 and above. J2EE declarative security in Oracle Containers for J2EE (OC4J) is implemented with Oracle JAAS, Oracle's implementation of the JAAS 1.0 standard. By default, the Oracle JAAS security provider allows user account information and security roles to be stored in one of two locations: a file based XML format or in an LDAP directory, leveraging the Oracle Internet Directory (OID). The file based Oracle JAAS provider is extensible to custom security implementations through the support of custom JAAS login modules for authentication and authorization.

This whitepaper explains how to use Oracle JDeveloper to configure declarative J2EE security for web applications. Further it describes using Oracle JDeveloper to deploy secure J2EE web application to an OC4J instance that is setup for custom JAAS LoginModule authentication.

The JAAS LoginModules provided as an example perform three different types of database authentication and authorization: based on a physical database schema, based on user and role tables and based on a stored database procedure that returns a Ref Cursor. The LoginModules are tested with OC4J 10.1.2, Oracle JDeveloper 10.1.2 and the Oracle 10g database. An Apache Ant script is provided to help you configuring the JAAS LoginModules and the related demo SQL scripts. All LoginModules, except the two that use container specific data-sources, can also be used with J2SE Swing applications.

The source code and the Apache Ant scripts are downloadable from the Oracle Technology Network (OTN).

J2EE Declarative Security

Container-managed security delegates all access control decisions to the J2EE container, thus cleanly separating application logic from security definitions. User roles in container-managed security, defined in the web application deployment descriptor ( web.xml) are statically mapped to security roles that are defined on the target J2EE container, for example Oracle Containers for J2EE (OC4J). Declarative J2EE security protects web applications by their URL patterns, which can be full absolute paths or relative paths and file extensions. For instance, to grant access to an application only to those users that are member of the USERS role, the following definition would be needed in the web.xml file:

<security-constraint>

<web-resource-collection>
<web-resource-name>AllPublic</web-resource-name>
<url-pattern>/</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USERS</role-name>
</auth-constraint>
</security-constraint>

This protects a web application starting from its J2EE root directory as indicated through the "/" pattern. To apply protection only to subdirectories, the pattern needed to be changed to "/<subdirectory name>". The role name USERS is a logical name that needs to be mapped to an existing role on the target platform, OC4J, using the container specific descriptor file, orion-web.xml.

<security-role-mapping impliesAll="false" name="USERS">

  <group name="APP_USERS"/> 
 </security-role-mapping>

In this example the security role USERS that is used to grant access to the J2EE web application is mapped to the user group APP_USERS on the OC4J platform. Members of the APP_USERS groups are specified either in the jazn-data.xml repository or in the Oracle Internet Directory (OID). In Oracle Containers for J2EE 10.1.3, users can also be defined in 3rd party LDAP servers. If the OC4J group name is the same as the role name used in the web.xml file, then no role to group mapping is required. Setting the impliesAll attribute of the <security-role-mapping> element to true will grant all defined users and groups of the target deployment platform as members of the logical USERS group.

Both configuration file, the web.xml deployment descriptor and the container specific orion-web.xml file can be edited visually using the Oracle JDeveloper IDE. The visual editing dialog is accessible from the context menu of the web.xml file entry in the Oracle JDeveloper project. The orion-web.xml file, because its a platform specific configuration file for OC4J, is not automatically added by default to a web application project in Oracle JDeveloper and must be manually added using the New option on the project's node context menu. Note that the orion-web.xml file is not required if the role names specified in the web.xml file have matching group names in the OC4J or Oracle Application Server user repository.

The benefit of the J2EE declarative security is that it does require little or no programming by the application developer because most of the security decisions are made during deployment. This model also allows changes to be applied to the security definition without requiring re-coding in the application.

Checking security roles in the application code

To support programmatic security, a web application developer can use the request.isUserInRole("<role name>") method call to evaluate the access granted to the authenticated user. Technologies like Struts and JavaServer Faces perform server side page forward navigation using postback requests, making it difficult to use declarative security throughout. Programmatic use of J2EE security that evaluates a security role within application code becomes more important with these technologies.

Role mapping

For the J2EE web application code that perform programmatic authorization to remain independent from the roles defined in the web.xml file or on the target platform, J2EE allows application developers to define logical role names in their application code later get mapped to role names in the web.xml deployment descriptor file.

In the application code, which can be in a Struts action, a JavaServer Faces (JSF) managed bean or in a JavaServer Pages (JSP) page, the application developer would use for example request.isUserInRole("VALID_USER") to verify that a user has been granted the access privilege for a specific resource or information. In the given example, the VALID_USER role name used in the application code, is mapped to the USERS role defined in the web.xml file, using the <security-role-ref> element as a sub-element of the <servlet></servlet> element in the web.xml deployment descriptor file.



 <security-role-ref> 
 <role-name>VALID_USER</role-name>    
 <role-link>USERS</role-link> 
 </security-role-ref>
 

User authentication

Authentication in declarative security is enforced when a user requests a protected web application area. If the user hasn't been authenticated before, a login dialog is shown for the user to identify himself. The commonly used types of authentication are FORM based authentication and BASIC authentication. The type of authentication is specified in the web.xml deployment descriptor using the <login-config> element.



 <login-config>    
 <auth-method>                                   
 BASIC
 </auth-method>    </login-config>

BASIC authentication uses the browser login dialog for the user to enter his username and password. This dialog form cannot be customized and thus varies in its look and feel depending on the type of browser used. The user credentials are stored in the browser session for the authenticated realm. A realm in J2EE is a protection domain that defines a set of permissions for the authenticated user. The default realm in Oracle JAAS is jazn.com. Using Basic authentication, the username and password is send with each request in a base64 encoded form in the HTTP header.

<login-config>

 <auth-method>  
 FORM </auth-method>    
 <form-login-config>   <form-login-page>logonform.jsp</form-login-page>  
 <form-error-page>error.jsp</form-error-page>
 </form-login-config>   
 </login-config>

FORMS based authentication allows the application developer to specifies a custom login dialog. The username parameter must have a name of j_username, the password field must be named j_password. The logon form action must have a value of j_security_check for the J2EE container to authenticate the request. The user remains authenticated throughout the server session.

Both approaches, FORM based authentication and BASIC authentication aren't secure and vulnerable against eavesdropping attacks. Therefore it is highly recommended to run applications that use BASIC or FORM based authentication with the HTTPS protocol. A less often used authentication, though more reliable, is to use mutual authentication with digital certificates, also known as public key encryption (PKI). All J2EE compliant containers support this type of authentication.

JAAS Authentication

The Java Authentication and Authorization Service (JAAS) consist of a set APIs and interfaces for fine grained programmatic authentication and authorization. JAAS was designed to augment the Java 2 Security platform, enabling security developers to perform authorization not only based on the code location, but also on the user executing the code. Authentication in JAAS is performed through a pluggable authentication module architecture (PAM), which uses one or more LoginModules to authenticate a user or service. Compared to declarative J2EE security, JAAS enables the security developer to customize the authentication process for an individual application. No changes are required in the J2EE application code to change the authentication source for an application.

The key to JAAS authentication are pluggable LoginModules that perform the authentication based on information provided through callback handlers. Custom LoginModules must implement the methods defined by the javax.security.auth.spi.LoginModule interface.

Callback handlers are used to obtain the user credentials to pass to the LoginModule(s) for authentication. user credentials could be provided through login dialogs, tokens, certificates and whatever developers come up with. The login() method of a LoginModule is called by the LoginContext to authenticate a user and returns either true for a successful authentication, false for a failed authentication or throws a javax.security.auth.login.LoginException in case of a failure. Its the LoginContext's responsibility to read the LoginModule configuration file and call each of the LoginModules configured for a particular application.

fig1

A JAAS Subject represents the authenticated user after successful authentication. LoginModules add instances of java.security.Principal to the Subject upon successful authentication. Principals are used in JAAS to authorize an authenticated user to perform specific privileged actions. Later, in the context of this paper, user Principals will be used to dynamically define J2EE security roles for the authenticated user. Only if the overall authentication of the LoginContext succeeded, the commit method is called on each configured LoginModule. Otherwise the LoginModule abort() method is called to reset the LoginModule's inner state.

J2EE and J2SE applications use an instance of LoginContext to perform the login process. The LoginModules are configured in an external configuration file under a named entry, which gets passed as the first argument to the LoginContext constructor. The second argument passed to the LoginContext is the callback handler that is used to obtain the user's authentication credentials. Note that an application that uses declarative J2EE authentication with JAAS in Oracle Application Server or OC4J does not need to create the LoginContext because its created by the Oracle J2EE container implicitly.

javax.security.auth.login.LoginContext lc = new javax.security.auth.login.LoginContext ("<LoginModuleDef",<callback handler>);

The "<LoginModuleDef>" is a named reference for one or more LoginModule specified in the JAAS configuration. The named configuration reference in the example is "DBLoginModuleAuth" and defines one LoginModule to perform user authentication against the database. The first argument in the configuration is the absolute class name of the LoginModule, followed by a flag indicating whether the LoginModule needs to succeed for the overall authentication to succeed.

DBLoginModuleAuth{ oracle.sample.dbloginmodule.DBSystemLM.DBSystemLoginModule required debug="true" log_level="ALL" ... };

The flag after the login module class name indicates how the authentication process continues in case of success or failure, in the case of a multiple LoginModule configuration. Using multiple LoginModules allows application security administrators to perform graduated authentication for an application, which is that different users have different sets of privileges based on the number and type of authenticated Principles added to the Subject. The available choice of flags is as follows:

Required The LoginModule must succeed. Authentication always proceeds down the list of LoginModule but the overall authentication will fail if one of the required LoginModules fails authenticating the user.
Requisite The LoginModule must succeed. Authentication continues down the LoginModule list, if successful. Control immediately returns to the application, if failed
Sufficient The LoginModule is not required to succeed. If it succeeds, control immediately returns to the application. If it fails, authentication continues down the list of LoginModules
Optional The LoginModule is not required to succeed

Following the flag, LoginModule specific options are listed. These options are defined by the LoginModule itself and control the LoginModule behavior. For a database LoginModule this information would include the JDBC connect string to perform user authentication against. One commonly used option is debug to enable or disable authentication logs being written. All options that are configured for the LoginModule are accessible to the LoginModule at runtime:

String db_schema = options.get("db_schema")!=null?(String) options.get("db_schema"):null;

The options variable is an instance of java.util.Map and is implicitly passed from the JAAS infrastructure to the LoginModules initialize method, based on the LoginModule configuration.

Configuring JAAS declarative J2EE security in OC4J

By default, Oracle Containers for J2EE (OC4J) authenticates users against the jazn-data.xml file, an XML based user provider, or Oracle Internet Directory (OID), an LDAP v3 compliant directory server. To customize J2EE authentication, OC4J supports custom LoginModules that are configured with the bootstrap jazn-data.xml file, which is located in the OC4J_Home\j2ee\home\config directory.

On OC4J, it is possible to define one or more LoginModules to authenticate a specific J2EE application. Access privileges are added to the authenticated Subject in the form of java.security.Principal instances. In OC4J, Principals can be configured to map to J2EE declarative security roles defined in the web.xml file. To successful deploy J2EE applications with a custom JAAS authentication to OC4J, the following configuration steps need to be performed

  • Definition of an application name for the J2EE application in Oracle JDeveloper
  • Configuration of the bootstrap jazn-data.xml file with the JAAS Login Module(s)
  • Configuration of the J2EE application to obtain security role names from the authenticated Subject
  • Configuration of data-sources.xml (optional)
  • Configuration of password indirection (optional)

Defining the J2EE application name in Oracle JDeveloper

The J2EE application name is configured as Enterprise Application Name when creating the WAR deployment profile for the web application project in JDeveloper.

fig2

The application name may be different from the selected web context root, which after deployment is shown as part of the request URL. In the example shown above, the Enterprise Application Name is set to DBLMTest, which will be used when configuring the JAAS LoginModules for J2EE declarative authentication.

Setting up the bootstrap jazn-data.xml file with application specific LoginModules

To configure custom JAAS LoginModules in OC4J or Oracle Application Server, the bootstrap jazn-data.xml file needs to be edited. The bootstrap jazn-data.xml file is located in the OC4J_Home\j2ee\home\config directory and is read at OC4J instance startup time. To edit this file, e.g. to add or remove JAAS LoginModule for J2EE authentication, it is recommended to use the jazn.jar command line tool with the following syntax, starting in the OC4J_Home\j2ee\home\ directory.

java -jar jazn.jar -addloginmodule application_name login_module_name control_flag [optionname=value ...]
java -jar jazn.jar -remloginmodule application_name login_module_name

To use one of the example LoginModule provided with this document for declarative J2EE authentication of the deployed "DBLMTest" web application, the command would be as follows:

java -jar jazn.jar -addloginmodule DBLMTest oracle.sample.dbloginmodule.DBProcLM.DBProcLoginModule required debug="true" log_level="ALL" jdbcUrl="jdbc:oracle:thin:@localhost:1521:orcl" jdbcDriver="oracle.jdbc.driver.OracleDriver" db_schema="scott" db_schema_pw="tiger" plsql_procedure="DBPROCLM.GET_USER_AUTHENTICATION" application_realm="Online Trainings"

This command adds the LoginModule DBProcLoginModule with the required flag for the DBLMTest application. LoginModule Specific options like debug, log_level and the jdbcURL are also provided. This configuration gets written into jazn-data.xml as

<application>                          <name>DBLMTest</name>

 <login-modules>  
 <login-module> <class>oracle.sample.dbloginmodule.DBProcLM.DBProcLoginModule</class>  <control-flag>required</control-flag> 
 <options>      
 <option>     
 <name>debug</name>   
 <value>true</value>     
 </option>           
 <option>   
 <name>jdbcDriver</name>    <value>oracle.jdbc.driver.OracleDriver</value>   
 </option>  
 <option>   
 <name>application_realm</name>  
 <value>Online Trainings</value> 
 </option>       
 <option>  
 <name>plsql_procedure</name>   
 <value>DBPROCLM.GET_USER_AUTHENTICATION</value>
 </option> 
 <option>  
 <name>db_schema</name>  
 <value>scott</value>  
 </option>     
 <option>   
 <name>jdbcUrl</name>    <value>jdbc:oracle:thin:@localhost:1521:orcl</value> 
 </option>  
 <option>  
 <name>db_schema_pw</name>  
 <value>tiger</value>  
 </option>         
 <option>        
 <name>log_level</name>
 <value>ALL</value>
 </option>   
 </options>  
 </login-module>   
 </login-modules>  
 </application>

As it becomes obvious, having the database password value written in clear text is not the safest way of configuration. This problem, or shall we say challenge, will be addressed in one of the following sections of this paper that explains how modified versions of the custom database LoginModule can be used with J2EE data sources to perform the database connect.

Before the jazn-data.xml file settings get written to the jazn-data.xml file, the OC4J administration username and password need to be provided at the command line. By default the administration username is admin and the password is set to welcome. To change the administration password, start OC4J with the -install option.

java -jar oc4j.jar -install

It is possible to repeat the -addloginmodule command for a specific application so that multiple LoginModule authentication is performed.

Configure the LoginModule JAR file with OC4J

The Java Archive file (JAR) that contains the custom LoginModule needs to be copied to the OC4J_Home\lib directory and configured in the OC4J_Home\j2ee\home\config\application.xml to be available for all web applications deployed on a OC4J instance. The application.xml file is a global configuration file and can be edited with a text editor of choice. To configure the LoginModule JAR file as a library entry, assuming the LoginModules are stored in a file called DBLoginModule.jar, the following entry needs to be added to the list of existing library entries:

<library path="../../../lib/DBLoginModule.jar"/>

It is necessary to restart the OC4J instance for this change to have an impact.

Configure the J2EE application to obtain security role names from the authenticated Subject

To use Principals added to the authenticated Subject as J2EE security roles, the role.mapping.dynamic property needs to be set in the application specific orion-application.xml file. A Principal name of "manager" the will be treated as the granted J2EE role "manager" that can be used to access control access to J2EE web applications, as explained earlier in this document.

Oracle JDeveloper can be used to add the orion-application.xml file to a web project, choosing orion-application.xml from the list of Deployment Descriptors in the JDeveloper New Gallery.

fig3

The orion-application.xml file gets created in the web application project's Application Sources > META-INF directory and can be opened for editing with a double click. After editing the file, its content should look like

<jazn provider="XML" location="jazn-data.xml" default-realm="jazn.com">

 <property name="role.mapping.dynamic" value="true"/>
 <property name="jaas.username.simple" value ="true" />                                       </jazn>                                     

Beside of the role.mapping.dynamic parameter, a second parameter, jaas.username.simple, is added in this example. Using the jaas.username.simple parameter removes the realm name from the username retrieved in a call to request.getUserPrincipal().getName(). The orion-application.xml file is deployed with the J2EE web application to OC4J.

Configuring J2EE data sources in j2ee\home\data-sources.xml

Database LoginModules require database account information to connect to the database. As mentioned earlier, providing this information in clear text in the jazn-data.xml file is not safe. An alternative option is to leverage J2EE data-sources that are configured on the OC4J server to hold the database connect information. The LoginModule can be programmed to obtain the required database connect information from a configuration in the data-sources.xml file. New data sources are configured in the OC4J_Home\j2ee\home\data-sources.xml file using a text editor of choice. In the example below, a datasource "jdbc/OracleDS" is defined that connects to the "scott" database account using the "tiger" password.



 <data-source 
 class="com.evermind.sql.DriverManagerDataSource"                                      
 name="jdbc/OracleDS"  
 location="jdbc/OracleCoreDS"  
 xa-location="jdbc/xa/OracleXADS"   
 ejb-location="jdbc/OracleDS"   
 connection-driver="oracle.jdbc.driver.OracleDriver" 
 username="scott"    
 password="tiger"   
 url="jdbc:oracle:thin:@localhost:1521:orcl" 
 inactivity-timeout="30"
 />

To work with this information in a LoginModule, the following code need to be added to the Loginmodule

Context ic = new InitialContext();

 DataSource dataSource = (DataSource) ic.lookup(_data_source_name);  
 Connection conn = dataSource.getConnection(); 

Now that the password no longer is passed as an option to the LoginModule, it still doesn't look safe. This however can be achieved with the password indirection feature in OC4J that allows passwords used in the data-sources.xml to be stored encrypted in the jazn-data.xml file, as explained in the next section.

Password indirection in OC4J

For stronger protection, configure the J2EE data sources to use password indirection in OC4J. An indirect password is made up of a special indirection symbol, which is a hyphen directly followed by a greater than character (->), and a user name. When OC4J encounters an indirect password, it uses its privileged access to retrieve the password associated with the specified user from the OC4J jazn-data.xml file, which is located in the <OC4J_Home>\j2ee\home\config directory.

To use password indirection, the value of the password attribute in the <data-source/> element is replaced by the "->PwdForScott" reference



 <data-source  
 class="com.evermind.sql.DriverManagerDataSource"
 name="jdbc/OracleDS"  
 location="jdbc/OracleCoreDS"   
 xa-location="jdbc/xa/OracleXADS"
 ejb-location="jdbc/OracleDS" 
connection-driver="oracle.jdbc.driver.OracleDriver" 
username="scott"       
 password=  
  "->PwdForScott"                                 url="jdbc:oracle:thin:@localhost:1521:orcl"
inactivity-timeout="30"                                      />

The jazn-data.xml file in the <OC4J_Home>\j2ee\home\config directory requires the following additional entry to make the password indirection work



 <user>    
 <name>PwdForScott</name>   
 <display-name>PwdForScott</display-name> 
 <description>Scott's 
 password</description>     
 <credentials>!tiger</credentials>   
 </user>
 

The database schema password in the jazn-data.xml example provided above is "tiger". Because the password is specified with a leading "!" character, it gets encrypted after re-starting the OC4J instance. The encrypted password looks similar to "{903}ZECYw/3kJmhVjzXgbZhxFg1/F8mhpsrr". The LoginModule usage of the data source does not need to be changed for using the password indirection feature.

Oracle Database LoginModule Examples

The Oracle database LoginModule examples provided with this document are designed for the Oracle platform, which is Oracle Containers for J2EE and the Oracle database. All LoginModules, except for the two that require a J2EE data source to be defined, can be used in a J2SE environment as well and thus can be used to also authenticate Swing applications. This section introduces each of the LoginModules in turn and provides all the information needed to use them in a customer project.

Note that LoginModules perform authentication only and do not connect the application to the database. For performance reasons J2EE web applications usually use database connection pools when interacting with the database.

List of example LoginModules and scripts

This how-to document provides 5 custom JAAS LoginModules for database authenticating J2EE users.

  • DBSystemLoginModule
  • DBTableLoginModule
  • DBTableOraDatasourceLoginModule
  • DBProcLoginModule
  • DBProcOraDataSourceLoginModule

fig4

The DBTableOraDatasourceLoginModule and DBProcOraDataSourceLoginModule are slightly modified versions of the DBTableLoginModule and the DBProcLoginModule that use the data-sources.xml file to retrieve the database connect information.

The LoginModules source code is available in the provided Oracle JDeveloper 10.1.2 workspace, named "DatabaseLoginModule1012". In this section each of the LoginModules is explained in brief.

SQL scripts are provided to populate a database schema with sample tables and data. The LoginModules however are configurable to use custom database table structures instead. The two SQL scripts are

  • TableLMDbScriptClearPw.sql
  • TableLMDbScriptEncryptedPw.sql

The scripts can be accessed and deployed to the database from the JDeveloper DatabaseLoginModule1012 workspace, using Oracle JDeveloper 10.1.2. both scripts create user and role tables. The TableLMDbScriptClearPw.sql creates users with passwords written in clear that can be used with the following LoginModules: DBTableLoginModule, DBTableOraDatasourceLoginModule, DBProcLoginModule and DBProcOraDataSourceLoginModule.

The TableLMDbScriptEncryptedPw.sql script creates a user table with SHA1 encrypted passwords. This script can be used with the DBTableLoginModule and DBTableOraDatasourceLoginModule, setting the pw_encoding_class="oracle.sample.dbloginmodule.util.DBLoginModuleSHA1Encoder" option in the LoginModule configuration.

fig4

To use other password encryptions techniques than SHA1, the LoginModule's password encoder is made pluggable, allowing custom implementations to be created and used. The default encoding class is DBLoginModuleClearTextEncoder, which expects passwords to be stored in clear text the database table. The DBLoginModuleSHA1Encoder used with one of the installation scripts uses the user password as the key when creating the encrypted password representation for comparison with the database stored user password. Developers that want to create their own password encoder must implement the DBLoginModuleEncodingInterface to make their implementation work with the LoginModules provided with this how-to document. If database passwords are encrypted with the database encryption capabilities, it may be preferred to use the DBProcLoginModule in a stored procedure and handle the password verification directly in the database. An example stored procedure that operates against the example database tables using the script with clear text passwords is provided.

A JDeveloper test case project is provided to test each of the LoginModules before deploying it to OC4J.

User accounts created by the TableLMDbScriptClearPw.sql or TableLMDbScriptEncryptedPw.sql example scripts are

Username Password Roles Application Realm
Darth Vader welcome0 Administrator,User,Content Owner Online Trainings
Luke Skywalker welcome1 User Online Trainings
Han Solo welcome2 User,Manager,Content Owner Online Trainings

The application realm is used for fine grained application access control. The application realm must not necessarily match the J2EE realm and is a named identifier for the LoginModule to select the user roles. If no application realm is provided in the JAAS LoginModule configuration then all roles are read from the configured role table. The options to use are: realm_column="realm" and application_realm="Online Trainings".

Possible JAAS database LoginModule custom enhancements: The example database table scripts also contain columns that store information about the validness of user accounts and granted user roles . For the user table, "SEC_USERS", this column is named "VALID_ACCOUNT" and has a value of 1 for valid user accounts and 0 for temporarily invalidated accounts. Similarly the "SEC_USER_ROLE_MAPS " table has a "VALID_GRANT" column to temporarily remove a permission from a user. The database LoginModules provided with this paper don't evaluate these columns but could be adapted to do so.

The LoginModules' source code is provided and can be modified to reflect account and role granting expiry. This modification is relative easy to do within the "performDbAuthentication(String username, char[] password)" method, which is part of each database LoginModules. All that needs to be done to handle temporary user account and role grant expiry is to include the two columns mentioned above in the JAAS authentication query for users and roles and evaluate the results when adding Principals to the JAAS Subject. Adding this functionality allows administrators to manage revocation lists easily, a feature that you don't usually find in declarative J2EE authentication, especially because the specification doesn't demand for it.

DBSystemLoginModule

The DBSystemLoginModule authenticates a user against a physical database schema using the provided username and password for authentication. If the user can be authenticated, the LoginModule reads all database role names that are granted to this user and turns them into J2EE security roles. This LoginModules is ideal for environments in which each user has his own database account and where non-J2EE web applications need to co-exist with J2EE applications, leveraging the same role names for permission granting.

The following JAAS options are case sensitive and can be configured for this LoginModule

Option Meaning
jdbcUrl The JDBC connect string except for username and password: jdbc:oracle:thin:@host:port:sid
jdbcDriver The JDBC driver used. The default setting is: "oracle.jdbc.driver.OracleDriver"
logger_class The class that implements the LMLogger interface to write log information for this LoginModule. Custom logging can be implemented using this option. The default configuration uses oracle.sample.dbloginmodule.util . ScreenLoggerImpl, which writes log messages to the console. The logger_class option can be omitted if console output is sufficient

A second option provided in the examples are oracle.sample. dbloginmodule.util.JavaLoggerImpl to leverage the java.util.logging package, in which case the location of a Java Logger properties file needs to be specified when starting OC4J or a J2SE application
log_level This option determines the granularity of the messages that are printed by the LoginModule. If this option isn't provided then all possible messages are written if the "debug" option is set to true. Similar, specifying log_level=ALL prints out all message details. Setting log_level to AUTH will only print the messages that are directly related to the authentication process itself
debug debug=true prints authentication process information to the configured logging system, which by default is the console

To configure the DBSystemLoginModule with jazn-data.xml in OC4J 10.1.2, a command similar to the following needs to be specified on a command line in the OC4J_Home\j2ee\home directory:



 java -jar jazn.jar -addloginmodule  
 oracle.sample.dbloginmodule.DBSystemLM.DBSystemLoginModule required debug="true" 
 log_level="ALL" jdbcUrl="jdbc:oracle:thin:@localhost:1521:orcl" 
jdbcDriver="oracle.jdbc.driver.OracleDriver"

DBTableLoginModule

The DBTableLoginModule authenticates the user against a configurable database table. Granted user roles as well are queried from a configurable table. Unlike existing database LoginModules, this LoginModule does not demand for a specific table structure, allowing users to leverage any existing database tables. This LoginModule is useful when new J2EE built applications should leverage existing custom security infrastructures in the database.

The following JAAS options are case sensitive and can be configured for this LoginModule

Option Meaning
jdbcUrl The JDBC connect string except for username and password: jdbc:oracle:thin:@host:port:sid
jdbcDriver The JDBC driver used. The default setting is: "oracle.jdbc.driver.OracleDriver"
logger_class The class that implements the LMLogger interface to write log information for this LoginModule. Custom logging can be implemented using this option. The default configuration uses oracle.sample.dbloginmodule.util . ScreenLoggerImpl, which writes log messages to the console. The logger_class option can be omitted if console output is sufficient

A second option provided in the examples are oracle.sample. dbloginmodule.util.JavaLoggerImpl to leverage the java.util.logging package, in which case the location of a Java Logger properties file needs to be specified when starting OC4J or a J2SE application
log_level This option determines the granularity of the messages that are printed by the LoginModule. If this option isn't provided then all possible messages are written if the "debug" option is set to true. Similar, specifying log_level=ALL prints out all message details. Setting log_level to AUTH will only print the messages that are directly related to the authentication process itself
db_schema The database schema that holds the user and role tables fro authentication and authorization. The schema itself should be less privileged because of its exposure in the JAAS configuration files.
db_schema_pw The password to connect to the database schema that holds the authentication and authorization tables. The password is provided in clear text, which is not safe. To make it safe, for J2EE applications it is recommended to use the DBTableOraDataSourceLoginModule.
user_table The name of the table holding the user authentication columns
roles_table The name of the table holding the user role information
username_column The name of the column in the user table that holds the username
password_column The name of the column in the user table that holds the user password for authentication
pw_encoding_class

This LoginModules supports encrypted passwords in the database table . The pw_encoding_class option expects an implementation of the DBLoginModuleEncodingInterface interface to work with. This allows custom password encryption algorithms to be used. Note that the passwords are compared by their encrypted values, not by their unencrypted strings.

The default implementation uses passwords written in clear text. An alternative implementation using SAH1 is provided with the oracle. sample.dbloginmodule.util.DBLoginModuleSHA1Encoder class, which performs a SHA1 encryption plus base64 encoding of the password, using the same string as a key if no extra encryption key is provided. The SQL script " TableLMDbScriptEncryptedPw.sql" provides a testcase that uses SHA1 encrypted passwords.

pw_key Option that, if provided, passes the encryption key to the LoginModule. The key is accessible for the class specified in pw_encoding_class.
roles_column Name of the column in the roles table that holds the user role names
realm_column Optional, the name of the column in the roles table that holds the application realm. The application realm can be used for fine grained authorization. For example, a user may be granted the manager role in app1 but not in app2.
application_realm The name of an application realm that restricts the user role query. This name is optional and is only required in combination with the realm_column. Not specifying a realm makes the LoginModule to read all user roles from the roles table
user_pk_column Name of the primary key column in the user table
roles_fk_column Name of the foreign key column in the roles table
debug debug=true prints authentication process information to the configured logging system, which by default is the console

To configure the DBSystemLoginModule with jazn-data.xml in OC4J 10.1.2, a command similar to the following, based on the provided TableLMDbScriptEncryptedPw example script, needs to be specified on a command line in the OC4J_Home\j2ee\home directory



 java -jar jazn.jar -addloginmodule <application name> 
 oracle.sample.dbloginmodule.DBTableLM.DBTableLoginModule required debug="true"
 log_level="ALL" jdbcUrl="jdbc:oracle:thin:@localhost:1521:orcl" 
 jdbcDriver="oracle.jdbc.driver.OracleDriver" db_schema="scott" db_schema_pw="tiger" 
 user_table="sec_users" roles_table="user_roles_view" username_column="username" 
 password_column="password" roles_column="rolename" user_pk_column="userid" 
 roles_fk_column="userid" realm_column="realm" application_realm="Online Trainings" 
 pw_encoding_class="oracle.sample.dbloginmodule.util.DBLoginModuleSHA1Encoder"

 

Note: It should be possible to copy the example configuration shown above and paste it on a command line to save you from typing.

DBTableOraDataSourceLoginModule

One important aspect in application security is configuration security. Unfortunately, providing database passwords in clear when configuring the custom JAAS LoginModule is a possible security breech. To enable better configuration security when deploying J2EE applications with OC4J, it is possible to define a J2EE datasource for the database connect information and use the password indirection feature of OC4J to encrypt the password. The DBTableOraDataSourceLoginModule supports J2EE data sources and the OC4J password indirection and should be the preferred LoginModule to use for user table based J2EE authentication. This LoginModule however doesn't work in J2SE environments.

The following JAAS options are case sensitive and can be configured for this LoginModule

Option Meaning
logger_class The class that implements the LMLogger interface to write log information for this LoginModule. Custom logging can be implemented using this option. The default configuration uses oracle.sample.dbloginmodule.util . ScreenLoggerImpl, which writes log messages to the console. The logger_class option can be omitted if console output is sufficient

A second option provided in the examples are oracle.sample. dbloginmodule.util.JavaLoggerImpl to leverage the java.util.logging package, in which case the location of a Java Logger properties file needs to be specified when starting OC4J or a J2SE application
log_level This option determines the granularity of the messages that are printed by the LoginModule. If this option isn't provided then all possible messages are written if the "debug" option is set to true. Similar, specifying log_level=ALL prints out all message details. Setting log_level to AUTH will only print the messages that are directly related to the authentication process itself
data_source_name Name of the data source configured in the data-sources.xml file
user_table The name of the table holding the user authentication columns
roles_table The name of the table holding the user role information
username_column The name of the column in the user table that holds the username
password_column The name of the column in the user table that holds the user password for authentication
pw_encoding_class

This LoginModules supports encrypted passwords in the database table . The pw_encoding_class option expects an implementation of the DBLoginModuleEncodingInterface interface to work with. This allows custom password encryption algorithms to be used. Note that the passwords are compared by their encrypted values, not by their unencrypted strings.

The default implementation uses passwords written in clear text. An alternative implementation using SAH1 is provided with the oracle. sample.dbloginmodule.util.DBLoginModuleSHA1Encoder class, which performs a SHA1 encryption plus base64 encoding of the password, using the same string as a key if no extra encryption key is provided. The SQL script " TableLMDbScriptEncryptedPw.sql" provides a testcase that uses SHA1 encrypted passwords.

pw_key Option that, if provided, passes the encryption key to the LoginModule. The key is accessible for the class specified in pw_encoding_class.
roles_column Name of the column in the roles table that holds the user role names
realm_column Optional, the name of the column in the roles table that holds the application realm. The application realm can be used for fine grained authorization. For example, a user may be granted the manager role in app1 but not in app2.
application_realm The name of an application realm that restricts the user role query. This name is optional and is only required in combination with the realm_column. Not specifying a realm makes the LoginModule to read all user roles from the roles table
user_pk_column Name of the primary key column in the user table
roles_fk_column Name of the foreign key column in the roles table
debug debug=true prints authentication process information to the configured logging system, which by default is the console

To configure the DBSystemLoginModule with jazn-data.xml in OC4J 10.1.2, a command similar to the following, based on the provided TableLMDbScriptEncryptedPw example script, needs to be specified on a command line in the OC4J_Home\j2ee\home directory



 java -jar jazn.jar -addloginmodule <application name> 
 oracle.sample.dbloginmodule.DBTableLM.DBTableOraDataSourceLoginModule required 
 debug="true" log_level="ALL" data_source_name="jdbc/OracleDS" user_table="sec_users"
 roles_table="user_roles_view" username_column="username" password_column="password" 
 roles_column="rolename" user_pk_column="userid" roles_fk_column="userid" 
 realm_column="realm" application_realm="Online Trainings" 
 pw_encoding_class="oracle.sample.dbloginmodule.util.DBLoginModuleSHA1Encoder"

 

The J2EE datasource information configured in the OC4J_Home\j2ee\home\config\data-sources.xml looks similar to the following



 <data-source
class="com.evermind.sql.DriverManagerDataSource" name="jdbc/OracleDS" location="jdbc/OracleCoreDS" xa-location="jdbc/xa/OracleXADS" ejb-location="jdbc/OracleDS" connection-driver="oracle.jdbc.driver.OracleDriver" username="scott" password=" ->PwdForScott" url="jdbc:oracle:thin:@localhost:1521:orcl" inactivity-timeout="30"
/>
 

The bootstrap jazn-data.xml file located in the OC4J_Home\j2ee\home\config directory contains the user password, which gets encrypted after restarting OC4J



 <user>
        <name>PwdForScott<
    /name>

    <display-name>PwdForScott<

    /display-name>
        <description>Scott's password<
    /description>
        <credentials>!tiger<
    /credentials>
</user>
 

DBProcLoginModule

Generic LoginModules are hard to write for complex customer environments that leverage their own security schema, if it is not based on two simple database tables. Another use case for this LoginModule is if database encryption capabilities are used to encrypt the user passwords, which also is a better solution then delegating password encryption to the middle tier where it can't be shared across different types of applications.

The DBProcLoginModule handles this more complex usecase and relies on a store database procedure to authenticate users. The granted user roles are provided to the LoginModule through a ref cursor. An example stored PLSQL procedure, taken from the example SQL scripts, looks like

CREATE OR REPLACE PACKAGE "DBPROCLM" IS

TYPE principal_ref IS REF CURSOR;
function get_user_authentication(p_username in varchar2, p_password in varchar2, p_realm varchar2) return principal_ref;
END;

/

CREATE OR REPLACE PACKAGE BODY "DBPROCLM" IS

FUNCTION get_user_authentication (p_username in varchar2, p_password in varchar2, p_realm varchar2)
RETURN principal_ref
AS
var_username varchar2(100);
var_userid number(10);
var_password varchar2(100);
role_cursor principal_ref;
FAILED_AUTHENTICATION exception;
BEGIN
select userid, username, password into var_userid, var_username, var_password from sec_users where username = p_username;
if (var_password = p_password) then
begin
if (p_realm is null) then
open role_cursor for
select rolename from user_roles_view where userid = var_userid;
else
open role_cursor for
select rolename from user_roles_view where userid = var_userid and realm=p_realm;
end if; -- p_realm check
end;
-- if password doesn't match, raise Excpetion for LM to
-- abort the authentication process
else raise FAILED_AUTHENTICATION;
end if;
RETURN role_cursor;
END get_user_authentication;
END;
/

The following JAAS options are case sensitive and can be configured for this LoginModule

Option Meaning

jdbcUrl

The JDBC connect string except for username and password: jdbc:oracle:thin:@host:port:sid

jdbcDriver

The JDBC driver used. The default setting is: "oracle.jdbc.driver.OracleDriver"

logger_class

The class that implements the LMLogger interface to write log information for this LoginModule. Custom logging can be implemented using this option. The default configuration uses oracle.sample.dbloginmodule.util . ScreenLoggerImpl, which writes log messages to the console. The logger_class option can be omitted if console output is sufficient.

A second option provided in the examples are oracle.sample. dbloginmodule.util.JavaLoggerImpl to leverage the java.util.logging package, in which case the location of a Java Logger properties file needs to be specified when starting OC4J or a J2SE application

log_level

This option determines the granularity of the messages that are printed by the LoginModule. If this option isn't provided then all possible messages are written if the "debug" option is set to true. Similar, specifying log_level=ALL prints out all message details. Setting log_level to AUTH will only print the messages that are directly related to the authentication process itself

db_schema

The database schema that holds the user and role tables fro authentication and authorization. The schema itself should be less privileged because of its exposure in the JAAS configuration files.

db_schema_pw

The password to connect to the database schema that holds the authentication and authorization tables. The password is provided in clear text, which is not safe. To make it safe, for J2EE applications it is recommended to use the DBTableOraDataSourceLoginModule.

plsql_procedure

The name of the PLSQL procedure to delegate authentication and authorization to

application_realm

The name of an application realm that restricts the user role query. This name is optional and is only required if the stored procedure supports least privilege access through application specific role grants.

debug

debug=true prints authentication process information to the configured logging system, which by default is the console

Note that the example stored procedure shown above doesn't handle encrypted passwords, which means that testing requires the TableLMDbScriptClearPw.sql to be installed. To configure the DBSystemLoginModule with jazn-data.xml in OC4J 10.1.2, a command similar to the following needs to be specified on a command line in the OC4J_Home\j2ee\home directory



                java -jar jazn.jar -addloginmodule <application name> 
                oracle.sample.dbloginmodule.DBProcLM.DBProcLoginModule required debug="true" log_level="ALL" 
                jdbcUrl="jdbc:oracle:thin:@localhost:1521:orcl" 
                jdbcDriver="oracle.jdbc.driver.OracleDriver" db_schema="scott" db_schema_pw="tiger" 
                plsql_procedure="DBPROCLM.GET_USER_AUTHENTICATION" application_realm="Online Trainings"

DBProcOraDataSourceLoginModule

Similar to what is mentioned for using the DBTableLoginModule implementation, exposing the database password in clear in the JAAS configuration doesn't support secure configuration. For this reason the DBProcOraDataSourceLoginModule supports the use of J2EE data sources for configuring the LoginModule's database connection. In combination with the OC4J password indirection feature, configuration security is provided. The DBProcOraDataSourceLoginModule can't be used with J2SE applications because of its dependency to the data-sources.xml file.

The following JAAS options are case sensitive and can be configured for this LoginModule

Option Meaning
logger_class The class that implements the LMLogger interface to write log information for this LoginModule. Custom logging can be implemented using this option. The default configuration uses oracle.sample.dbloginmodule.util . ScreenLoggerImpl, which writes log messages to the console. The logger_class option can be omitted if console output is sufficient.

A second option provided in the examples are oracle.sample. dbloginmodule.util.JavaLoggerImpl to leverage the java.util.logging package, in which case the location of a Java Logger properties file needs to be specified when starting OC4J or a J2SE application
log_level This option determines the granularity of the messages that are printed by the LoginModule. If this option isn't provided then all possible messages are written if the "debug" option is set to true. Similar, specifying log_level=ALL prints out all message details. Setting log_level to AUTH will only print the messages that are directly related to the authentication process itself
plsql_procedure The name of the PLSQL procedure to delegate authentication and authorization to
application_realm The name of an application realm that restricts the user role query. This name is optional and is only required if the stored procedure supports least privilege access through application specific role grants.
data_source_name Name of the data source configured in the data-sources.xml file
debug debug=true prints authentication process information to the configured logging system, which by default is the console

Note that the example stored procedure shown above doesn't handle encrypted passwords, which means that testing requires the TableLMDbScriptClearPw.sql to be installed. To configure the DBSystemLoginModule with jazn-data.xml in OC4J 10.1.2, a command similar to the following needs to be specified on a command line in the OC4J_Home\j2ee\home directory



java -jar jazn.jar -addloginmodule <application name> 
oracle.sample.dbloginmodule.DBProcLM.DBProcOraDataSourceLoginModule required 
debug="true" log_level="ALL" data_source_name="jdbc/OracleDS" 
plsql_procedure="DBPROCLM.GET_USER_AUTHENTICATION" application_realm="Online Trainings"

The J2EE datasource information configured in the OC4J_Home\j2ee\home\config\data-sources.xml looks similar to the following



<data-source
        class="com.evermind.sql.DriverManagerDataSource"
        name="jdbc/OracleDS"
        location="jdbc/OracleCoreDS"
        xa-location="jdbc/xa/OracleXADS"
        ejb-location="jdbc/OracleDS"
        connection-driver="oracle.jdbc.driver.OracleDriver"
        username="scott"
        password=" ->PwdForScott"
        url="jdbc:oracle:thin:@localhost:1521:orcl"
        inactivity-timeout="30"
/>

The bootstrap jazn-data.xml file located in the OC4J_Home\j2ee\home\config directory contains the user password, which gets encrypted after restarting OC4J



                <user>
                <name>PwdForScott</name>  
                <display-name>PwdForScott</display-name>                                       
                 <description>Scott's password</description>   

                <credentials>!tiger</credentials>                                   
                 </user>
                

Writing log information

Setting the JAAS LoginModule's debug option to true prints out logging messages during the authentication process. The granularity of the printed message can be configured using the log_level LoginModule option, which can be set to "ALL" or "AUTH". The "AUTH" value prints only the information required to document the authentication process.

fig5

For logging, all database JAAS LoginModules support a pluggable logging infrastructure, which by default uses an implementation of System.out.println() to write the log output to the console. An implementation that leverages the java.util.logger package is provided as an alternate logging provider. To write a custom logger class, the LMLogger interface needs to be implemented. To use a logger instance other than the default, the JAAS LoginModule option logger_class is set to a value of "oracle.sample.dbloginmodule.util.JavaLoggerImpl " or any other custom logger class. For the java.util.logging.Logger class implementation to work, the application needs to be started with the -Djava.util.config.file command line option. The referenced config file needs to be a valid Java Logger properties file, as defined in the J2SE documentation.

The Oracle OC4J default logging is based on the J2SE 1.4 java.util.logging as well. This means that even if the JAAS LoginModules uses System.out.println() for logging, messages get written to the java.util.logging.Logger class. To customize the logging output format, a Logger properties file can be specified when starting OC4J with the -Djava.util.config.file option

java -Djava.util.logging.config.file=<OC4J Home>\j2ee\home\config\<logger file name>.properties -jar oc4j.jar

Note that using the database LoginModules with J2SE applications requires the -Djava.util.logging.config.file to be specified with the application start command if messages should be written with the java.util.logging.Logger class. An example properties file is provided in the JDeveloper 10.1.2 LoginModuleTestCase project contained in the demo downloads.

Using the provided ANT scripts for configuration

To ease the task of installation and administration, an Ant script is provided that can be used to configure the various LoginModules provided with this paper. The scripts requires Apache Ant version 1.6 or above.

The Ant scripts are located in the JDeveloper1012Workspaces\DatabaseLoginModule1012 directory contained in the demo sources zip file. The scripts must be executed within this directory because all the required deployment sources and SQL scripts are addressed relative to that location. The benefit of storing the scripts within the DatabaseLoginModule1012 directory comes from this directory also being the Oracle JDeveloper 10.1.2 workspace directory. This way the scripts can be used to deploy custom modifications of the LoginModules to OC4J without having to copy the source files to other locations. Note that the source files and scripts are provided as they are. You can use them as a starting point for custom LoginModule development.

What the Ant Script does for you

The primary function of the supplied Ant script is to eliminate typing errors in the long commands needed to add LoginModules using jazn.jar. The script has a set of pre-built targets, one for each flavor of LoginModule documented in this paper. All of the settings such as the name of the application that is being secured and the connection information are defined in the build.properties file which you need to customize before running the script.

As well as installing (and removing) login modules the script also ensures that the custom LoginModule jar file is put in the correct place in the OC4J directory structure, and it will also set up the database schema objects used by the demo application if required.

Note that there are still some manual tasks that you will need to carry out when using this script:

  • You must edit the DatabaseLoginModule1012\build.properties file to define your environment and settings
  • You must still manually your OC4J application.xml file to add the entry for the custom LoginModule jar file
  • You must manually define any DataSources that you may be using in the OC4J data-sources.xml

Running the Ant Script

For convenience a simple DOS batch file is provided for windows users run.bat. This simply acts as a wrapper to run the supplied Ant build script. To use this batch file, set the environment variables JAVA_HOME and ANT_HOME to point to the Java SDK directory and the Ant install directories respectively. You can set these values from the command shell using the SET command, or you can edit the REM'ed out values in the DatabaseLoginModule1012/run.bat file, (don't forget to uncomment the settings by removing the REM string in front of it). Once theses variables are set you type run at the command prompt and the usage screen for the script will display:

fig6

To carry out a specific action, such as installing the demo tables with clear-text passwords, type run followed by the name of the target as specified by the usage screen. In this case run demoClear. Note that the run targets are case sensitive.

If you are not running on a Windows platform you can still run the Ant scripts by directly invoking the ant command from the DatabaseLoginModule1012 directory. You should again set JAVA_HOME and ANT_HOME in your environment shell before doing so. The command to run is $ANT_HOME/bin/ant demoClear to install the demo tables as above.

About the demos that use encrypted user passwords

The Ant script does support the installation of the sample SQL script with the encrypted passwords in it. It doesn't however configure the LoginModules. To test it, configure the DBTableLoginModule by running the run table command. Open the jazn-data.xml file and add



                <option>   
                <name>pw_encoding_class</name>
                <value>oracle.sample.dbloginmodule.util.DBLoginModuleSHA1Encoder</value> 
                </option>
                

to the configuration before starting up OC4J.

Testing the Ant Script

The JDeveloper1012Workspaces\DBLMTest directory also is an Oracle JDeveloper 10.1.2 workspace directory. It contains a J2EE application that you can use for testing. Deploy the application to the OC4J instance you configured with the Ant Script and it will create an application "foo" that is by default the configuration name used in the scripts.

Request the application after deployment by typing the following URL

http://servername:port/foo-webcontext/authtest.jsp

If you deployed the DBSystemLoginModule, provide a valid database schema username and password in the authentication dialog. If you use one of the other LoginModules, assuming you installed the example SQL scripts, try Han Solo as a username and welcome2 as the password. See a list of all user accounts here.

Note: Please read the comments provided in the build.properties file.

SQL Injection detection

With the first invention of keys and locks, a breed of people was born that never learned to accept "no" for an answer. This group of users typically tries to explore a system for what's beneath, trying to break in to what they normally aren't granted access to. One way of doing this is to use SQL injection, which is an act of entering SQL commands where developers expect username and passwords to be provided. The database LoginModules provided with this document use prepared statements when querying the underlying database, which should be safe. To better secure the JAAS LoginModule implementation, regular expression is used to analyze the provided username and passwords strings for possible SQL injection attacks. The LoginModules will immediately stop processing authentication the authentication when one of the defined SQL key words is found as part of the user login. This solution is not 100 % perfect and may not resist the attempt of a skilled hacker, but it helps keeping out the wannabe's.

// SQL INJECTION DETECTION

// Detects and reports SQL injection attempts. The following code logs all attempts to enter
// SQL commands like create, drop, update, delete, insert, hexadecimal encoded characters etc.
// and immediately returns false

Pattern p = Pattern.compile("(?i)\\bselect|create|insert|delete|drop|update|or|%.\\d\\b");
Matcher m = p.matcher(username);

if (m.find())
{
//someone tries to break into this application and should be tracked back
log("SQL Injection attempt detected: username was altered to include SQL keyword: "+m.group(),LOG_AUTH);
return false;
}

All database LoginModules that perform authentication based on user and role tables contain this code snippet. The regular expression can be extended to filter even more SQL key words if needed.

Working with the LoginModuleTestCase project in Oracle JDeveloper 10.1.2

The Oracle JDeveloper 10.1.2 LoginModuleTestCase project is contained in the "DatabaseLoginModule1012" workspace and allows instant LoginModule testing to be performed. For this, the LoginModule configuration is stored in a text file "jaasTestConfig.txt" that is part of the JDeveloper project as well. This file contains named configuration sections and can be edited with a text editor or within Oracle JDeveloper directly.

Executing the JaasTester.java file performs the LoginModule functional testing, writing all messages to the JDeveloper output window. Testings scenarios are defined in the class constructor and can be enabled by uncommenting the code line. Each test references a configuration in the jaasTestConfig. txt file.



/* Database Schema Users */
// lc = new LoginContext("DBTableLoginModuleTest", pcbh);

/* Clear Text Passwords in User Table */
// lc = new LoginContext("DBTableLoginModuleJavaLogger", pcbh);

/* Encrypted Passwords in User Table */
//lc = new LoginContext("DBTableLoginModuleJavaLoggerEncrPw", pcbh);

/* Authentication using stored procedure */
lc = new LoginContext("DBProcLoginModuleJavaLogger", pcbh);

In addition, the LoginModuleTestCase project contains the two example SQL scripts to populate a database schema with the example user and role tables. All test entries in the jaasTestConfig.txt file that have the "EncrPw" string in their name require the script TableLMDbScriptEncryptedPw.sql to be used.

fig7

The main method of the JaasTester class performs the authentication when instantiating the JaasTester. The username and password pair to test is provided in the constructor, allowing multiple accounts to be tested within one execution.

The DbLoginModuleFileLogging.properties entry in the LoginModuleTestCase project enables testing of the java.util.logging package, using the logger_class="oracle.sample.dbloginmodule.util.JavaLoggerImpl option in the jaasTestConfig.txt JAAS LoginModule configuration. For example, to switch between an XML formatted log and a plain text log, the following two lines contained in the logger properties file can be switched:

#java.util.logging.ConsoleHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

Testing the LoginModules in OC4J using the DBLMTest J2EE web application

To make it easy to get started with deploying the custom database login modules, a J2EE web application is provided in a separate Oracle JDeveloper 10.1.2 workspace, named DBLMTest. The testcase only contains one project with one JSP file that shows a table listing the name of the authenticated user and the granted J2EE security roles. The logon is configured to use BASIC authentication. To use this application, the following steps should be followed

  1. Deploy and configure the custom database LoginModule JAR file to OC4J
  2. Configure the bootstrap jazn-data.xml file to include the LAAS LoginModule configuration for the "DBLMTest" application
  3. Create a OC4J connection in Oracle JDeveloper 10.1.2
  4. Deploy the DBLMTest project from JDeveloper 10.1.2 to OC4J using the project's DBLMTest. deploy entry
  5. After successful deployment, run the URL http://<server name>:8888/DBLoginModuleTest/authtest.jsp

The following screen is shown when running the example and authenticating as "Han Solo" with a password of "welcome2"

fig8

Troubleshooting

We did our best to describe the configurations of the LoginModules and also provided an Ant configuration script for you to use. To expect the unexpected, this section is about troubleshooting the situation in which the custom J2EE application cannot be authenticated and the logon screen keeps on showing.

Enable debugging

All the provided LoginModules can print debug messages to the OC4J console window. To enable debugging, the debug flag needs to be set to true in the jazn-data.xml file configuration.

<options>

<option>
<name>debug</name>
<value>true</value>
</option>
<option>
<name>log_level</name>
<value>ALL</value>
</option>
</options>

If no debug messages are written

If no debug messages are written then chances are that either the J2EE application name doesn't match the case sensitive name specified in the LoginModule configuration or that the JAR file containing the LoginModules is not accessible in OC4J.

jazn-data.xml

Verify that the jazn-data.xml file located in the OC4J_Home\j2ee\home\config directory contains the LoginModule configuration for the J2EE application. The name of the JAAS LoginModule configuration should be exactly the same name you provided in the Enterprise Application Name option of the deployment profile configuration. Note that the enterprise application name does not represent the web context root. The name of the enterprise application and the web context root can be same but don't have to be.

Note The jazn-data.xml file that gets deployed with the project is not used and can be omitted completely.

Wrong location of DBLoginModule.jar

The Java Archive file (JAR) that contains the custom LoginModule needs to be copied to the OC4J_Home\lib directory and configured in the OC4J_Home\j2ee\home\config\application.xml to be available for all web applications deployed on a OC4J instance.

<library path="../../../lib/DBLoginModule.jar"/>

Missing or badly configured orion-application.xml file

The orion-application.xml file defines that custom LoginModules should be used by OC4J for J2EE authentication and must be added to and deployed with the Oracle JDeveloper project. A missing orion-application.xml file disables custom JAAS authentication and enforces the default container managed authentication.

If debug messages are written

Debug messages indicate success of the JAAS LoginModule configuration. The information provided should be explicit enough for you to track down the problem. For security reasons the debug statement doesn't print any user passwords, even for failed login attempts.

[DBSystemLoginModule] Error: Io exception: The Network Adapter could not establish the connection

Start the database and make sure the TNS listener is working

[DBSystemLoginModule] Error: Io exception

ORA-12505, TNS:listener does not currently know of SID given in connect descriptor The Connection descriptor used by the client was:
localhost:1521:orcls

Make sure the database information provided in the jdbcUrl configuration option of the LoginModule is correct.

[DBTableLoginModule] Error: ORA-01017: invalid username/password; logon denied

You are using one of the table or PLSQL stored procedure based LoginModules. The database schema access information provided for the LoginModule to access the user and role tables is not correct.

You can't find the encryption class to create encrypted passwords

One of the sample SQL scripts creates database user tables with encrypted passwords. The file used to encrypt the data is not provided. Modern encryption is based on algorithms that are publicly known and encryption keys that are kept secret. The encryption in the example uses a very weak key that should not be used in production. We've seen many lines of demo code getting copied unchanged into production code sources so that we decided to not publish this part of the example. The JAAS LoginModules that authenticate against tables with encrypted passwords are configurable to use custom encoding classes to work with custom encryption.

Downloads

The jaasdatabaseloginmodule.zip file contains two JDeveloper 10.1.2 workspaces. The "DatabaseLoginModule1012" workspace contains the JAAS LoginModules and the JaasTester project with the SQL scripts mentioned throughout this paper. The "DBLMTest" workspace contains the J2EE application shown above that can be used to test the JAAS LoginModules with OC4J. It is strongly recommended to use the password indirection feature for all JAAS LoginModules that otherwise would expose user passwords in their configuration. The JAAS LoginModules are also made available in a separate JAR file.

In addition to the LoginModule and JDeveloper source files, the zip file also contains ANT scripts to automate the configuration of JAAS LoginModules in OC4J. Note that the Ant scripts require at least Ant version 1.6.

Download