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.
|