Ozibug - web based bug tracking


  1. Introduction
  2. Procedure
  3. Configuration
  4. Creating a custom authentication module
  5. Examples
Back to index
 

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.

Back to top
 

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.

  1. Standard - authentication is performed against the user details held in Ozibug based on the user id and password supplied in the HTTP request.
  2. 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.)
  3. 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.)

Back to top
 

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.

authentication.handler.chain=Standard,Key,TmpLogin

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.

authentication.handler.1=au.com.tortuga.ozibug.auth.LDAPAuthenticationHandler
authentication.handler.1.parameter.1=ldap.host=myHost.myDomain
authentication.handler.1.parameter.2=ldap.port=389
authentication.handler.1.parameter.3=ldap.bind.dn=cn=Manager,o=Tortuga Technologies
authentication.handler.1.parameter.4=ldap.bind.passwd=mypassword
authentication.handler.1.parameter.5=ldap.search.base=o=Tortuga Technologies
authentication.handler.1.parameter.6=ldap.search.filter=(&(uid={0})(objectclass=inetorgperson))

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.

authentication.handler.1=au.com.tortuga.ozibug.auth.SSOAuthenticationHandler
authentication.handler.2=au.com.tortuga.ozibug.auth.LDAPAuthenticationHandler
authentication.handler.3=au.com.tortuga.ozibug.auth.IPAuthenticationHandler

The parameters are also specified in the same manner with the numeric suffix being incremented for each definition.

authentication.handler.1=au.com.tortuga.ozibug.auth.MyAuthenticationHandler
authentication.handler.1.parameter.1=name1=value1
authentication.handler.1.parameter.2=name2=value2
authentication.handler.1.parameter.3=name3=value3

Notes:

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

Back to top
 

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.

  1. 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 );
    
      ...

  2. Implement the AuthenticationHandler interface

    It is mandatory to implement this interface. You must define a name for the handler as well as the method to authenticate the incoming request.

    • String getName()

      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.

      authentication.handler.chain=MyHandler,Standard,Key,TmpLogin
    • String getDescription()

      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";
      }

    • boolean authenticate( Map context )

      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.

  3. Implement the LifeCycle interface

    This interface allows you to initialize and destroy your handler cleanly, in a specified manner.

    • init( Map handlerInfo )

      This method is called when the servlet initializes and can be used to obtain configuration properties from the system properties file.

      public void init( Map handlerInfo ) {
      
        String logId = "init";
      
        log.debug( logId + ": initializing" );
      
        // log the configuration parameters
        Iterator it = handlerInfo.keySet().iterator();
        while ( it.hasNext() ) {
          String name  = (String) it.next();
          String value = (String) handlerInfo.get( name );
          log.debug( logId + ": " + name + " = " + value );
        }
      
        // initialize your handler here ....
      }
    • destroy()

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

      authentication.handler.1=com.myDomain.myApplication.MyAuthenticationHandler
      authentication.handler.1.parameter.1=name1=value1
      authentication.handler.1.parameter.2=name2=value2
      ...
      

    • Configure the chain

      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.

      authentication.handler.chain=MyHandler,Standard,Key,TmpLogin
      
  5. Enable logging

    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
    

  6. 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.
                              
Back to top
 

  • LDAP (External Authentication)

    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.

  • IP (Single Sign On)

    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.

  • JCSI SSO (Single Sign On)

    This Authentication Handler uses the Wedgetail Communications JCSI SSO product to implement a Single Sign On solution (SSO).

    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.

Back to top
 
Back to index