## OpenAM Server - Authentication Samples ### 1. Sample Login Module How to Write Sample Login Module using AMLoginModule SPI (Service Provider Interface)? Create Module properties XML file with the same name of the class (no package name) and have the extension .xml. Based on this configuration file, Authentication UI will dynamically generate page. Note : create XML file with above naming convention even if no states required. Page states can be defined in module properties file as shown below, each Callbacks Element corresponds to one login page state. When an authentication process is invoked, there will be `Callback[]` generated from user's Login Module for each state. All login state starts with 1, then module control the login process, and decides what's the next state to go.
            <ModuleProperties moduleName="LoginModuleSample" version="1.0" >
            <Callbacks length="2" order="1" timeout="60"
                header="This is a sample login page" >
                <NameCallback>
                <Prompt> User Name </Prompt>
            </NameCallback>
            <NameCallback>
                <Prompt> Last Name </Prompt>
            </NameCallback>
            </Callbacks>
            <Callbacks length="1" order="2" timeout="60"
                header="You made it to page 2" >
                <PasswordCallback echoPassword="false" >
                <Prompt> Just enter any password </Prompt>
                </PasswordCallback>
            </Callbacks>
        </ModuleProperties>
In the sample module configuration shown above, page state one has two Callbacks, first callback is for user ID and second is for Last Name. When the user fills in the Callbacks, those Callback[] will be sent to the module, where the module writer gets the submitted Callbacks, validates them and returns. Module writer will set the next page state to 2. Page state two has one Callback to request user to enter password. The `process()` routine is again called after user submits the Callback[]. If the module writer throws an `LoginException`, an 'authentication failed' page will be sent to the user. If no exception is thrown, the user will be redirected to their default page. Click here to view XML. ### 2. Principal Object This object is created by the Authentication framework if authentication succeeded. Source code ### 3. Login Module Login Module writers must subclass `AMLoginModule` class and implement `init()`, `process()`, `getPrincipal()` methods. `AMLoginModule` is an abstract class which implements JAAS `LoginModule`, it provides methods to access OpenAM services and the module XML configuration. Refer javadocs for complete list of methods.
        public void init(Subject subject,Map sharedState, Map options);
This method initializes the login module. If the module does not understand any of the data stored in `sharedState` or options parameters, they can be ignored. This method is called by a `AMLoginModule` immediately after the login module is instantiated. This method may additionally peruse the provided `sharedState` to determine what are additional authentication state that was provided by other login modules; and may also traverse through the provided options to determine what configuration options were specified to affect the login module's behavior. It may save option values in variables for future use.
        public int process(
            javax.security.auth.callback.Callback[] callbacks,
            int state
        ) throws LoginException;
This method is called to authenticate a subject. For example, it prompts for a user name and password, and then attempt to verify the password against a database. If the login module requires some form of user interaction (e.g. retrieving a user name and password), it should not do so directly. That is because there are various ways of communicating with a user, and it is desirable for login module to remain independent of the different types of user interaction. Rather, this method should invoke the handle method of the the `CallbackHandler` which deals with user interaction; and then send the results back to this process method. For instance, user name and password are modeled as `NameCallback` and `PasswordCallback` respectively. The `CallbackHandler` then set the name and password values for these callbacks respectively; and call this process method again to perform authentication. Consider following steps while writing preocess() method. Perform the authentication. If Authentication succeeded, track the principal who has successfully authenticated. Return -1 if authentication succeeds, or throw a login exception such as `AuthLoginException` if authentication fails or return relevant state specified in module configuration XML file. If multiple states are available to the user, the Callback array from a previous state may be retrieved by using the `getCallbak(int state)` methods. The underlying login module keeps the `Callback[]` from the previous states until thes login process is completed. If a module writer need to substitute dynamic text in next state, the writer could use the `getCallback()` method to get the `Callback[]` for the next state, modify the output text or prompt, then call `replaceCallback()` to update the Callback array. This allows a module writer to dynamically generate challenges, passwords or user IDs. Note: Each authentication session will create a new instance of your Login Module Java class. The reference to the class will be released once the authentication session has either suceeded or failed. It is important to note that any static data or reference to any static data in your Login module must be thread-safe.
        public Principal getPrincipal();
This method should be called once at the end of a successful authentication session. A login session is deemed successful when all pages in the Module properties XML file have been sent and the module has not thrown an exception. The method retrieves the authenticated token string that the authenticated user will be known by in the OpenAM environment. Source code ### 4. Setup Perform the following steps Login to OpenAM Console as amadmin. [here] Click on "Configuration" tab. Select "Core" under the Authentication table. Add `com.sun.identity.samples.authentication.spi.providers.LoginModuleSample` to "Pluggable Auth Modules Classes" attribute. Click on save button to save the changes Followings are already set up for you. Compile LoginModuleSample.java and SamplePrincipal.java Copy the compiled classes to web application's WEB-INF/classes directory Copy this XML to web application's config/auth/default directory. ### 5. Run the sample Click here. (If you choose to use a realm other than the root realm, add &org= and the realm name to this URL).