For one of the projects I was recently involved in, we had to implement JAAS based authentication & authorization for our JSF Web Application, and we wanted to base it on the tables in our own application specifying the usernames and their roles. The users and roles can be managed through the application itself – instead of from some management console in the application server or worse still in some XML file in the middle tier.
Since we initially created the application with standard JAAS based authentication, we did not need to change a thing in the application itself, in order to switch from standard JAAS (file based in OC4J) to database based JAAS. This article describes how we implemented a database package that provided the functionality required by a custom JAAS Database powered Login Module and configured it in all of JDeveloper 10.1.3 embedded OC4J, standalone OC4J 10.1.3.1 and OPMN managed OC4J. You might want to first read the article Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 in which I describe in detail how a Web Application can be configured to use JAAS in general for Authentication and Authorization.
Note: an important part of the inspiration for this article comes from Duncan Mills and Frank Nimphius in their OTN article:Declarative J2EE authentication and authorization with JAAS.
In this article, we will first create the most incredibly simple web application in the world. It is not about this web app, the focus for this article is on the JAAS Custom LoginModule and how to make it work for you. We will be using JDeveloper 10.1.3; anything I write applies to 10.1.3.x as well, as far as I have been able to establish.
Create an extremely simple Web Application
Here are the steps for implementing a secure web application:
1. Create a new application in JDeveloper 10.1.3
2. Create a new project inside this application
3. Create a new JSP with simple content – that includes the name of the currently logged in (JAAS) user
Go through the New JSP wizard:
And write the content for the JSP:
4. Configure Authentication and Authorization for this Web Application in the web.xml:
With these simple entries – security-constraint for specifying the URL patterns to protect and the roles that have access, login-config to configure the login method (in this case a Login.jsp) and security-role for each role that should be supported by the application and its authorization infrastructure – we have made our web application a ‘secure’ one. Note though that we now have to change our focus to the Application Server where we deploy our application in order to specify who are the users and what roles they have.
Configure JAAS Database Login on JDeveloper 10.1.3 Embedded OC4J
Since we have developed our web application in JDeveloper 10.1.3, we probably want to first try it out on the embedded OC4J server in JDeveloper. To that end, we have to configure our (well, actually Frank’s and Duncan’s) JAAS Database LoginModule for the embedded OC4J.
1. Copy the DBLoginModule.jar file (see download under Resources at the end of this article) to an appropriate directory, for example JDEV_HOME\jdev\lib.
2. Edit the application.xml file in JDEV_HOME\jdev\system\oracle.j2ee.10.1.3.36.73\embedded-oc4j\config
In this file, we have to create a new library definition, to make the DBLoginModule.jar available to the OC4J instance and the applications running in it. We also have to configure JAAS: specifying the fact that we are using a custom loginmodule.
There are two things in this fragment you should care about: the library element:
and the jazn-provider element:
<jazn provider="XML"><br /> <property name="custom.loginmodule.provider" value="true"/><br /> <property name="role.mapping.dynamic" value="true"/><br /></jazn><br />
3. Configure the system-jazn-data.xml file for the current-workspace-app
The JDEV_HOME\jdev\system\oracle.j2ee.10.1.3.36.73\embedded-oc4j\config\system-jazn-data.xml file is used to configure the Custom LoginModule. Here we specify the class to be invoked by the Application Server when authentication is to be performed or a check if a user has a role must be performed. In our case, that is the oracle.sample.dbloginmodule.DBProcLM.DBProcOraDataSourceLoginModule that is in the DBLoginModule.jar that we downloaded from the OTN article by Frank and Duncan.
We also have to provide some configuration details for this LoginModule. The class we are using – DBProcOraDataSourceLoginModule – expects two parameters: data_source_name and plsql_procedure. The data_source_name refers to the JNDI name of a JDBC data source configured on the OC4J instance. This data source should provide access to a database schema that contains the PL/SQL function specified in the second parameter plsql_procedure. This second parameter refers to a stored function, possibly part of a package, that implements the following interface expected by the DBLoginModule.jar (or more specifically, the DBProcOraDataSourceLoginModule class):
function <whatevernameyoufancy><br /> ( p_username in varchar2<br /> , p_password in varchar2<br /> , p_realm in varchar2)<br /> return principal_ref <br />
where the cursor returned is one that has two columns: a user identification and a role name. Note that the function should raise the FAILED_AUTHENTICATION exception if the p_username + p_password combination does not constitute valid login credentials.
4. Configure a JDBC Data Source on the Embedded OC4J instance
Configuring the data source is straightforward:
5. Implement the the plsql_procedure Stored Function
This function is where you implement the custom authorization logic. Here you specify how a username and password are authenticated and how it is determined which roles the user has. You can write complex queries against your very own application tables. Or do really anything you feel appropriate for your application. Here we use a very simple standalone implementation of the
CREATE OR REPLACE PACKAGE BODY "JAAS_UTILS" IS<br /><br /> FUNCTION get_user_authentication (p_username in varchar2, p_password in varchar2, p_realm in varchar2)<br /> RETURN principal_ref<br /> AS<br /> var_username varchar2(100);<br /> var_userid number(10);<br /> var_password varchar2(100);<br /> role_cursor principal_ref;<br /> FAILED_AUTHENTICATION exception;<br /> BEGIN<br /> select id<br /> , username<br /> , password<br /> into var_userid<br /> , var_username<br /> , var_password<br /> from ( select 1 id , 'ME' username ,'ME' password from dual<br /> union<br /> select 2 id , 'YOU' username ,'YOU' password from dual<br /> union<br /> select 3 id , 'HIM' username ,'HIM' password from dual<br /> )<br /> where username = p_username<br /> ;<br /> if (var_password = p_password)<br /> then<br /> begin<br /> -- do not cater for different realms for the moment<br /> open role_cursor for<br /> select rle<br /> from ( select 1 usr_id, 'MANAGER' rle from dual<br /> union<br /> select 1 usr_id, 'USER' rle from dual<br /> union<br /> select 2 usr_id, 'USER' rle from dual<br /> union<br /> select 3 usr_id, 'ADMIN' rle from dual<br /> union<br /> select 3 usr_id, 'MANAGER' rle from dual<br /> union<br /> select 3 usr_id, 'USER' rle from dual<br /> )<br /> where usr_id = var_userid<br /> ;<br /> end;<br /> -- if password doesn't match, raise Exception for LM to<br /> -- abort the authentication process<br /> else raise FAILED_AUTHENTICATION;<br /> end if;<br /> RETURN role_cursor;<br /> END get_user_authentication;<br />END JAAS_UTILS; <br />
This function sets up three different users: ME, YOU and HIM (with each the same password as username). ME has roles MANAGER and USER, YOU only has (or should that be have?) the USER role while HIM has ADMIN, MANAGER and USER. Note that the names of these roles should match the roles specified in the security-role elements in the web.xml file of our application.
6. Running the SecureWebApp on the Embedded OC4J Server
Let’s run the web application – or more specifically the SecuredPage.jsp – from within JDeveloper, by simpling selecting Run from the Right Mouse Button Menu on this JSP. Since we have specified a security constraint in the web.xml file that protects this JSP, we will first be presented with the Login.jsp that we specified in the web.xml:
Once we provide the credentials and press the Inloggen button (sort of Dutch for Login), our custom JAAS DatabaseLoginModule kicks in to perform authentication and authorization. From the logging in the Console we can see what is happening:
Once authenticated and authorized we see our JSP:
Deploying and Configuring on Standalone OC4J 10.1.3
Deployment on a standalone OC4J instance is slightly different from deployment on the Embedded OC4J server. First, in order to deploy our web application, we will create a WAR file. In JDeveloper, this is most easily accomplished through a Deployment Profile. From the New Gallery, let’s create a new WAR File deployment profile:
Specify the name of the Profile:
And specify name and location of the WAR profile:
Copy the DBLoginModule.jar to the j2ee\home\lib directory on the standalone OC4J 10.1.3.1 instance:
And configure the JAR as new library in the application.xml:
Start the standalone OC4J instance
Go to the Enterprise Manager Console
And deploy our Web Application through the SecureWebApp.war.
Once the application is deployed, we can try to access the SecuredPage.jsp from our browser:
However, no matter what we try, we can not into the application. Logging in does not lead to successful authentication – as we have not yet configured our JAAS login details.
Well, we know from before that we need to do the following things:
- define the Custom JAAS LoginModule for this web application
- define the data-source
- specify the parameters data-source-name and plsql-procedure
All of this can be done through the Enterprise Manager console:
First of all, let’s create a new Managed Connection Pool for the database schema that contains the PL/SQL package JAAS_UTILS (where else than in the SCOTT schema)?
Select New Connection Pool and press Continue.
Specify the connection details for this Pool. Press Finish.
Next we create a Data Source based on this Pool:
and step two:
Now it is time for configuration of the Security Provider for our SecureWebApp (under the Administration option for the SecureWebApp application, there is an option to edit the Security Provider) :
Press Change Security Provider:
Select the Custom Security Provider value from the Security Provider Type drowdownlist. Specify the JAAS Login Module Class – the s
odule class we used before. Then create two properties for the two parameters plsql_procedure and data_source_name with appropriate values. The data_source_name is the JNDI name (that is including jdbc/) for the DataSource we created in the previous step.
When done, press OK. The following confirmation is shown.
Restart the web application.
Once the application has been restarted, we can attempt again to gain access to the SecuredPage.jsp. Since the Application Server now can turn to the custom DBLoginModule library to perform Authentication and Authorization, this time we do get in:
Note: we had a lot of trouble with deploying an EAR file including an orion-application.xml that referenced our custom data-sources.xml and jazn-data.xml that configured the custom DBLoginModule as security provider and the data source for accessing the plsql_procedure. It should be possible defining the JAAS setup thus, but we could not get it to work and had to resort to manual setup through the Enterprise Manager console. That is primarily a pain if you frequently do a fresh deployment of the application, as an Undeploy/Deploy will remove the Security Provider configuration.
It should be possible to use the command line interface of the application server to configure the security provider, with a statement such as:
java -jar jazn.jar -addloginmodule SecureWebApp <br />oracle.sample.dbloginmodule.DBProcLM.DBProcOraDataSourceLoginModule <br />required <br />data_source_name="jdbc/SecurityDS" <br />plsql_procedure="JAAS_UTILS.GET_USER_AUTHENTICATION
I have not tried this out though.
Deploying on OPMN Managed OC4J 10.1.3.1 (Oracle Application Server 10g)
Deployment on an OPMN Managed OC4J 10.1.3.1 instance is essentially the same as deploying on a stand alone OC4J. The URLs are slightly different and the Enterprise Manager console has an extra layer (first choose the OC4J instance, then configure within that instance), but otherwise the custom JAAS LoginModule works the same.
Download the Secure Web App demonstrated in this article, along with the JAAS_UTILS package JaasSecureWebApp.zip . Note: you have to add the adf-faces-impl.jar file to the WEB-INF\lib directory yourself in order to run the SecureWebApp.
Download the DBLoginModule.jar from Duncan and Frank’s article. It is part of the jaasdatabaseloginmodule.zip you can download. (I believe that for copyright reasons I cannot make the jar available for download from our own site).
The configuration of a custom loginmodule in the embedded OC4J container for JDeveloper 10.1.3 is in Joh Stegeman – Real World ADF Faces Using a custom login module with JDev 10.1.3
Documentation Oracle Application Server 10.1.3 Custom Login Modules for more background.