i-Planet Administration Guide

Appendix B Pluggable Authentication API

This appendix describes an abstract class used for writing pluggable authentication modules.

An Abstract Class Used for Writing Pluggable Authentication Modules


Caution - Caution -

This API is classified Unstable. For an explanation of this classification, see the manpage attributes(5) in Solaris 2.6. The likelihood that this API will change is very high. Make a backup copy of any file that you are going to edit.


This is an abstract class that can be used to write pluggable authentication modules. Because it is an abstract class authentication, writers must subclass and override the abstract methods init, validate, and getUserTokenId.

How Authentication Works

The HTML for the authentication states is generated dynamically based on the parameters set in the configuration file for the authentication module developed. There must be a configuration file with the name of the class (no package name) and the extension .properties. This file must reside in /etc/opt/SUNWstnr on the i-Planet server when it is started.

The properties file is of the following form shown in Missing Cross Reference Target


SCREEN

TIMEOUT 60

TEXT Sample Login Page

TOKEN Enter User Name:

PASSWORD Enter User Password:


SCREEN

TIMEOUT 30

TEXT Sample Login Page 2

TOKEN Enter Favorite Color

TOKEN Enter Secret Pin Number

PASSWORD Enter Challenge form

Each SCREEN entry corresponds to one authentication state or authentication HTML page. When an authentication session is invoked, one HTML page is sent for each state. In the previous sample SCREENS, the first state sends an HTML page asking the users to enter a token and a password. When the users submit the token and the password, the validate() method is called. Module writers get the tokens, validate them, and return them. The second page is then sent and the validate() routine is again called.

If the module writers throw a LoginException, an authentication failed page is sent to the user. If no exception is thrown, which implies successful completion, the users are redirected to their default page. The TIMEOUT parameter is used to ensure that the users respond in a timely manner. If the time between sending the page in response is greater than the TIMEOUT, a time-out page is sent.

Optional Pages

There are optional HTML and IMAGE parameters for each page. The HTML parameter allows the module writers to use their own HTML page for the authentication screens. The IMAGE parameter allows writers to display a background image on each page.

The SetReplace method allows module writers to substitute dynamic text for the token and password accompanying text descriptions.

When multiple pages are sent to the user, the tokens from a previous page may be retrieved by using the getTokenForState methods. Each page is referred to as a state. The underlying authentication module keeps the tokens from the previous states until the authentication is completed.

Using Your Authentication Module

For the i-Planet server to recognize your authentication module, you must add the full class name with package to the /etc/opt/SUNWstnr/platform.conf file after the authenticators = parameter. The reverseproxy.policy file on the i-Planet gateway must also be modified to allow requests to your authentication module. You will find this file on the i-Planet gateway in the directory /opt/SUNWsnrp/policy/. You must restart the reverse proxy server on the i-Planet gateway and the web server on the i-Planet server after you have modified these files.

Each authentication session creates a new instance of your authentication Java class. The reference to the class is released once the authentication session has either succeeded or failed.


Note -

Any static data or reference to any static data in your authentication module must be thread safe.


For example, .properties and Java module files, see "Sample Files"" section in this appendix or the /opt/SUNWstnr/sample/auth/com/sun/login/sample on the i-Planet server. /opt is the directory for the default installation. If you have customized your installation, you may have installed this file in another directory.

Constructors

Login


public Login () throws LoginException

If the Login constructor fails, LoginException should be thrown.

Methods

init


public abstract void init() throws LoginException

This method must be overridden. It is called each time an authentication session is started. If the initialization of the module fails, the LoginException should be thrown.

Overrides: init in class Authenicator

validate


public abstract void validate() throws LoginException

This method must be overridden. It is called once for each authentication page that is specified in the authentication modules properties file. The various getToken methods may be used to get the values for the user-entered tokens and passwords. LoginException should be thrown at some point during the validate() method if authentication has failed. The message in the exception is logged and users are sent an Authentication Failed page. If no exception is thrown, which implies successful completion, and all authentication pages have been sent, the user is authenticated. The abstract method getUserTokenId() is called to get the authenticated name of the user.

Overrides: validate in class Authenticator

getUserTokenId


public abstract String getUserTokenId()

This method must overridden. It is called once after the all authentication pages have been sent to the user.

Overrides: getUserTokenId in class Authenticator

getSessionId


public String getSessionId()

This method returns a unique key for this authentication session.

getCurrentState


public int getCurrentState()

This method returns the current state in the authentication process.

getNumberOfTokens


public int getNumberOfTokens()

This method returns the total number of tokens and passwords in the current authentication state.

getNumberOfTokensForState


public int getNumberOfTokensForState(int stateNumber)

This method returns the total number of tokens and passwords for the given authentication state. This method may be used to get token values from previous authentication states.

getToken


public String getToken(int index)

This method returns the user-entered value for the specified token in the current authentication state.

getToken


public String[] getToken()

This method returns the user-entered value for the first token in the current authentication state.

getAllTokens


public String[] getAllTokens()

This method returns all the user-entered tokens in the current authentication state.

getAllTokensForState


public String[] getAllTokensForState(int stateNumber)

Returns all the user-entered tokens in the specified authentication state.

getNumberOfStates


public int getNumberOfStates()

This method returns the number of authentication states for this authentication module.

setReplaceText()


public void setReplaceText(int token,

				String text)

The tokens and passwords have text descriptions for each authentication page. If your module needs to add to these descriptions, this can be done by inserting the keyword into the description. This method can then be used to substitute the specified text with generated dynamic text.

This method should be called for the next state, before returning from the validate method().

setReplaceText


public void setReplaceText(int token,

							String text[])

Same as setReplaceText(), but allows replacement of multiple text strings.

logout


public void logout()

Not implemented. This method is a placeholder. It will be called when a user logs out.

Writing A Pluggable Authentication Module

This section is a task-oriented guide to writing a pluggable authentication module. It takes you through the steps for writing a pluggable authentication module. At the end of this section is a sample. You must first decide what your authentication mechanism is going to be and how many pages it will be and what inputs that the user will have to enter for each page.

Writing the Module

You must first write a stand-alone Java class that will call your specific authentication process, library, or the interface that it requires. In many cases, this will require the Java Native Interface (JNI) to have access to C or C++ library or system call.

You will most likely save time if you get it working in a stand-alone environment before you integrate it into i-Planet.

To Write a Pluggable Authentication Module
  1. Write a stand-alone Java class that will call your specific authentication process, library, or the interface that it requires.

  2. Test your module in a stand-alone environment.

Integrating the Module

Assume you have a Java class called com.companyx.auth.MyLogin that takes two inputs on the command line from a user. One input is a userId and the second is a password. MyLogin then passes these two inputs to two routines called myAuthenticateId(Id) and myAuthenticatePass(pass), which in turn calls the authentication-specific library and returns a success or fail with an error message if it fails.

After you have written your pluggable authentication module and tested it, you must integrate it into i-Planet. Use the following procedure to integrate your module into i-Planet.

To Integrate Your Pluggable Authentication Module
  1. Modify your class to do the following:


    import com.sun.authd.*
    
    extend com.sun.authd.Login
    
    implement the validate(), init(), and getUserTokenId() methods

    The validate method replaces your input gathering method. Each time the user submits an HTML page, the validate() method will be called. In the method, you call your authentication-specific routines. At any point in this method, if the authentication has failed, you must throw a LoginException. If desired, you can pass the reason for failure as an argument to the exception. This reason will be logged in the i-Planet authentication log.

    init() should be used if your class has any specific initialization such as loading a JNI library. init() is called once for each instance of your class. Every authentication session creates a new instance of your class. Once a login session is completed the reference to the class is released.

    getUserTokenId() is called once at the end of a successful authentication session by the i-Planet authentication server. This is the string the authenticated user will be known as in the i-Planet server. A login session is deemed successful when all pages in the MyLogin.properties file have been sent and your module has not thrown an exception.

  2. Create a MyLogin.properties file.

    This file contains some simple directives which tell the i-Planet authentication daemon how to create the HTML pages for your login class dynamically. Since MyLogin requires two screens with one input each, the MyLogin.properties file will look like the following:


    SCREEN
    
    TEXT Welcome to my login pages
    
    TIMEOUT 60
    
    TOKEN Please enter your company ID
    
    
    
    SCREEN
    
    TIMEOUT 120
    
    TEXT Welcome to my second page
    
    PASSWORD Please enter your password

    This .properties file tells the i-Planet authentication daemon to send two successive pages to the user. After each submit, your MyLogin validate routine will be called with the inputs made available through public getXX methods of the Login class.

  3. Compile your java class.

  4. Include /opt/SUNWjeev/classes/authd.jar and /opt/SUNWjeev/classes/acm.jar in your CLASSPATH.


    Note -

    If you use a package name to create the directories for the package, note the name that you used.


  5. Copy your class file to /opt/SUNWjeev/classes.


    Note -

    If you use a jar file, you will need to edit the /opt/SUNWjeev/bin/iplsrv script and add your jar file to the web server's CLASSPATH. You can also just add it to your root CLASSPATH. The iplanet_srv script will pick it up.


    If you have JNI library, you must copy it into /opt/SUNWjeev/lib/sparc, or you will need to modify the LD_LIBRARY_PATH of iplsrv script.

  6. Copy your MyLogin.properties file to /etc/opt/SUNWstnr.

  7. Add your full package.class name to the authenticators property in the platform.conf file.

       authenticators=com.sun.login.unix.Unix
    com.companyx.auth.MyLogin
  8. Add the lines to the /opt/SUNWsnrp/policy/reverseproxy.policy file on the i-Planet gateway.

    http://host:port/login/MyLogin

    https://host/login/MyLogin

    Be sure to add both http and https.

  9. Restart the web server on the i-Planet server.

  10. Restart the reverse proxy server on the i-Planet gateway.

  11. Test your login.

The java file for MyLogin Module

Missing Cross Reference Target contains a sample Java file for MyLogin Module.


package com.companyx.auth;

import com.sun.authd.*;

public class MyLogin extends Login {

	private String userTokenId;

	public MyLogin() throws LoginException{}

	public void init() throws LoginException {}

	public void validate() throws LoginException {

			String token = getToken();
			if (getCurrentState() == 1) {
				int ret = myAuthenticateId(token);
				if (ret == 0) {
						throw new LoginException("Invalid UserId: " + userTokenId);
		 		}
			}


			else {
		 	 	int ret = myAuthenticatePassword(token);
		 		if (ret == 0) {
						throw new LoginException("Invalid Password: " + userTokenId);
		   		}
		 		userTokenId = token;
			}

	}

	public String getUserTokenId() {
			return userTokenId;
	}

	public int myAuthenticateID(
			Sting userID
	)
	{
			return 1;
	}
	public int myAuthenticatePassword(
			String userId
	)
	{
			return 1;
	}

}

There is also a sample in /opt/SUNWstnr/sample/auth/com/sun/login that uses most of the methods in the Login class. There is also a javadoc in /opt/SUNWstnr/docs/javadocs/com/sun/authd for the Login class.

Sample Files

Each authentication module must have a corresponding module.properties file.The following sample files show the form and content of the .properties file and samples of the code.

Examples

There are two examples of .properties and Java code files.

Sample .properties File 1

Missing Cross Reference Target is a sample .properties file.


SCREEN

TEXT This is a sample login page

TOKEN First Name

TOKEN Last Name
TOKEN Favorite Car

PASSWORD Favorite Car's password



SCREEN
TIMEOUT 200

TEXT   The all password page

PASSWORD password 1

PASSWORD password 2

PASSWORD password 3

PASSWORD password 4



SCREEN

TEXT 3rd page

TOKEN Enter anything

TOKEN This will be your userID

Sample Java Module 1

Missing Cross Reference Target is the sample code for MySampleLogin.java.


package com.sun.login.sample;

import java.util.*;
import com.sun.authd.*;

public class MySampleLogin extends Login {

    private String userTokenId;

    public MySampleLogin() throws LoginException{
        System.out.println("MySampleLogin()");
    }

    public void init() throws LoginException {
        System.out.println("MySampleLogin initialization");
    }

    public void validate() throws LoginException {
        System.out.println("SampleLoginModule validate()");
			// get the current login page

			int login_page = getCurrentState();

			// print out all the tokens and passwords the user entered

			String[]tokens = getAllTokens();
			for (int i = 0; i < tokens.length; i++) {
            System.out.println(i + "->" + " " + tokens[i]);
			}

			if (login_page == 2) {
	   			 userTokenId = new String(getToken(1));
			}
            
	}
	public String getUserTokenId() {
        return new String(userTokenId);
	}
	public String getDescription() {
			return "My Sample Login Module";
	}
}

Sample .properties File 2

You can also find the following sample file SampleLoginModule.properties in /opt/SUNWstnr/sample/auth/com/sun/login/sample, where /opt is the directory in which it is installed by default. Missing Cross Reference Target shows a sample .properties file.


SCREEN

TEXT This is a sample login page

TOKEN First Name

TOKEN Last Name
SCREEN

TIMEOUT 30



TEXT   You made it to page 2

PASSWORD Enter any password
SCREEN



TIMEOUT 60

TEXT You made it past the first page

TOKEN Enter <REPLACE>'s favorite car

PASSWORD Enter <REPLACE>'s favorite color



SCREEN

TEXT 4th page

PASSWORD who cares

TOKEN anything here

Sample Java Module 2

You can also find the following sample in a file named SampleLoginModule.java in /opt/SUNWstnr/sample/auth/com/sun/login/sample, where /opt is the directory in which it is installed by default.Missing Cross Reference Target shows a sample Java module


package com.sun.login.sample;

import java.util.*;
import com.sun.authd.*;

public class SampleLoginModule extends Login {

	private String userTokenId;
	private String firstName;
	private String lastName;

	public SampleLoginModule() throws LoginException{
			System.out.println("SampleLoginModule()");
	}

	public void init() throws LoginException {
			System.out.println("SampleLoginModule initialization");
	} 

	public void validate() throws LoginException {

			int currentState = getCurrentState();
			if (currentState == 1) {
				firstName = getToken(1);
				lastName = getToken(2);
				if (firstName.equals("") || lastName.equals("")) {
						throw new LoginException("Sample failed names must not be\

empty");
			}
			return;
	}
	else if (currentState == 2) {
			String pass = getToken(1);
			System.out.println("Replace Text first: " + firstName + " last: "\

+ lastName);
			setReplaceText(1, firstName);
			setReplaceText(2, lastName);
			return;
			}
.


	else if (currentState == 3) {
			String[] tokens = getAllTokens();
			for (int i=0; i<getNumberOfTokens(); i++) {
				System.out.println("Token-> " + tokens[i]);	    }
			return;
	}
	else if (currentState == 4) {
			String[] tokens = getAllTokensForState(1);
			for (int i=0; i<getNumberOfTokensForState(1); i++) {
				System.out.println("Token-> " + tokens[i]);
			}
	}

			userTokenId = firstName;
	 }

	public String getUserTokenId() {
			return userTokenId;
    }

}