Orion Server: Creating custom user authentication
This is a Java/J2EE tutorial for Orion Application Server.
This short article aims to answer the following question:
I would like to restrict access to my
web-application using FORM or BASIC
authentication, but I do not store all my
usernames in the principals.xml
file. How can I authenticate using a custom
user database?
Well, Orion has support for pluggable
UserManagers
. The idea is that
you create a class that implements the com.evermind.security.UserManager
interface and tell Orion to use that for
your application. The
UserManager
is responsible for
locating, creating, editing, removing and
managing User and Group object.
Once a UserManager
has been
plugged in, Orion will call it when it needs
to authenticate a user. This can happen in
situations such as user’s accessing
restricted pages of a web-app or a client
trying to bind to the JNDI context. While
the UserManager
is very rich
and flexible, this article focuses purely on
solving the above question and many aspects
of the UserManager
shall be
ignored.
Four steps are required:
- Write the custom UserManager.
- Plug the UserManager into your application.
- Define your groups.
- Create security constraints in your web-app.
Step 1 : Writing the custom UserManager
To make life easier, an abstract
UserManager
implementation has
been created called
com.orionsupport.security.SimpleUserManager
.
Download simpleusermanager.jar
In order to create your own
UserManager
, you simply extend
this class and implement three methods to
your own needs:
protected boolean userExists(String username);
protected boolean checkPassword(String username, String password);
protected boolean inGroup(String username, String groupname);
Optionally, if your
UserManager
needs to perform a
task upon startup, you can overide this
method:
public void init(Properties properties) throws InstantiationException;
These methods will perform code to talk
to your custom user-database. Here is an
example, that implements a custom
user-database in memory using
HashMap
s. Three standard users
are added (with passwords) and 1 admin is
added. The standard users are in the ‘users’
group and the admin is in all groups.
package test;
import java.util.*;
import com.orionsupport.security.SimpleUserManager;
public class MyUserManager extends SimpleUserManager {
// map contains username/password pairs
private Map users = new HashMap();
private Map admins = new HashMap();
public void init( Properties properties ) {
.put( "joe", "schmoe" );
users.put( "someone", "mypassword" );
users.put( "billgates", "banana" );
users.put( "admin", "secret" );
admins}
protected boolean userExists( String username ) {
return users.containsKey( username ) || admins.containsKey( username );
}
protected boolean checkPassword( String username, String password ) {
if ( admins.containsKey( username ) ) {
return password.equals( admins.get( username ) );
}
else {
return password.equals( users.get( username ) );
}
}
protected boolean inGroup( String username, String groupname ) {
if ( admins.containsKey( username ) ) {
// admins are in all groups
return true;
}
else if ( users.containsKey( username ) ) {
// users are only in group 'users'
return groupname.equals( "users" );
}
else {
// unknown user
return false;
}
}
}
The above example is not going to be very
useful in the real world, but reading
through it should illustrate how to create a
UserManager
that connects to
your custom user-database. This could be a
relational database, in memory store, XML
file, flat-file, LDAP server, NT domain or
proprietary solution. It’s your job to
create the custom hooks -
SimpleUserManager
just makes it
very quick and easy.
Step 2 : Plugging the UserManager into your application
Once you have written the UserManager you
need to let Orion know about it. To do this,
edit the appropriate
orion-application.xml
in your
orion/application-deployments
directory for your application and add the
following:
user-manager class="test.MyUserManager" /> <
Tip: If you need to specify properties to be passed to your
UserManager
, you can insert<property name="..." value="..." />
tags inside the<user-manager>
tag. These are then passed to thepublic void init( Properties properties )
method of theUserManager
.
You also need to ensure that
SimpleUserManager
and your own
implementation (MyUserManager
)
are in the class-path for your application.
To do this, add appropriate
<library path="...;" />
tags to
orion-application.xml
.
Once you’ve done this, check the log for Orion (if it’s not running - start it). If you don’t have any errors, well done. If you do, it’s almost always a class-path problem - check all the classes are available to Orion.
Step 3 : Defining your groups
Edit the file principals.xml
in the same directory as
orion-application.xml
and add
entries for each group you require in your
application. For every group add an
appropriate
<group name="...;" />
tag. Example:
principals>
<
groups>
<group name="users" />
<group name="admins" />
<groups>
</
users>
<users>
</
principals> </
Notice that only groups are specified
here - users are not as your
UserManager
is responsible for
retrieving them.
Step 4 : Creating security constraints on your web-application
And finally we need to tell our web-application to restrict certain pages to users who are in a specified group.
Open WEB-INF/web.xml
of your
web-app, 3 additions are about to be
made.
1. Add security roles
For every group that you want to use, you
need to add a
<security-role>
tag. The
syntax is:
security-role>
<role-name>myGroup</role-name>
<security-role> </
2. Add login configuration
This specifies how the user shall be
prompted to enter their username and
password. There are a few types, although
typically you will use BASIC
or
FORM
.
BASIC
BASIC
is the easiest to use
- it involves using HTTP authorization
features built into the browser to prompt
for username and password. When a user
attempts to access a page using BASIC
authentication, the browser will pop-up a
window asking for login details. This
username/password is stored by the browser
and automatically sent for any page that is
in the specified realm - this allows
multiple username/passwords to be stored by
the browser for different web-apps.
Typically a username/password is remembered
by the browser until it is closed.
login-config>
<auth-method>BASIC</auth-method>
<realm-name>myRealm</realm-name>
<login-config> </
FORM
FORM
is a more practical
solution - when a restriced page is
requested, an HTML page shall be returned
instead containing a form to enter the
username/password into. The advantage of
this is that the page can be customized to
have the same look and feel as the rest of
your site and contain other information
(such as help or links to retrieve your lost
password or create new account).
In order to use the FORM
method, you must first create an HTML page
containing the actual form. Create a file
called login.jsp
in your
web-app directory:
<form method="post" action="j_security_check">
<input name="j_username" type="text"><br>
Username: <input name="j_password" type="password"><br>
Password: <input type="submit">
</form>
Of course, the form can look however you
want it to, so long as it: * has the
action
attribute set to
j_security_check
* has the
method
attribute set to
post
(actually this isn’t
really required but you are recommended to
do it) * contains 2 fields:
j_username
and
j_password
When your form has been created, you need to let Orion know about it:
<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>
If you would like another page to handle
invalid login attempts, you can change the
<form-error-page>
tag.
3. Protect resources
The last thing you have to do is tell Orion, which files or directories in your web-app are restricted to which users:
security-constraint>
<web-resource-collection>
<url-pattern>/path/</url-pattern>
<web-resource-collection>
</auth-constraint>
<role-name>myGroup</role-name>
<auth-constraint>
</security-constraint> </
Example
The following web.xml
file
sets up 2 restrictions (using form-based
authentication). The /users/
directory is restricted to people in the
users
group only, and the
/admins/
directory is
restricted to, well you can guess.
web-app>
<
security-role>
<role-name>users</role-name>
<security-role>
</
security-role>
<role-name>admins</role-name>
<security-role>
</
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>
</
security-constraint>
<web-resource-collection>
<url-pattern>/users/</url-pattern>
<web-resource-collection>
</auth-constraint>
<role-name>users</role-name>
<auth-constraint>
</security-constraint>
</
security-constraint>
<web-resource-collection>
<url-pattern>/admins/</url-pattern>
<web-resource-collection>
</auth-constraint>
<role-name>admins</role-name>
<auth-constraint>
</security-constraint>
</
... rest of web.xml here ...
web-app> </
Et voila! Trying to access
http://mysite/myapp/users/
will
prompt with the a form for logging in. If
your UserManager responds with
true
for all three methods that
is called on it, the user will be shown the
restricted page.
Remember to download simpleusermanager.jar.