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.
Create a callback requirements file for the new authentication module.
Implement a Principal class.
Create a service file for the new authentication module.
(OPTIONAL) Create a localization properties file for the new authentication module.
Develop the custom authentication module.
(OPTIONAL) Add post processing features.
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.
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.
Restart OpenSSO Enterprise.
The custom authentication module is now listed under the Configuration tab as an Authentication option.
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)?.
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.
<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<BR></BR>#REPLACE#<BR></BR>" > <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:
The values are sent to the module.
The process() routine validates the values.
If the module writer throws a LoginException, an Authentication Failed page will be sent to the user. If no exception is thrown, the user is redirected to his or her default page.
If the user's password is expiring, the module writer sets the next page state to 2.
Page state 2 requires the user to change a password. The process() routine is again called after the user submits the appropriate values.
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.
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.
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.
<?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>
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 data following the equal (=) sign in each key/value pair could be translated to a specific language as necessary.
The alphanumeric keys (a1, a2, etc.) map to fields defined by the i18nKey attribute in the corresponding amAuthmodulename.xml service file.
The alphanumeric keys also determine the order in which the fields are displayed in the OpenSSO Enterprise console. The keys are taken in the order of their ASCII characters (a1 is followed by a10, followed by a2, followed by b1). For example, if an attribute needs to be displayed at the top of the service attribute page, the alphanumeric key should have a value of a1. The second attribute could then have a value of either a10, a2 or b1, and so forth.
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.
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.
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.
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:
Perform the authentication and if successful, save the authenticated principal.
Return -1 if authentication succeeds.
Throw an exception, such as AuthLoginException, if authentication fails or return the relevant state specified in the module's configuration properties file
Throw an exception, such as InvalidPasswordException, if using the Login Failure Lockout feature
If multiple states are available to the user, the Callback array from a previous state may be retrieved by using the getCallback() method. The underlying login module keeps callback information from previous states until the login process is completed.
If a module needs to substitute dynamic text (generate challenges, passwords or user identifiers) in the next state, use the getCallback() method to retrieve the callback for the next state, modify the text, and call replaceCallback() to update the array.
Each authentication session will create a new instance of your module's Java class. The reference to the class will be released once the authentication session has either succeeded or failed.
Any static data or reference to any static data in your module must be thread-safe.
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.
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:
Adding attributes to a user’s session token after successful authentication.
Sending notification to an administrator after failed authentication.
General clean up such as clearing cookies after logout, or logging out of other system components.