J3 Limited
 
Google
WWW J3Ltd
 
Using Jaas

Introduction

Jaas is used to secure Java applications. It is part of the core J2SE API. When developing enterprise applications, Jaas is what is used to manage user logon. Jaas manages what parts of the system a given user can access.

This document uses a simple project to illustrate how a JEE application can use Jaas.

All the example code is developed using Eclipse, Jboss 4.0.4 GA and MySQL. The source code can be downloaded as a zip archive file here.

Project Overview

The image on the left shows the project tree. The project is created as an JBoss IDE EJB3.0 project.

The project has one stateless EJB. The EJB contains methods which use annotations to control who can call them.

The jsp's provide the client end to the application, these files are placed in the src/web folder. A login, logout and error page are defined. In addition, folders are created for src/web/admin,src/web/user and src/web/anonymous users. Each one of these folders is mapped to a Jaas security role.

Initially the project uses JBoss's default authentication mechanism and realm (called "other"). This mechanism uses properties files to authenicate users. The roles.properties file lists the roles and which users have the role. The users.properties file lists the users and their login password. Once this is running, a database authentication mechanism is used instead (using a MySQL database).

Eclipse generates two archive files: JaasTests.jar contains the ejb related files, and JaasTests.war contains the web application related files.

The EJB Package

The stateless EJB implementation ( StatelessEJBBean.java) is shown below:

package ejbs;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.*;

@Stateless
public class StatelessEJBBean implements StatelessEJB, java.io.Serializable {
  static final long serialVersionUID = 3;
  
  @PermitAll
  public String anonymousMethod() {
    return "You called the anonymous method";
  }
  @RolesAllowed({"RegularUser"})
  public String userMethod() {
    return "You called the user method";
  }
  @RolesAllowed({"AdminUser"})
  public String adminMethod() {
    return "You called the admin method";
  }
}

JEE 5 introduces annotations, in the above EJB, annotations are used to specify the roles allowed to access the bean's methods. Previous EJB specifications would have required this information to be placed in the deployment descriptor file ejb-jar.xml. It is now possible to do away with the deployment descriptor file ejb-jar.xml altogether.

The remote interface for the stateless EJB implementation (StatelessEJB.java) is shown below:

package ejbs;

import javax.ejb.Remote;

@Remote
public interface StatelessEJB {
    public String anonymousMethod();
    public String userMethod();
    public String adminMethod();
}

The JBoss deployment descriptor file (jboss.xml) is defined as follows:

<?xml version="1.0" encoding="UTF-8"?>
<jboss>
<!-- Bug in EJB3 of JBoss 4.0.4 GA
<security-domain>java:/jaas/other</security-domain>
-->
<security-domain>other</security-domain>
<unauthenticated-principal>AnonymousUser</unauthenticated-principal>
</jboss>

The security domain "other" is defined in the JBoss configuration file JBoss/server/default/conf/login-config.xml. Which will be looked into later on in this document. The security domain other uses properties files to pick up user names, passwords and their associated roles. These files are packaged in the jar as well.

The unauthenticated-principal is set to AnonymousUser. This is to allow the stateless EJB method with the annotation @PermitAll to permit unauthenticated users, in addition to all authenticated users (default).

The users.properties file is shown below:

# org.jboss.security.auth.spi.UsersRolesLoginModule username to password mapping
admin=jboss
user=ejb3

The roles.properties file is shown below:

# org.jboss.security.auth.spi.UsersRolesLoginModule username to roles mapping
admin=AdminUser,RegularUser
user=RegularUser

The ejb is packaged into a jar file. Below is how it looks in Eclipse's package properties:

The layout of the jar file is as follows:

JaasTests.jar
| +-ejbs | | | +-StatelessEJB.class | | | +-StatelessEJBBean.class | +-META-INF | | | +-jboss.xml
| +-jndi.xml | +-users.properties | +-roles.properties

The Web Application Package

The web application consists of jsp pages, html pages and xml deployment descriptor files.

The application's welcome page (index.jsp) is shown below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
                  pageEncoding="ISO-8859-1"%>                 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>Jaas tests</title>
</head>
<body> <jsp:include page="/includes/menubar.jsp"/> <H3>Jaas Tests</H3> <P> The following <A href="anon/anonymousPage.jsp">page</A> is available to anonymous visitors </P> <P> The following <A href="user/userPage.jsp">page</A> is available to users with a logon
</P> <P> The following <A href="admin/adminPage.jsp">page</A> is available to admin users
</P> </body> </html>

The page includes /includes/menubar.jsp this file contains a set of hyperlinks which is displayed in many pages. The hyperlinks highlighted in the above listing point to pages that have been assigned security roles (in the web application deployment descriptor file web.xml). Hence trying to access some of these pages causes Jaas to intervene with the login page login.html:

<html>
  <head>
    <title>Jaas Tests</title>
  </head>

  <body>
    <center><h2>Jaas Tests Login</h2></center>
    <br />
    Please enter your credentials
    <br />
    <form method="POST" action="j_security_check">
       Username: <input type="text" name="j_username"/>
       <br />
       Password: <input type="password" name="j_password"/>
       <br />
       <input type="submit" value="Log me in"/>
    </form>
    <p>
      Administrator username: <STRONG>admin</STRONG> 
        password: <STRONG>jboss</STRONG>
    </p>
    <p>User username: <STRONG>user</STRONG> password <STRONG>ejb3</STRONG></p>
  </body>
</html>

The highlighted parts of the login page above are all defined in the Jaas specification.A form based login must have an html page with a form whose action is j_security_check, a username input field named j_username and a password input field named j_password must also be present. Jaas is responsible for displaying this page, and it is responsible for processing the page when it is submitted.

The adminPage.jsp file is shown below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"
    import="javax.naming.*, ejbs.*"%>
<%@ page errorPage="/errorpage.jsp" %>
<%!
  private StatelessEJB ejb = null;

  public String doIt () {
    try {
      InitialContext ctx = new InitialContext();
      ejb = (StatelessEJB) ctx.lookup(
                  "StatelessEJBBean/remote");
      return ejb.adminMethod();
    } catch (Exception e) {
      e.printStackTrace ();
      return e.getMessage();
    }
   
  }
%>                 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Admin Page</title>
</head>
<body>
<jsp:include page="/includes/menubar.jsp"/>
 This page is only available to admin users
 <p><%=doIt()%></p>
 </body>
</html>

The code highlighted above has a method called doIt which calls on the stateless EJB's adminMethod. The string returned by the EJB is displayed on the page. The other jsp's ( userPage.jsp and anonymousPage.jsp differ only slightly: they call a different method in the stateless EJB.

A logout page is defined to log out of the system.

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"
import="javax.naming.*, javax.servlet.http.*,
  org.jboss.security.*"%>
<%@ page errorPage="errorpage.jsp" %>
<%
      ((HttpSession) request.getSession()).invalidate ();
      SecurityAssociation.clear ();
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>

<head>
<META HTTP-EQUIV="Refresh" CONTENT="1;URL=http:index.jsp">
</head>  
  <body>
    Logout in progress... <br>
  </body>
</html>

The web application's JBoss deployment descriptor (jboss-web.xml) is shown below:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE jboss-web PUBLIC 
          "-//JBoss//DTD Web Application 2.3V2//EN" 
          "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd">
<jboss-web>
  <security-domain>java:/jaas/other</security-domain>
</jboss-web>

The security domain points to the JBoss authentication realm called other. The security domain "other" is defined in the JBoss configuration file JBoss/server/default/conf/login-config.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation=
    "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>JaasTests</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
   <error-page>
      <error-code>403</error-code>
      <location>/notAuthenticated.html</location>
   </error-page>
   
   <!--  Regular user allowed URL's -->
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Protected Pages</web-resource-name>
      <url-pattern>/user/*</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
      <auth-constraint>
         <role-name>RegularUser</role-name>
      </auth-constraint>
     
      <user-data-constraint>
         <transport-guarantee>NONE</transport-guarantee>
      </user-data-constraint>
  </security-constraint>
  <!--  End Regular user allowed URL's -->
  
  <!--  Admin user allowed URL's -->  
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Protected Pages</web-resource-name>
      <url-pattern>/admin/*</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
      <auth-constraint>
         <role-name>AdminUser</role-name>
      </auth-constraint>
     
      <user-data-constraint>
         <transport-guarantee>NONE</transport-guarantee>
      </user-data-constraint>
  </security-constraint>  
  <!--  End Admin user allowed URL's -->  
  
   <security-role>
      <description>Authorized to access everything.</description>
      <role-name>AdminUser</role-name>
   </security-role>
   <security-role>
      <description>Authorized to limited access.</description>
      <role-name>RegularUser</role-name>
   </security-role>  
   <login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
         <form-login-page>/login.html</form-login-page>
         <form-error-page>/loginFailed.html</form-error-page>
      </form-login-config>
   </login-config>
</web-app>

In the above file the following was highlighted:

  • An error page is defined for the 403 http error code. This allows a customised page to be displayed whenever the user tries to access a page that requires a different role.
  • Security constraints are defined for various url's , based on a folder name. For example all the files within the /user url are for registered users (RegularUser). /admin is constrained to AdminUser users. All other utrl patterns are open to everyone.
  • The login mechanism (FORM) is defined, and the login and login failed pages are defined.

The web application archive (JaasTests.war) is packaged as follows:

The generated archive file is structured as follows:

JaasTests.war
    |
    +-errorpage.jsp
    |
    +-index.jsp
    |
    +-login.html
    |
    +-loginFailed.html
    |
    +-logout.jsp
    |
    +-notAuthenticated.html
    |
    +-admin
    |  |
    |  +-adminPage.jsp
    +-anon
    |  |
    |  +-anonymousPage.jsp
    +-includes
    |  |
    |  +-menubar.jsp      
     +-user
    |  |
    |  +-userPage.jsp
    +-web-inf
    |  |
    |  +-jboss-web.xml
    |  |
    |  +-web.xml                

The JBoss login-config.xml File

Before launching JBoss, it is ncessary to edit the JBoss login configuration file login-config.xml in the jboss installation foler/server/default/conf. By default thepolicy named "other" does not allow unauthenticated user access. This is enabled by editing the relevant section of the file as shown below:

    <!-- The default login configuration used by any security domain that
    does not have a application-policy entry with a matching name
    -->
    <application-policy name = "other">
       <!-- A simple server login module, which can be used when the number 
       of users is relatively small. It uses two properties files:
       users.properties, which holds users (key) and their password (value).
       roles.properties, which holds users (key) and a comma-separated list of
       their roles (value).
       The unauthenticatedIdentity property defines the name of the principal
       that will be used when a null username and password are presented as is
       the case for an unuathenticated web client or MDB. If you want to
       allow such users to be authenticated add the property, e.g.,
       unauthenticatedIdentity="nobody"
       -->
       <authentication>
          <login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule"
             flag = "required">
             <module-option name = "unauthenticatedIdentity">AnonymousUser</module-option>
          </login-module>
       </authentication>
    </application-policy>

Deploy And Run

The archives are packaged in Eclipse, JBoss is launched, JaasTests.jar and JaasTests.war are deployed, and finally a web browser is pointed to the application's home page (http://localhost:8080/JaasTests).

Now that the application is known to work using Jaas, it can be changed to use a MySQL database to access the user names, passwords and associated roles.

Create A JaasTests Database

In order to get JBoss to authenticate users by way of a database, a database must be present, with users and roles defined in it. JBoss uses customisable SQL queries, so almost any database structure is possibe. In this document a simple database is created to illustrate the process.

A terminal window is opened, and mySQL command tool started on the same host as the mysql server.

Below is a sample session using the mysql command line tool. It is used to create a database called "jaastests". A new user called "user" with a password value of "password" is assigned to the database, with all privileges. Later on the new user can connect to mysql locally, or remotely, to create tables and add or delete data, in the database.

prompt> mysql -u root -p

Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5 to server version: 5.0.18-standard

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> create database jaastests;
Query OK, 1 row affected (0.00 sec)

mysql> grant all privileges on jaastests.* to user identified by 'password';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.02 sec)

mysql> quit
Bye

Now that the new database and user is created. All operations on the database can be carried out using the username 'user'.

The MySQL Administrator program is launched, and art the logon prompt the username "user" is given, along with a password of "password". Using the administrator, two new tables are created, a user table and a userrole table as shown below:

The MySQL query browser is launched from the administrator's tools menu. This is used to add users and passwords to the user table:

The userrole table is also edited to contain roles for the users:

The JBoss login-config.xml File Revisited

A new login configuration is added to JBoss' login-config.xml file. Just before the configuration called "other" , the following is inserted:

  • <!-- ....................... JaasTests login configuration ....................-->
        <application-policy name="JaasTests">
          <authentication>
            <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule"
               flag="required">
              <module-option name="dsJndiName">java:/JaasTestsDS</module-option>
              <module-option name="principalsQuery">
                select password from user where name=?
              </module-option>
              <module-option name="rolesQuery">
                select rolename,'Roles' from userrole
                WHERE userrole.username=? 
              </module-option>
              <module-option name = "unauthenticatedIdentity">AnonymousUser</module-option>
            </login-module>
          </authentication>
        </application-policy> 
  • The policy's name is JaasTests, and will be added to the application's various deployment descriptors.
  • The login module is defined to use JBoss' database login module.
  • To access the database, the JaasTestsDS datasource is used (as defined in the next section).
  • The principals query defines how JBoss can get a password given a username.
  • The roles query allows JBoss to get a list of roles a given user has been assigned in the database.
  • The unauthenticated identity is here to allow unauthenticated users to access any application which uses the JaasTests application policy.

It is probably a good idea to remove the unauthenticatedIdentity in the "other" application policy, if it was added in a previous step.

Login Datasource File

In the previous section, JBoss is configured to use a datasource called JaasTestsDS . A file called jaastests-ds.xml is created as shown below, to define the datasource:

<datasources>
  <local-tx-datasource>
    <jndi-name>JaasTestsDS</jndi-name>
    <connection-url>jdbc:mysql://databasehostname:3306/jaastests</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>user</user-name>
    <password>password</password>
    <metadata>
        <type-mapping>mySQL</type-mapping>
    </metadata>      
  </local-tx-datasource>
</datasources>

The datasource file jaastests-ds.xml is saved in the deployment folder of JBoss (JBoss installation folder/server/default/deploy).

Modify Deployment Descriptors

Two JBoss deployment descriptor files are edited to use the new application policy.

The web application's JBoss deployment descriptor (jboss-web.xml) is shown below:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE jboss-web PUBLIC 
          "-//JBoss//DTD Web Application 2.3V2//EN" 
          "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd">
<jboss-web>
  <security-domain>java:/jaas/JaasTests</security-domain>
</jboss-web>

The JBoss deployment descriptor file (jboss.xml) is defined as follows:

<?xml version="1.0" encoding="UTF-8"?>
<jboss>
<!-- Problem in EJB3 of JBoss 4.0.4 GA
<security-domain>java:/jaas/Jaastests</security-domain>
-->
<security-domain>JaasTests</security-domain>
<unauthenticated-principal>AnonymousUser</unauthenticated-principal>
</jboss>

Modify JaasTests.jar Packaging

The properties files are no longer needed and so are not included in the EJB archive.

Deploy And Run

The archives are packaged in Eclipse, JBoss is launched, JaasTests.jar and JaasTests.war are deployed, and finally a web browser is pointed to the application's home page (http://localhost:8080/JaasTests).

Any change made to JBoss' login-config.xml only takes effect after JBoss is started or if it is already running, JBoss must be restarted for the changes to take effect.

  Copyright © 2006 J3 Ltd Permission is granted to reproduce material on this page, on the condition that a reference to "WWW.J3Ltd.com" is given as the source of the material.