Buttso Does the BLOG Thing
   Getting down and dirty with OC4J, JMX, Mountain Biking ...

 

Steve Button

Subscribe to "Buttso Does the BLOG Thing" in Radio UserLand.

 

Click to see the XML version of this web page.

Click here to send an email to the editor of this weblog.

 
 

Using Form Based Authentication


It's quite easy to setup and use form-based authentication for Web applications running on OC4J.  Here's how you do it.

The example to go along with this can be found here.

1. Add custom login and error pages to your Web application.

These are simple JSPs, which contain a form to allow a user to enter a username/password. When the submit button is pressed, the values are sent off to a special handler servlet containers implement to authenticate users in the form based authentication model.  If the supplied user is authenticated, then the originally requested URL is loaded. If the authentication fails, the error page is shown.

Note: you must use the exact values shown in the form below for the form action, the username and password fields.

Here's a working example of a login.jsp page

<html>
<head>
<title>Login Page for Example FormBasedAuth</title>
</head>
<body bgcolor="white">
<h2>Custom Login Page</h2>
<hr>

<!--
  This is the custom logon page.  You must use the exact action and form field names
  for a custom logon page.
-->

<form method="POST" action="j_security_check">
  <table border="0" cellspacing="5">
    <tr>
      <th align="right">Username:</th>
      <td align="left"><input type="text" name="j_username"></td>
    </tr>
    <tr>
      <th align="right">Password:</th>
      <td align="left"><input type="password" name="j_password"></td>
    </tr>
    <tr>
      <td align="right"><input type="submit" value="Login"></td>
      <td align="left"><input type="reset"></td>
    </tr>
  </table>
</form>
</body>
</html>
The error.jsp page would look very similar.  Perhaps with the addition of some text to indicate that the logon wasn't successful. Since these pages are JSPs, you can make them look however you need to -- images,  text, colors -- whatever.  It's your logon page.

The logon and error pages need to be put into your web application so they can be loaded by the servlet container when necessary.

A good place to put them so they aren't directly accessible to clients (which they shouldn't be!) is in the /WEB-INF directory.

2. Create a protection scheme for your Web application.

Once you have these pages, you need to configure a security constraaint for a set of resources within the Web application. This basically involves specifying a URL pattern to be protected, definining with authentication method is used to get the user to log on, and specifying a logical user role which is allowed access to the protected resources.

This is all done in the WEB-INF/web.xml file.

First up, lets define the security constraint -- forgive the colors, I was trying to make the sections easily distringuished and the color palette is quite limited.

  <security-constraint>
    <display-name>Example Security Constraint</display-name>
    <web-resource-collection>
      <web-resource-name>Protected Pages</web-resource-name>
      <url-pattern>/*</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
      <role-name>FunkyUser</role-name>
    </auth-constraint>
  </security-constraint>


The tags in purple indicate that we are adding a security constraint for the Web application.

The tags in blue define a protected resource, providing a description and indicating which HTTP methods the protection should apply to.

The tag in red defines the URL of this specific Web context that this protection applies to. In this case, any page requested within the Web application will be protected and require the user to be authenticated before running.

The tags in green define the logical security role that a supplied user must belong to in order to access the protected resource.  The role-name used here is completely up to you, it does not need to map to any specific security roles defined at the J2EE container level.  There must however be a corresponding entry in the web.xml file that actually defines this role-name for the application. See step 4 for more details.

3. Define a login configuration.

This steps basically tells the container how users are to sign on when needing to authenticate to access a protectec resource.  This is where we tell the servlet container that it needs to use your custom logon and error pages.  There are several other options for this;
BASIC, FORM, CLIENT-CERT with each serving a slightly differnet role.  If you used the BASIC method, this results in the browser popping up a dialog box to let users enter a username and password. 

Since you want to use a custom logon page, you need to specify the FORM option, and specify the resources to use to for the logon and error pages.

  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>Example Form-Based Authentication Area</realm-name>
    <form-login-config>
      <form-login-page>/web-inf/login.jsp</form-login-page>
      <form-error-page>/web-inf/error.jsp</form-error-page>
    </form-login-config>

  </login-config>

The blue tags specify which authentication method should be used.  For custom form based logon, set it to FORM..

The green tags specify the details for the form authentication method.  Here you specify the resources to for the login page, and the error page. Note here how the path is set to load the pages from the WEB-INF directory. This serves two handy purposes -- 1) it protects your logon/error pages from direct client access; nothing from the WEB-INF directory is accessible to clients via a direct URL, and 2) it allows you to easily protect the root of your Web application.

4. Define a logical security role-name

Here you are actually declaring the logical security role-name that you used in the step 2 in the security-constraint setting to indicate who is allowed access to the protected resources.

A logical security role-name is just that -- it allows you as a developer to specify protection schemes for resources, without knowing the actual security roles that will exist on the production server.  This makes your application portable and not tied to any one specific environment.

You can pretty much choose any name you want for your logical roles.  The important thing as far as the web.xml file goes is that the name you choose for the logical role-name here

  <security-role>
    <description>A Funky User</description>
    <role-name>FunkyUser</role-name>
  </security-role>

For improved clarity, this security-role tag step could have been listed here before the security contrainst step since it's defines something used later -- but I just replicated what was in my web.xml file......

5. The completed web.xml file.

At this point, you're done with the web.xml file.  Here's a complete example of the file so you can see where the elements all fit.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd">


<web-app>

  <welcome-file-list>

    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <!--

    Define a security constraint and tell it which abstract roles are
    permitted to access this resource
  -->
  <security-constraint>
    <display-name>Example Security Constraint</display-name>
    <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <url-pattern>/*</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
      <role-name>FunkyUser</role-name>
    </auth-constraint>
  </security-constraint>

  <!-- Default a login configuration that uses form-based authentication -->
  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>Example Form-Based Authentication Area</realm-name>
    <form-login-config>
      <form-login-page>/web-inf/login.jsp</form-login-page>
      <form-error-page>/web-inf/error.jsp</form-error-page>
    </form-login-config>
  </login-config>


  <!-- Define a logical role for this application, needs to be mapped to an actual role at deployment time -->
  <security-role>
    <description>A Funky User</description>
    <role-name>FunkyUser</role-name>
  </security-role>

</web-app>
Now I hear you asking, if the logical role-name defines who can access the protected resources, how on earth do I fit my actual users into that?

"That's a good question 99" -- bit of Max Smart there ...

6. Map the logical role-name to an actual security role from OC4J

With OC4J (and all J2EE containers I presume) the administrator can setup lists of actual users with real usernames and passwords. These are defined in XML files, or in some cases stored in LDAP directories.  These real users are typically assigned into groups or roles.  If you look at your OC4J installation, you can see an example of this in the j2ee/home/config/jazn-data.xml file. This is a default repository of users that are available to your OC4J instance.

So what we really need to do is tell OC4J how to map the logical role-name defined in the Web application, to an actual set of users available on OC4J.  OC4J will then be able to join the dots, and validate the logon details entered by a user against the actual user repository, also ensuring that the specified username belongs in the required actual role.

To perform this mapping, you use an OC4J specific deployment descriptor -- for a Web application, this is a file called orion-web.xml.

Now there are a couple of ways you can go from here.  I'll try and explain them.

6a Modify the generated orion-web.xml

Everytime an application is deployed, OC4J generates it's own set of XML deployment descriptors which contain settings that apply specifically to it.  These are additional to the standard J2EE deployment descriptors.

By default, the OC4J deployment descriptors are put into the j2ee/home/config/application-deployments/<app-name>/<web-module> directory, where app-name and web-module are the names from your actual application being deployed.

Once you've deployed your web application, you can find the orion-web.xml file which gets generated for your web module. Opening it in an editor, you should that OC4J has noticed the definition of the logical role in the web.xml file, so it has generated a section to allow you to specify the mapping.

<orion-web-app ...>
   <security-role-mapping name="FunkyUser">
     <group name="" />
   </security-role-mapping>
</orion-web-app>
The security-role-mapping tags allows you to map the logical role-name from web.xml to an actual group/role from the OC4J user repository.

So all you need to do to get this to work is add the name of an actual role from the OC4J user repository to the group tag. 

<orion-web-app ...>
   <security-role-mapping name="FunkyUser">
     <group name="administrators" />
   </security-role-mapping>
</orion-web-app>

For simple testing purposes, you can always use the "administrators" role since this is always defined in the OC4J instance.  This lets you logon to the Web application using the administration user (admin/welcome by default) for your OC4J instance.  If you've modified the admin password using the -install option of OC4J, then enter that password instead.

6b Provide the mapping in the WAR file

The second option is to provide the orion-web.xml file, preconfigured within the WAR file you are deploying. This can be done quite simply by creating the skeleton of the orion-web.xml file with the elements you with to map, and putting it in the /WEB-INF directory alongside the standard J2EE web.xml file.

When you deploy the WAR file, OC4J will notice the orion-web.xml file that is supplied and will use this as a template when it generates the actual file it uses as described in step 6a. 

Providing the file with the orion-web.xml file with the application is a useful tip when you specifically know which actual roles and groups you need to map the Web application to.  It saves you from needing to make post deployment configurations, which is very handy when you are testing out things in development.

Here is an example of a orion-web.xml which is included within the WAR file and which supplies the mapping for the logical role.
<orion-web-app>
    <security-role-mapping name="FunkyUser">
        <group name="administrators"/>
    </security-role-mapping>
</orion-web-app>
This contains just the bare essentials -- OC4J will generate all the other necessary tags and attributes it requires in this file when the application is deployed.

Summary

So that's all there is to it.  Create some JSP pages to gather user logon details, tell the servlet container that you're using form based auth for a specific set of resources, give a logical security role permission to access the resources and finally tell OC4J which of it's actual groups map into the logical role.

I have a zip file HERE you can download which provides the full source code of a simple example using form-based-authentication, mapping the users to the OC4J "administrators" group. 

It has a prebuilt EAR file which can be deployed immediately to your OC4J instance, or you can use the supplied Ant script to rebuild the application and deploy it to a local OC4J instance.'

The prebuilt EAR file is in the build directory. Deploy it using admin.jar or however you usually deploy applications.

To rebuild the source code, use the app target

    >ant app

To deploy the application to a local OC4J instance

    >ant bind-web-app

Be sure to check the property settings at the top of the build.xml file to make sure they correspond to your environment.

To access the application use the URL

   http://localhost:8888/fba

This should present you with the custom login page. 



© Copyright 2004 buttso.
Last update: 4/23/2004; 3:46:51 PM.

Click here to visit the Radio UserLand website.