Ozibug can be configured to support pluggable
authentication modules, whereby user authentication is
performed against an external source such as a user
management system or LDAP directory. This allows, for
example, username/password verification to be performed
against an external source or
for single sign on to occur, based on mapping
a request to a valid user.
While authentication can be performed externally,
authorization and access control are still managed
within Ozibug. Authentication of a user by an external
source does not automatically grant the user
access to Ozibug, the user details must also exist in
Ozibug.
The authentication process takes place
when a new incoming HTTP Request is detected.
An authentication context is created and
the HTTP Request is placed in it.
The authentication mechanism will then execute
each module (or link) in the chain of
authentication handlers in turn.
Each module is given the authentication context so
that it can examine the contents (the HTTP Request),
and carry out the authentication.
If the authentication module succeeds then the
validated user name is placed in the context
and the handler returns the value true;
otherwise it should return the value
false.
Following successful authentication, the authorization
and access control processes will be invoked to
ensure the user is authorized to access Ozibug
and will determine their access level.
Once this is complete a successful login to Ozibug
has occurred and the standard welcome page will
be presented.
The default authentication handler chain is comprised
of the following modules.
Standard - authentication is
performed against the user details held in
Ozibug based on the user id and password
supplied in the HTTP request.
Key - authentication is
performed against the user details held in
Ozibug based on the single access key supplied
in the HTTP request (used by the reporting
module.)
TmpLogin - authentication is
performed against the user details held in
Ozibug based on the user id and temporary
password supplied in the HTTP request
(used by the forgotten password module.)
A default Ozibug installation will use the default
authentication handler chain out of the box. To change
this behaviour open the
OZIBUG_HOME/WEB-INF/ozibug.properties file
with your favourite editor and configure the
authentication.handler.chain property.
The configuration allows the names of custom and/or
default handlers to be included in any order. The
handler names should be specified as a comma separated
list, in which the order is significant. The default
authentication handler chain is equivalent to setting
the property as follows.
Additional properties can be set for each custom
authentication handler to allow for configuration of
its behaviour.
At a minimum the fully qualified class name of the
handler must be supplied, along with any number of
optional parameters to configure attributes such
as a database connection.
For example, the configuration required for the
example LDAP authentication handler would be
similar to the following.
Multiple authentication handlers can be specified
by incrementing the numeric suffix for each handler.
The suffixes must be contiguous.
The example below shows three handler definitions.
Setting the handler chain property overrides the
default behaviour, therefore any default handlers
required must be included in the required
order.
Changes to any of the handler properties will
require a restart of the servlet container before
the changes take effect.
The class files for any custom authentication
handlers must be placed in the classpath of the
Ozibug context, by either including them in a jar
and adding it to the lib directory (eg.,
OZIBUG_HOME/WEB-INF/lib/myhandlers.jar)
or by adding the class itself to the classes
directory (eg.,
OZIBUG_HOME/WEB-INF/classes/myDomain/myPackage/MyAuthenticationHandler.class).
The following steps take you through the procedure
of creating an authentication module.
There are two interfaces defined as part of the
Ozibug Pluggable Authentication API Specification
that you need to implement to do this.
Define a logger
Ozibug uses
log4j
and you can use this mechanism to write your
own log messages with.
They can then be configured through the
standard log4j mechanism. eg.,
// your package name
package com.myDomain.myApplication;
// external imports
import org.apache.log4j.Category;
public class MyAuthenticationHandler implements AuthenticationHandler, LifeCycle {
/** your applications logging category */
private static final Category log =
Category.getInstance( MyAuthenticationHandler.class );
...
This method should return the name that
your handler will be known as.
This will be the name you will use in
the configuration of the order that the
handlers are executed in.
public String getName() {
return "MyHandler";
}
You then use this name in the authentication.handler.chain
property.
This method should return a useful description
which is displayed in the logfile when debug
is turned on.
This is useful when a chain has been configured
as the combined output of the handlers is printed
describing the requirements and the operations
of all of the configured handlers.
public String getDescription() {
return "Uses the hostname of the requesting machine as the username";
}
This method must actually do the authentication
and map the incoming context, which contains
the HttpServletRequest, to an Ozibug user.
This method must determine if the requesting user
is valid, and if so place the username into
the context for further processing by the
system and return true.
public boolean authenticate( Map context ) {
// did we authenticate ?
boolean result = false;
try {
// retrieve the incoming servlet request
HttpServletRequest req = (HttpServletRequest) context.get( HTTP_REQUEST );
// retrieve the fully qualified hostname of the requesting user
String host = req.getRemoteHost();
// strip off the prefix from the fully qualified name
String name = host.substring( 0, host.indexOf(".") );
if ( name != null )
// log what we did
log.debug( "Authenticate: derived user " + name + " from " + host );
// put the derived name back into the context
context.put( USER_NAME, name );
// yes we authenticated
result = true;
}
else {
// couldn't get name from hostname
log.debug( "Authenticate: failed to get user from " + host );
}
}
catch ( Exception e ) {
// add in your error handling here ...
log.error( "Authenticate: exception: " + e.toString(), e );
}
// return the result
return result;
}
The authentication handler should place
the username in the context under the key
FAILURE_DETAILS when the
handler should have authenticated but didn't.
This is used to pass the failure details,
perhaps a user name, back to the user through
the login screen.
This method is called when the servlet is terminated.
It should be used to release any resources such
as database connections, etc.
public void destroy() {
log.debug( "destroy: terminating" );
// release your resources here ....
}
Set the properties
As previously mentioned you must configure your
new authentication handler.
This includes defining the handler itself and
any properties it may require as well as the
order that the handlers are executed.
Define the handler
There are several properties you can use to
configure your authentication handler.
The first, authentication.handler.x,
defines the class name of the handler.
Multiple handlers can be defined, this
is done by incrementing the suffix value
(1, 2, etc.)
The subsequent properties define any name/value
properties which are handed to the init() method.
Again multiple properties can be specified by
incrementing the suffix.
Add the name of the handler to the front
of the list.
Your handler will be executed first when
a request is received.
If the authentication fails then the next
handler will be called.
The example here shows the new handler being
executed before the standard handlers.
To enable logging for classes in the ozibug package (au.com.tortuga.ozibug), you should login as the administrator and
make sure that the log level is set appropriately.
To enable logging for classes in packages other than the ozibug package, you must override the application log preferences by supplying your own configuration file and define all aspects of the logging system in it, eg., log4j.properties.
The following entry must also be added to ozibug.properties to specify the location of your log configuration file, where a relative filename indicates that the configuration file is to be found in the OZIBUG_HOME/WEB-INF directory.
log.properties.filename=log4j.properties
Start the Web Container
Now start the web container and look at the
initialization messages.
In the following example you can see the
25/04/2004 15:48:29,593 [main] INFO InitializeHelper.initializeLicenseManager: done.
25/04/2004 15:48:29,862 [main] DEBUG ActionHandler.get: storing auth.LoginAction handler in cache
25/04/2004 15:48:29,863 [main] DEBUG ActionHandler.initialize: initializing au.com.tortuga.ozibug.auth.LoginAction
25/04/2004 15:48:30,343 [main] INFO LoginAction.init: configured 5 authentication handlers (MyHandler,Standard,Key,TmpLogin,Final)
25/04/2004 15:48:30,344 [main] DEBUG LoginAction.init: handler[1] MyHandler:Uses the hostname of the requesting machine as the username
25/04/2004 15:48:30,344 [main] DEBUG LoginAction.init: handler[2] Standard:uses name/password in http request against Ozibug user database
25/04/2004 15:48:30,344 [main] DEBUG LoginAction.init: handler[3] Key:uses key in http request against Ozibug user database, sets singleAccess mode
25/04/2004 15:48:30,345 [main] DEBUG LoginAction.init: handler[4] TmpLogin:uses name/temporary password in http request against Ozibug user database
25/04/2004 15:48:30,345 [main] DEBUG LoginAction.init: handler[5] Final:carries out final integrity checks
25/04/2004 15:48:30,425 [main] DEBUG MyAuthenticationHandler.init: initializing
25/04/2004 15:48:30,425 [main] DEBUG MyAuthenticationHandler.init: name1 = value1
25/04/2004 15:48:30,425 [main] DEBUG MyAuthenticationHandler.init: name2 = value2
25/04/2004 15:48:30,615 [main] INFO InitializeHelper.initializeActionHandlers: done.
This example Authentication Handler uses an
LDAP server to verify the details of the user
attempting access against.
The user id and password are obtained from the
HttpServletRequest and then the password verified
against the plain text password
retrieved from the LDAP Server.
Note: this is an example which
doesn't include handling failed, dropped or
broken connections to the LDAP server.
Nor does it terminate and
release any resources through its destroy()
method.
The IP Authentication Handler is an example of
how a simple Single Sign On
solution can be added to Ozibug.
This handler simply reads in a set of
host/username or
address/usernamemappings at
initialization time and then tries to authenticate
each request based on its host name or address.
This handler also shows the usage of the
LifeCycle
interface for initialization and termination.
This application authenticates the user from
the incoming HTTP request using Microsoft®
Windows Integrated Authentication protocols
such as SPNEGO and NTLM along with the
Microsoft® Active Directory.
The authenticated user name is then placed into
the HTTP session (contained in the HTTP
request) which this handler accesses and places
in the Ozibug authentication context.