Sun OpenSSO Enterprise 8.0 Developer's Guide

Chapter 1 Using the Authentication Service API and SPI

This chapter provides information on the application programming interface (API) and service provider interface (SPI) developed for Sun OpenSSO Enterprise Authentication Service. It contains the following sections:

For information on Authentication Service C API, see Sun OpenSSO Enterprise 8.0 C API Reference for Application and Web Policy Agent Developers. For a comprehensive listing of Authentication Service Java API and SPI, see the Sun OpenSSO Enterprise 8.0 Java API Reference.

Initiating Authentication with the Authentication Service API

The OpenSSO Enterprise Authentication Service can be accessed by a web browser, an application using the authentication client API or any client that correctly implements the Authentication Service messaging interfaces. The com.sun.identity.authentication package contains the authentication client interfaces and classes with which a custom application can be enhanced to achieve authenticated access to the OpenSSO Enterprise Authentication Service. The custom application, running either locally or remotely to OpenSSO Enterprise, can initiate an authentication process, submit required credentials and retrieve the single sign-on (SSO) session token for itself or a user. The authentication client API starts the authentication process, and the Authentication Service responds with a set of requirements such as user ID and password. The appropriate credentials are returned to the Authentication Service. This back and forth communication between the custom application (with implemented API) and the Authentication Service continues until all requirements have been met and authentication has been determined to be successful or not.

The first step in the code sequence for the authentication process is to instantiate the com.sun.identity.authentication.AuthContext class which will create a new AuthContext object for each authentication request. Since OpenSSO Enterprise can handle multiple realms, AuthContext should be initialized, at the least, with the name of the realm to which the requestor is authenticating. Once an AuthContext object has been created, the login() method is called indicating to the server what method of authentication is desired. The getRquirements() method returns an array of Callback objects that correspond to the credentials the user must pass to the Authentication Service. These objects are requested by the authentication plug-ins, and are usually displayed to the user as login requirement screens. For example, if the requested user is authenticating to an organization configured for LDAP authentication only, the server will respond with the LDAP login requirement screen to supply a user name and a password. The code must then loop by calling the hasMoreRequirements() method until the required credentials have been entered. Once entered, the credentials are submitted back to the server with the submitRequirements() method. The final step is to make a getStatus() method call to determine if the authentication was successful. If successful, the caller obtains a session token for the user; if not, a LoginException is thrown.

The following code sample illustrates how to authenticate users with user name and password credentials and obtain the session token using getSSOToken().


Example 1–1 Authentication Code Sample

import com.iplanet.sso.SSOToken;
import com.sun.identity.authentication.AuthContext;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;

public class TokenUtils {
    public static SSOToken getSessionToken(String realmName, String userId, 
        String password) throws Exception {
        AuthContext ac = null;
        try {
            if (realmName == null || realmName.length() == 0) {
                realmName = "/";
            }
            ac = new AuthContext(realmName);
            ac.login();
        } catch (LoginException le) {
            le.printStackTrace();
            return null;
        }

        try { 
            Callback[] callbacks = null;
            // Get the information requested by the plug-ins
            if (ac.hasMoreRequirements()) {
                callbacks = ac.getRequirements();

                if (callbacks != null) {
                    addLoginCallbackMessage(callbacks, userId, password);
                    ac.submitRequirements(callbacks);

                    if (ac.getStatus() == AuthContext.Status.SUCCESS) {
                        System.out.println("Auth success");
                    } else if (ac.getStatus() == AuthContext.Status.FAILED) {
                        System.out.println("Authentication has FAILED");
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return ac.getSSOToken();
    } 

    static void addLoginCallbackMessage(Callback[] callbacks, String userId,
        String password) 
         throws UnsupportedCallbackException 
    {
        int i = 0;
        try {
            for (i = 0; i < callbacks.length; i++) {
                if (callbacks[i] instanceof NameCallback) {
                    NameCallback nc = (NameCallback) callbacks[i];
                    nc.setName(userId);
                } else if (callbacks[i] instanceof PasswordCallback) {
                    PasswordCallback pc = (PasswordCallback) callbacks[i];
                    pc.setPassword(password.toCharArray());
                }
            }
        } catch (Exception e) {
             throw new UnsupportedCallbackException(callbacks[i], 
                   "Callback exception: " + e);
        }
    }
}


Note –

Because the Authentication Service is built using the Java Authentication and Authorization Service (JAAS) framework, the Authentication Service client API can invoke any authentication modules written using the JAAS API. JAAS enables services to authenticate and enforce access controls upon users. It implements a Java version of the standard Pluggable Authentication Module (PAM) framework. Because of this architecture, any custom JAAS authentication module (as well as those modules built specifically for OpenSSO Enterprise) will work with the Authentication Service. For more information on JAAS, see the Java Authentication And Authorization Service Reference Guide and http://java.sun.com/products/jaas/.


Writing Authentication Modules with the Authentication Service SPI

OpenSSO Enterprise provides the com.sun.identity.authentication.spi package to write Java-based authentication modules and plug them into the Authentication Service framework, allowing proprietary authentication providers to be managed using the OpenSSO Enterprise console. The authentication module is created using the abstract com.sun.identity.authentication.spi.AMLoginModule class which implements the JAAS LoginModule class.

The com.sun.identity.authentication.spi.AMLoginModule interface provides methods to access the Authentication Service and the authentication module's callback requirements file. This class takes advantage of many built-in features of OpenSSO Enterprise and scales well. Once created, a custom authentication module can be added to the list of authentication modules displayed by the OpenSSO Enterprise console. Use the following list of procedures as a checklist to complete the task.

  1. Create a callback requirements file for the new authentication module.

    See Creating an Authentication Module Callback Requirement File.

  2. Implement a Principal class.

    See Writing a Principal Class for the Authentication Module.

  3. Create a service file for the new authentication module.

    See Creating an Authentication Module Service File.

  4. (OPTIONAL) Create a localization properties file for the new authentication module.

    See Creating an Authentication Module Localization Properties File.

  5. Develop the custom authentication module.

    See Extending the AMLoginModule Class

  6. (OPTIONAL) Add post processing features.

    See Adding Authentication Post Processing Features.

  7. Access http://osso-host.osso-domain:osso-port/opensso/ssoadm.jsp from a browser and choose create-svc to create the service in OpenSSO Enterprise.

    You will need to copy the authentication module's service file to the text box. For more information regarding the ssoadm options, see the Sun OpenSSO Enterprise 8.0 Administration Reference.

  8. Choose the register-auth-module option (also on ssoadm.jsp) to register the custom authentication module with the Core Authentication framework.

    Enter the complete module name including the prepended package. For more information regarding the ssoadm options, see the Sun OpenSSO Enterprise 8.0 Administration Reference.

  9. Restart OpenSSO Enterprise.

    The custom authentication module is now listed under the Configuration tab as an Authentication option.


Note –

After deploying the opensso.war, you can also point a browser to http://openSSO-host.openSSO-domain:openSSO-port/opensso/samples/authentication/AuthSampleLoginModule.html for the sample, How to Write Sample Login Module using AMLoginModule SPI (Service Provider Interface)?.


Creating an Authentication Module Callback Requirement File

The authentication module's callback requirements file is XML that defines the module's authentication requirements and login state information. The parameters in this file automatically and dynamically customize the authentication module's user interface in the form of login pages, providing the means to initiate, construct and send the credential requests to the Distributed Authentication User Interface. Auth_Module_Properties.dtd defines the data structure of the file.

When an authentication process is invoked, the values nested in the Callbacks element of the module's callback requirements file are used to generate login screens. The module controls the login process, and determines each concurring screen. LDAP.xml, the callback requirements file for the LDAP authentication module, illustrates this concept.


Example 1–2 LDAP Authentication Module Callback Requirements File


<ModuleProperties moduleName="LDAP" version="1.0" >

    <Callbacks length="2" order="1" timeout="120" 
     header="This server uses LDAP Authentication" >
        <NameCallback>
            <Prompt> User Name: </Prompt>
        </NameCallback>
        <PasswordCallback echoPassword="false" >
            <Prompt> Password: </Prompt>
        </PasswordCallback>
    </Callbacks>

    <Callbacks length="4" order="2" timeout="120" 
     header="Change Password&lt;BR&gt;&lt;/BR&gt;#REPLACE#&lt;BR&gt;&lt;/BR&gt;" >
        <PasswordCallback echoPassword="false" >
            <Prompt>Old Password </Prompt>
        </PasswordCallback>
        <PasswordCallback echoPassword="false" >
            <Prompt> New Password </Prompt>
        </PasswordCallback>
        <PasswordCallback echoPassword="false" >
            <Prompt> Confirm Password </Prompt>
        </PasswordCallback>
        <ConfirmationCallback>
            <OptionValues>
                <OptionValue>
                    <Value> Submit </Value>
                </OptionValue>
                <OptionValue>
                    <Value> Cancel </Value>
                </OptionValue>
            </OptionValues>
        </ConfirmationCallback>
    </Callbacks>

    <Callbacks length="0" order="3" timeout="120" 
     header=" Your password has expired. Please contact service desk to 
     reset your password" error="true" />

    <Callbacks length="0" order="4" timeout="120" template="user_inactive.jsp" 
     error="true"/>

</ModuleProperties>

The initial interface has two Callback elements corresponding to requests for the user identifier and password. When the user enters values, the following events occur:


Note –

Name the authentication module's callback requirements file using the same name as that of the authentication module's class (no package information) and use the extension .xml. Create the file and use this naming convention even if no states are required for the module.


The file is located in the appropriate localized directory in the OpenSSO-Deploy-base/config/auth directory. Use one of the provided files as a template for creating the file and copy it to the aforementioned directory when finished.

Writing a Principal Class for the Authentication Module

After creating the authentication module's callback requirements file, write a class which implements java.security.Principal to represent the entity requesting authentication. For example, the constructor takes the username as an argument. If authentication is successful, the module will return this principal to the Authentication Service which populates the login state and session token with the information representing the user.

Creating an Authentication Module Service File

The authentication module's service file is written in XML and imported to OpenSSO Enterprise to allow the management of its attributes using the OpenSSO Enterprise console. The name of the service file follows the format amAuthmodulename.xml (for example, amAuthSafeWord.xml or amAuthLDAP.xml). The file is located in OpenSSO-Deploy-base/WEB-INF/classes. The new service file must conform to the sms.dtd. Use one of the provided authentication module service files as a template. Conversely, you can use the template provided.


Example 1–3 Authentication Module Service File Template


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ServicesConfiguration
PUBLIC "=//iPlanet//Service Management Services (SMS) 1.0 DTD//EN"
"jar://com/sun/identity/sm/sms.dtd">

<ServicesConfiguration>
  <Service name="iPlanetAMAuthMYMODULEAuthService" version="1.0">
    <Schema
     serviceHierarchy="/DSAMEConfig/authentication/
      iPlanetAMAuthMYMODULEAuthService"
     i18nFileName="mymoduleauth"
     revisionNumber="1"
     i18nKey="iplanet-am-auth-mymoduleauth-service-description">
      <Organization>
                
       <AttributeSchema name="iplanet-am-auth-mymoduleauth-primary-server"
        type="single"
        syntax="string"
        i18nKey="a102">
         <DefaultValues>
             <Value>msg1dev.ec-lille.fr:1389</Value>
         </DefaultValues>
       </AttributeSchema>
       <AttributeSchema name="iplanet-am-auth-mymoduleauth-primary-base-dn"
        type="single"
        syntax="dn"
        i18nKey="a103">
          <DefaultValues>
            <Value>dc=ec-lille,dc=fr</Value>
          </DefaultValues>
       </AttributeSchema>
       <AttributeSchema name="iplanet-am-auth-mymoduleauth-primary-search-base-dn"
         type="single"
         syntax="dn"
         i18nKey="a104">
          <DefaultValues>
             <Value>ou=people,dc=ec-lille,dc=fr</Value>
          </DefaultValues>
       </AttributeSchema>
       <AttributeSchema name="iplanet-am-auth-mymoduleauth-primary-bind-dn"
        type="single"
        syntax="dn"
        i18nKey="a105">
         <DefaultValues>
           <Value>cn=Directory Manager</Value>
         </DefaultValues>
       </AttributeSchema>
       <AttributeSchema name="iplanet-am-auth-mymoduleauth-primary-bind-passwd"
         type="single"
         syntax="password"
         i18nKey="a106">
       </AttributeSchema> 
       <AttributeSchema name="iplanet-am-auth-mymoduleauth-auth-level"
         type="single"
         syntax="number"
         i18nKey="a500">
          <DefaultValues>
             <Value>0</Value>
          </DefaultValues>
         </AttributeSchema>
        </Organization>
      </Schema>
        
      <Configuration>
        <OrganizationConfiguration name="/">		
            <AttributeValuePair>
               <Attribute name=
                "iplanet-am-auth-mymoduleauth-primary-bind-passwd"/>
                  <Value>adminadmin</Value>
            </AttributeValuePair>
        </OrganizationConfiguration>
      </Configuration>
    </Service>
</ServicesConfiguration>

Creating an Authentication Module Localization Properties File

A localization properties file specifies the screen text that an administrator will see when directed to an authentication module's service page in the OpenSSO Enterprise console as well as messages (error or otherwise) displayed by the module. Following are some concepts behind the creation of this file.

The file is located in OpenSSO-Deploy-base/WEB-INF/classes and follows the naming format amAuthmodulename.properties; for example, amAuthLDAP.properties. Use one of the provided authentication module localization properties files as a template for creating the file and copy it to the aforementioned directory when finished.

Extending the AMLoginModule Class

Custom authentication modules extend the com.sun.identity.authentication.spi.AMLoginModule class and must implement the init(), process() and getPrincipal() methods. The module should also invoke the setAuthLevel() method. Other methods that can be implemented include setLoginFailureURL() and setLoginSuccessURL() which define URLs to which the user is sent based on a failed or successful authentication, respectively. To make use of the account locking feature with custom authentication modules, the InvalidPasswordException exception should be thrown when the password is invalid. These sections contain information on the three main methods.

Implementing the init() Method

init() is an abstract method that initializes the module with relevant information. This method is called by AMLoginModule prior to any other method calls. The method implementation should store the provided arguments for future use. It may peruse the sharedState to determine what information it was provided by other modules, and may also traverse through the options to determine the configuration parameters that will affect the module's behavior. The data can be ignored if the module being developed does not understand it.

Implementing the process() Method

process() is called to perform the actual authentication. For example, it may prompt for a user name and password, and then attempt to verify the credentials. If your module requires user interaction (for example, retrieving a user name and password), it should not do so directly. This method should invoke the handle method of the javax.security.auth.callback.CallbackHandler interface to retrieve and display the appropriate callbacks. The AMLoginModule then internally passes the callback values to the Distributed Authentication User Interface which performs the requested authentication.

Consider the following points while writing the process() method:

Implementing the getPrincipal() Method

getPrincipal() should be called once at the end of a successful authentication session. This method retrieves the authenticated token string which will refer to the authenticated user in the OpenSSO Enterprise environment. A login session is deemed successful when all pages in the module's configuration properties file have been sent and the module has not thrown an exception.

Adding Authentication Post Processing Features

The com.sun.identity.authentication.spi.AMPostAuthProcessInterface interface can be implemented for post processing tasks on authentication success, failure and logout using the methods onLoginSuccess(), onLoginFailure(), and onLogout(), respectively. The Authentication Post Processing Classes are defined in the Core Authentication Service and configurable at several levels such as at the realm or role levels. Post processing tasks might include:

Communicating Authentication Data as XML

Communication between applications and the Authentication Service is conducted using XML messages sent over HTTP(s). The remote-auth.dtd is the template used to format the XML request messages sent to OpenSSO Enterprise and to parse the XML return messages received by the external application. The remote-auth.dtd is in the OpenSSO-Deploy-base/opensso/WEB-INF directory.

XML Messages and remote-auth.dtd

The following sections contain examples of XML messages based on the remote-auth.dtd.


Note –

The client application writes XML messages based on the remote-auth.dtd but, when the messages are sent, the Authentication API adds additional XML code to them. This additional XML is not illustrated in the following examples.


Authentication Request Message from Application

This example illustrates the XML message sent to OpenSSO Enterprise requesting authentication. It opens a connection and asks for LDAP authentication requirements regarding the examplerealm realm to which the user will login.


<?xml version="1.0" encoding="UTF-8"?>
<AuthContext version="1.0">
<Request authIdentifier="0">
<Login realmName="examplerealm">
<IndexTypeNamePair indexType="moduleInstance">
<IndexName>LDAP</IndexName>
</IndexTypeNamePair></Login></Request></AuthContext>

Response Message from OpenSSO Enterprise with Session Identifier and Callbacks

This example illustrates an affirmative response from OpenSSO Enterprise that contains the session identifier for the original request (authIdentifier) as well as callback details.


<?xml version="1.0" encoding="UTF-8"?>
<AuthContext version="1.0">
<Response authIdentifier="AQIC5wM2LY4SfczGP8Kp9
cqcaN1uW+C7CMdeR2afoN1ZxwY=@AAJTSQACMDE=#">
<GetRequirements>
<Callbacks length="3">
<PagePropertiesCallback isErrorState="false">
<ModuleName>LDAP</ModuleName>
<HeaderValue>This server uses LDAP Authentication</HeaderValue>
<ImageName></ImageName>
<PageTimeOutValue>120</PageTimeOutValue>
<TemplateName></TemplateName>
<PageState>1</PageState>
</PagePropertiesCallback>
<NameCallback><Prompt> User Name: </Prompt></NameCallback>
<PasswordCallback echoPassword="false"><Prompt> Password: </Prompt>
</PasswordCallback></Callbacks></GetRequirements></Response></AuthContext>

Response Message from Application with User Credentials

This example illustrates the client's response to OpenSSO Enterprise. It contains the login credentials entered by the user.


<?xml version="1.0" encoding="UTF-8"?>
<AuthContext version="1.0">
<Request authIdentifier="AQIC5wM2LY4SfczGP8Kp9cqca
N1uW+C7CMdeR2afoN1ZxwY=@AAJTSQACMDE=#">
<SubmitRequirements>
<Callbacks length="2">
<NameCallback><Prompt>User Name:</Prompt>
<Value>amadmin</Value>
</NameCallback>
<PasswordCallback echoPassword="false"><Prompt>Password:</Prompt>
<Value>admin123</Value>
</PasswordCallback></Callbacks></SubmitRequirements></Request></AuthContext>

Authentication Status Message from OpenSSO Enterprise With Session Token

This example illustrates the message from OpenSSO Enterprise specifying the user's successful authentication and the session token (SSOToken).


<?xml version="1.0" encoding="UTF-8"?>
<AuthContext version="1.0"><Response authIdentifier="AQIC5wM2LY4SfczGP8Kp9cqcaN1uW+
C7CMdeR2afoN1ZxwY=@AAJTSQACMDE=#">
<LoginStatus status="success" ssoToken="AQIC5wM2LY4SfczGP8Kp9cqcaN1uW+C7CMdeR2afoN1
ZxwY=@AAJTSQACMDE=#" successURL="http://blitz.red.sun.com/opensso/console">
<Subject>AQICOIy3FdTlJoAiOyyyZRTjOVBVWAb2e5MOAizI7ky3raaKypFE3e+GGZuX6chvLgDO32Zugn
pijo4xW4wUzyh2OAcdO9r9zhMU2Nhm206IuAmz9m18JWaYJpSHLqtBEcf1GbDrm3VAkERzIqsvkLKHmS1qc
yaT3BJ87wH0YQnPDze4/BroBZ8N5G3mPzPz5RbE07/1/w02yH9w0+UUFwwNBLayywGsr3bJ6emSSYqxos1N
1bo98xqL4FKAzItsfUAMd6v0ylWoqkoyoSdKYNHKbqvLDIeAfhqgoldxt64Or6HMXnOxz/jiVauh2mmwBpH
q1H2mOeF3agfUfuzKxBpLfELLwCH6QWcJmOZl0eNCFkGl7VwfnCJpTx1WcUhPSg0xD26D3dCQNruJpHPgzZ
FThe55M2gQ2qX+I1klmvzghSqiYfyoGg2SFeBeHE7iHuujO0e6UZgKDrOQPjU9aDh1GxxnsMQmaNkjuW+up
ghruWBGy+mDWmPQTme2bQWPIjBgB4wTDXTedeDzDBeulhCH4M0Ak9lvS7EIv6kHX5pRph6d0ND4/RVHka3k
WcQ5e0w2HpPjOxzNrWMfyXTkQJwOrA8yh1eBjG04VwiVqDV4wAV5EsIsIt0TrtAW2VZwV/KtLcGmjaKaT0H
dwRy0M4DHEqDbc6jF5ItVo9NneGFXMswPIoLm2nLuMrteAt7AtK7FGuCHlfYLavKoROtjaSuYTJGFwgz8Oi
vZ2r9boVnWVlz7ehwlyHvdfmpSKVl76Y4qEclX25m+lddAZE92RgSIrg97fp9gBOk2gVJWoQORNRDV2siHr
26 RiPLdvW3foG0hZgpLimJuLdByThRd/tdknDCCNRzelv7khr6nLPVPFVBgEJWlHmuffkdz4OsL0omFWpi
Jq05sQCPs/q6rq9ZJ98a8mcFK10BVPQki/1VfkIbKAdO4eswsIMalYkglBqXT4ARVTWRCWRNMCTDlQitF3g
T51AHn1WioFPm+NZ2KagVjQR6JFxHbdW0bKN7cLQViArJJFRtktR1BJh31/K+dAM2P+KbT1Lq13UUvXCynS
QwVbf7HJP5m3XrIQ6PtgZs4TB026H+iKy5T85YNL03j9sNnALiIKJEgvGLg2jxG+SU10xNLz3P3UVqmAnQI
9FIjmCtJcFtlLYR6BbkTvZVKxWz6+SoxNfDeKhIDwxkTNTLOzK491KzU/XAZTKmvdxTgf+WikbriBhFjsJ4
M6Npsq4p9Ksrjun9FVBTE/EUT5X/bY8zXLm0nw5KspQ7XRHPwrppQMVMMekz5qrNtQ9Cw/TeOhm4jvww/Bz
j4rydi7s7D10s2BWMfcuxmwQEipAWNmraKL37wWskrCdAzO2HXH4iJjWimiJ6J</Subject>
</LoginStatus></Response></AuthContext>

XML/HTTP(s) Interface for Other Applications

Applications written in a programming language other than Java or C can also exchange authentication information with OpenSSO Enterprise using the XML/HTTP(s) interface and the Authentication Service URL, http://server_name.domain_name:port/opensso/authservice. An application can open a connection using the HTTP POST method. In order to access the Authentication Service in this manner, the client application must contain the following:


Tip –

If contacting the Authentication Service directly through its URL, a detailed understanding of remote-auth.dtd will be needed for generating and interpreting the messages passed between the client and OpenSSO Enterprise.


Customizing Plug-Ins for the Password Reset User Interface

OpenSSO Enterprise provides plug-ins for the Password Reset service. When a user wants to reset their password, the following occurs:

  1. The Password Reset service prompts the user for a userID and for the answer to an individualized security question.

  2. The Password Reset service calls the NotifyPassword.java plug-in. This plug-in notifies the administrator that a user password is being reset.

  3. The Password Reset service then calls the PasswordGenerator.java plug-in. This plug-in generates a new user password based on the developer's specification. If no plug-in is defined, OpenSSO Enterprise generates a random-string password.

You must define the plug-ins using the Password Reset module in the OpenSSO Enterprise console. The customizable code is available on opensso.dev.java.net. See Chapter 13, Password Reset Service, in Sun OpenSSO Enterprise 8.0 Administration Guide and Password Reset in Sun OpenSSO Enterprise 8.0 Administration Reference.