Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3

Implementing JAAS based security – or at least Authentication and (role based) Authorization – in JSF applications is a joint responsibility of the Application and the Application Server.

The Application has to:

  • specify which security roles it recognizes
  • indicate which resources (URLs) are to be secured and to which role(s) each category of resources should be made accessible
  • determine which method of login-challenge is used (the standard browser login-popup or a custom login page)

All of these are indicated in the web.xml file.

In its turn, the Application Server will

  • check for each request if the requested resource is a secured one
  • if it is, it will verify whether the user has already been authenticated in the current session (“do we know who it is?”)
    if not, it will present the login challenge and subsequently attempt authentication using the username and password data submitted by the user
    if authentication fails, either an error page or the login challenge again is presented to the user; no access is given to the requested resource
  • now that it knows who the user is, the application server will determine if the user has at least one of the roles required for accessing this secured resource
    if he/she does – the request is passed on to the application
    if he/she does not – an error code is returned to the browser if not, the request is passed on to the application

OC4J 10.1.3 uses JAAS based authentication and authorization. That means that it relies on an implementation of a more or less standardized interface for authenticating a user from username/password data as well as inspecting the role-membership for a user. The JAAS loginmodule – as this implementation is called – uses some form of repository with user and role data – typically an XML file or a database. The most straightforward implementation of a JAAS loginmodule – and the default on OC4J – uses the system-jazn-data.xml (or application specific jazn-data.xml) repository for storing usernames, (encrypted) passwords and role-memberships. Alternatively OC4J has a LDAP (e.g. OID) based loginmodule as well as the option to configure custom JAAS loginmodules.

In this article, we will see how to implement Authentication and Authorization for the world’s simplest ADF Faces application, that demonstrates all features – including logout, presenting the name of the logged in user and hide & display of elements depending on the role of the current user. We will deploy this simplest of applications on the Embedded OC4J 10.1.3 server in JDeveloper as well as on a Stand-alone OC4J instance. This article only discusses file based (jazn-data.xml) repositories. In a subsequent article we will see how we can use our own custom Database based mechanism for Authentication and Authorization.


Our Application – SecureWebApp – consists of three pages. One is accessible to all users, even the non-authenticated ones. Another is accessible to all roles: normaluser and manager – but contains some elements the normaluser may either not see or modify. The third one is only accessible to the manager.

Step one – Configuring the web.xml file

The web.xml contains three pieces of security related information: which roles matter for the applications, which resources (URL patterns) are to be secured and to which roles is each accessible and finally what login-method is to be used.

Roles in the application

These are defined in the security-role element within the web-app element:

    <security-role>
        <description>Normal User</description>
        <role-name>normaluser</role-name>
    </security-role>
    <security-role>
        <description>Administrator, Super User</description>
        <role-name>manager</role-name>
    </security-role>

Secure(d) Resources

Using security-constraints we specify the URL patterns of categories of secure resources – indicating for each category to which roles access is available.

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>SuperSecurePages</web-resource-name>
            <url-pattern>faces/page/SuperSecure/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>manager</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Normal Secure Pages</web-resource-name>
            <url-pattern>faces/page/NormalSecure/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>normaluser</role-name>
            <role-name>manager</role-name>
        </auth-constraint>
    </security-constraint>

Here we have created two constraints, for the NormalSecure resources and SuperSecure resources. For each category, we have specified the roles that are allowed to access the resources.

Login Configuration

The final piece of setup to perform in the web.xml file is specifying the way for the user to provide credentials. Using the login-config element in the web.xml, we can choose from four methods of login. The one we use is the custom login-page: we provide a JSP that the user can use to login:

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

JDeveloper provides a wizard style interface for creating all these entries in the web.xml file. Open the right mouse button menu on web.xml, select the option Properties and the editor pops up. Editing Security Constraints looks like this:

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas3

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas4

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas5

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas6

 

Step two – Create the Login page

The Login.jsp we have configured in the previous step can be any page we like, with our very own format. There are just a few requirements, to ensure that the Application Server can recognize the credential-information and request Authentication from the JAAS loginmodule. These requirements are:

  • a form with action=j_security_check
  • input element called j_username
  • input element called j_password

A very simple implementation of our Login.jsp could look like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=UTF-8"%>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Login</title>
  </head>
  <body style="font-family:sans-serif; background-color:rgb(214,231,255); color:rgb(0,0,255);">
          <form action="j_security_check" method="post">
      <span style="font-size:xx-large; font-weight:bold;">
        The Secure Application
      </span>
      <hr/>
      <h2>
        Login:
      </h2>
      <table cellspacing="3" cellpadding="2" border="0" width="100%">
            <tr>
              <td width="120">
                <b style="whitespace:nowrap">Username</b>
              </td>
              <td>
                <input type="text" name="j_username"/>
              </td>
            </tr>
            <tr>
              <td width="120">
                <b>Password</b>
              </td>
              <td>
                <input type="password" name="j_password"/>
              </td>
            </tr>
            <tr>
              <td>&nbsp;</td>
              <td>
                <input type="submit" name="logon" value="Login"/>
              </td>
            </tr>
          </table>
         </form><p>
      (c) AMI
S - (2002-20
06) - 
      <a href="http://www.amis.nl">
        http://www.amis.nl
      </a>
    </p></body>
</html>

When executed, this page looks as follows:

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas7

Step 3a – (optional) Configuring the Users and their Roles with the application

Typically all users and their roles will be managed by the Application Server administrator, typically through the Enterprise Manager Console or alternatively in the configuration files such as application.xml and system-jazn-data.xml. However, when the the (initial) list of users is known in advance, it can be configured in the application before deployment to save work after deployment. Especially in a development environment with frequent deployment on the Embedded OC4J server in JDeveloper, this can be very convenient.

In our example, we create a file called jazn-data.xml in the src\META-INF directory of our project. Note: a convenient way of correctly creating this file is from the New Gallery in JDeveloper: New, General – Deployment Descriptors, OC4J Deployment Descriptor Wizard – pick option jazn-data.xml in Step 1 of 2 in this wizard. Our file looks like this:

<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<jazn-data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/jazn-data-10_0.xsd"
           filepath="" OC4J_INSTANCE_ID="">
 <!-- JAZN Realm Data -->
 <jazn-realm>
  <realm>
   <name>jazn.com</name>
   <users>
    <user>
     <name>me</name>
     <credentials>!me</credentials>
    </user>
    <user>
     <name>you</name>
     <credentials>!you</credentials>
    </user>
    <user>
     <name>her</name>
     <credentials>!her</credentials>
    </user>
   </users>
   <roles>
    <role>
     <name>manager</name>
     <members>
      <member>
       <type>user</type>
       <name>me</name>
      </member>
     </members>
    </role>
    <role>
     <name>normaluser</name>
     <members>
      <member>
       <type>user</type>
       <name>me</name>
      </member>
      <member>
       <type>user</type>
       <name>her</name>
      </member>
      <member>
       <type>user</type>
       <name>you</name>
      </member>
     </members>
    </role>
   </roles>
  </realm>
 </jazn-realm>
 <!-- JACC Repository Data -->
 <jacc-repository/>
</jazn-data>

In order to ensure that this application specific jazn-data.xml is picked up by the application server (and its contents merged into the system-jazn-data.xml file on the application server) we have to also create an application specific orion-application.xml file. This file can be initiated from the New Gallery in the same way as the jazn-data.xml file. It should look like this:

<?xml version = '1.0' encoding = 'UTF-8'?>
<orion-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.oracle.com/technology/oracleas/schema
                   http://xmlns.oracle.com/oracleas/schema/orion-application-10_0.xsd" version="10.0"
                   xmlns="http://www.oracle.com/technology/oracleas/schema">
  <jazn  provider="XML" location="./jazn-data.xml" default-realm="jazn.com"/>
</orion-application>

and be located also in src/META-INF.

Step 3b – (alternatively) Configure the Users and their Roles with the application server

Instead of creating our own application specific jazn-data.xml file, we can also add the information from that file directly to the system-jazn-data.xml file on the application server (OC4J_HOME\j2ee\home\config or JDEV_HOME\jdev\system\oracle.j2ee.10.1.3.36.73\embedded-oc4j\config for the embedded OC4J server in JDeveloper) or indirectly through the Enterprise Manager console.

Step 4 – Create the application’s pages

Okay, typically you would probably have created the application’s pages by now. In fact, configuring security and developing the application itself can largely be parallel processes. Only when elements inside pages should be dynamically switched on or off depending on the level of authorization of the current user is the application impacted by the security set up.

in this example I have created three very simple (and I really mean very simple) JSF JSP pages with minimal content, just to show the idea.

Step 5 – Deploy and Run the Application

From within JDeveloper, we can now simply run any of the pages in our web application. If it is a secured one, we will be sent to the Login page by the application server. If not, we can access it directly.

We can also package the application in a WAR file (or EAR) and deploy it on the OC4J application server. Note that the orion-application.xml and jazn-data.xml file are only included in the EAR file, not in the war.

Useful Security related extensions

We will discuss a number of security related features that you probably will want to implement in your ADF Faces application. The JDeveloper Application you can download at the end of this article implements all of these features, to give you a working example of what they look like.

Displaying the currently logged in user

The name of the currently logged in user is readily available in your application. In JSF application, we can use the following EL expression to access the username:

#{facesContext.externalContext.userPrincipal.name}

The ADF PanelPage element has a facet that is specifically designed in the BLAF guidelines to display the user:

<f:facet name="infoUser">
  <af:outputFormatted value="logged in as #{facesContext.externalContext.userPrincipal.name}" />
</f:facet> 

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas8

Adding a Logout facility to the application

Being able to login to an application is certainly useful if we want to make use of JAAS based Authentication and Authorization. Being able to logout again – and possibly login as another user – is also quite useful, especially during development of the application as well as for applications that will have end-users who can take on multiple identities. Logging out effectively means giving up the identity associated with the current session. This can be done with a little code in a managed bean, that we can associate with a logout link or button.

The method that logs a user out of his current identity looks like this:

public void logout() throws IOException {
    ExternalContext ectx =
    FacesContext.getCurrentInstance().getExternalContext();
    HttpServletResponse response =
    (HttpServletResponse)ectx.getResponse();
    HttpSession session = (HttpSession)ectx.
getSes
sion(false);
    session.invalidate();
}

In our sample application, we have configured a Managed Bean called security:

<managed-bean>
  <managed-bean-name>security</managed-bean-name>
  <managed-bean-class>nl.amis.infrastructure.SecuritySupporter</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

The bean implementation is like this:

package nl.amis.infrastructure;

import java.io.IOException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SecuritySupporter {
    public SecuritySupporter() {
    }
    
    public String logout() throws IOException {
        ExternalContext ectx =
        FacesContext.getCurrentInstance().getExternalContext();
        HttpServletResponse response =
        (HttpServletResponse)ectx.getResponse();
        HttpSession session = (HttpSession)ectx.getSession(false);
        session.invalidate();
        // redirect is with regard to current page
        // if we want to use an absolute path (starting with /), then we have 
        // to include the context root such as SecureWebApp-SecureApp-context-root
        response.sendRedirect("../PublicPage.jspx");
        return null;
        }
}

To complete the Logout feature, we add the following button to the Global Menu in our secure pages:

<f:facet name="menuGlobal">
  <af:menuButtons>
    <af:commandMenuItem text="Logout" action="#{security.logout}" icon="/logout.gif"/>
  </af:menuButtons>
</f:facet>

The button’s action ties to the logout method on the security bean.

Role-based Disabling and Enabling of UI Elements

In order to bind properties like disabled and rendered to the roles a user may or may not have, we will use JSF EL expressions that somehow refer to the roles for which an element is visible/invisible or enabled/disabled. We cannot ask the JAAS security module for a list of all roles a user has; all we can do is ask whether he has a specific role. A method we could easily implement is something like this:

public boolean isUserInRole(String role) {        
  return FacesContext.getCurrentInstance().getExternalContext().isUserInRole(role);
}

Unfortunately we cannot call it directly from an EL Expression – as we cannot pass a parameter from an EL expression to a method.

That is a challenge I solved quite some time ago – using a Map implementation. See for details an earlier article on this weblog: How to call methods from EL expressions- pre JSP 2.0 trick for JSPs with JSTL. This means that if our backing bean implements the Map interface, we can use EL expressions such as #{backingBean[‘rolename’]} that will call the get(Object key) method on the backing bean. In this methodm, we can do with the key parameter whatever we like – such as call the isUserInRole method – and return its result.

To turn our SecurityProvider class into a Map, select the option Implement Interface from the Source Menu and enter the java.util.Map interface. JDeveloper will create stub implementations of the required methods in the Map interface. We only care about the get method, implementing it like this:

public Object get(Object key) {
  return isUserInRole((String)key);
}

Now we can start disabling JSF elements using expressions such as rendered=”#{security[‘manager’]}” that will display an element only if the current user has the manager role.

For example in the NormalSecuredPage.jspx :

<af:panelHorizontal >
  <af:outputText value="Here is a value that should be visible to any user visiting this page"/>
  <af:panelBox rendered="#{security['manager']}">
    <af:outputText value="And this can only be seen by a user with role manager!" />
  </af:panelBox>
</af:panelHorizontal>

Now if we logon as YOU (not a manager) the page looks like this:

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas1

If we logout and login as ME (of course a manager), the same page now looks like this:

Implement JAAS based Authentication and Authorization for ADF Faces applications on OC4J 10.1.3 jaas2

Easy switching off security (for development/testing purposes)

Now that we have implemented security in our application, there may be times – especially during development and testing – that we wish it would not be there. If the security somehow is buggy, we may not be able to get into our application at all! Fortunately, (temporarily) turning security off is quite simple. Basically, only web resources that match one of the security constraints in the web.xml file are secured. So if we make sure that no security constraints match, the pages can be accessed by non-authenticated users. In our sample application this means that we can turn off authentication & authorization by adding two characters in the web.xml file:

     <security-constraint>
        <web-resource-collection>
            <web-resource-name>SuperSecurePages</web-resource-name>
            <url-pattern>xfaces/page/SuperSecure/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>manager</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Normal Secure Pages</web-resource-name>
            <url-pattern>xfaces/page/NormalSecure/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>normaluser</role-name>
            <role-name>manager</role-name>
        </auth-constraint>
    </security-constraint>

If we have tied the render or disabled property of elements in our page to the roles of our user, we have to take an additional step to switch off security – otherwise since the user is not authenticated and therefore will not have any roles at all, far too many elements will be hidden or disabled. So we want to slightly enhance our SecurityProvider class, to allow switching off the authorization – we can achieve that by always returning true from the get method that is called from the EL expressions like rendered=”#{security[‘manager’]}”.

We add a property roleBasedAuthorization to the SecurityProvider class – with its accessors.

    private boolean roleBasedAuthorization = true;

    public void setRoleBasedAuthorization(boolean roleBasedAuthorization) {
        this.roleBasedAuthorization = roleBasedAuthorization;
    }

    public boolean isRoleBasedAuthorization() {
        return roleBasedAuthorization;
    }

We then modify the get method:

public Object get(Object key) {       
  return (roleBasedAuthorization?isUserInRole((String)key):true);
}

Finally we  add a managed property to the faces-config.xml file, where we switch role based authorization on and off by flipping the value of this property:

  <managed-bean>
    <managed-bean-name>security</managed-bean-name>
    &l
t;mana
ged-bean-class>nl.amis.infrastructure.SecuritySupporter</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>roleBasedAuthorization</property-name>
      <property-class>boolean</property-class>
      <value>false</value> <!-- set to true to turn role-based authorization on -->
    </managed-property>
  </managed-bean>

With this configuration, the get method will always return true and all role dependent elements will act as if the user has the required role.

Accessing the current user inside ADF Business Components

If you make use of ADF Model and ADF Business Components, you have easy access to the current web-user. ADF takes care of setting the value of the user on the Session object. We can use a statement like this:

String currentWebUser = ((SessionImpl)getDBTransaction().getSession()).getUserPrincipalName());

inside for example the ApplicationModuleImpl in our application.

Setting Database Security Context – for example for VPD

It is not unlikely that you not only want to know about the current user in the Model side of the Java Application, but in the database itself as well. Many web applications rely on a backend database and the security – especially horizontal authorization that determines which records are to be returned for the current user – is usually implemented in the database as well. The mechanism used for that horizontal authorization ideally is VPD (Virtual Private Database) that uses an application context and PL/SQL functions that return a policy based on that context. For this to work, the current user typically has to be set in an Application Context, through a PL/SQL package. To make a long story not any longer, the consequence is that we want ADF Business Components to ensure that for any database access that takes place, the current web user is set in the database.

This can easily be achieved by implementing an override of the prepareSession method in your own ApplicationModuleImpl that extends the standard ADF BC one. This prepareSession() method will look like:

protected void prepareSession(Session session) {
      super.prepareSession(session);
      SessionImpl ses = (SessionImpl)getDBTransaction().getSession();
      String appContext = "Begin MY_CONTEXT_PACKAGE.SET_CURRENTUSER('"+ses.getUserPrincipalName()+"'); END;";

     java.sql.CallableStatement st= null;
     try
     {
       st = getDBTransaction().createCallableStatement(appContext,0);
       st.execute();
     } catch (java.sql.SQLException s)
     {
      throw new oracle.jbo.JboException(s);
     }  finally
     {
      try
      {
        if (st!= null)
        {
          st.close();
        }
      } catch (java.sql.SQLException s2)
   }
 }
}

 

 

Resources

The JDeveloper 10.1.3 Application with Secure Web Application demonstrated in this article: SecureWebApp.zip.

Frank Nimphius on J2EE Security: Dynamic user creation for container managed authentication (programmatically maintaining users in the jazn-data.xml file!) http://www.orablogs.com/fnimphius/archives/000937.html

OC4J 10.1.3 Documentation on jazn configuration – http://download-uk.oracle.com/docs/cd/B25221_03/web.1013/b14429/configxml.htm#sthref486

Frank Nimphius on Lifting the confusion: jazn-data.xml vs. workspace-jazn-data.xml http://www.orablogs.com/fnimphius/archives/001763.html

Peter Koletzke Web Application Security Part 1: Implementing the Superstition in JDeveloper (presentation ODTUG 2006)

 

10 Comments

  1. Peter June 24, 2009
  2. Laci P. June 22, 2009
  3. Laci P. June 22, 2009
  4. Laci P. June 22, 2009
  5. zakir May 18, 2009
  6. Vimalan Balan May 10, 2008
  7. Anshuman January 25, 2008
  8. SOnu January 17, 2008
  9. Sonu January 17, 2008
  10. Rob Clevenger December 11, 2006