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).
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.
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.
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.
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
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.
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
.
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.
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.
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
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.
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.
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"
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 " |
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.
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 " |
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>
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 |
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 |
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"
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>
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.
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.
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:
DatabaseLoginModule1012\build.properties
file to define your environment and settingsRunning 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:
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.
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.
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
DBLMTest
project from JDeveloper 10.1.2 to OC4J using the project's DBLMTest
. deploy
entryhttp://<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"
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
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.
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.