IBM Support

Configuring Maximo Anywhere behind an ISAM Authenticating Proxy Server Part Two

Technical Blog Post


Abstract

Configuring Maximo Anywhere behind an ISAM Authenticating Proxy Server Part Two

Body

Our first article on configuring Maximo Anywhere behind an Authenticating proxy server used a simple Basic Authentication HTTP Server.  A more common example is to use an Authenticating server like ISAM or WebSeal.

This assumes that your Maximo server is configured in SSO, to trust the Authentication that WebSeal/ISAM provides.  Usually this is done through exchanging LTPATokens, and having the ISAM server pass the LTPAToken through to the MobileFirst and Maximo server.

 

Maximo Anywhere App Customization

To configure Maximo Anywhere you need to make a few changes to the running application to get it to detect and response to the ISAM proxy server instead of the MobileFirst server.

Change these methods and fields in the out of the box CustomChallengeHandler:

The CUSTOM_AUTH_URL is a local variable in CustomChallenge handler that points to the url of the form that is presented to the user if they are not successfully logged into ISAM.  This URL is used to submit the user credentials to ISAM.  Make sure it is set correctly to the form that ISAM presents when a user is not authenticated.

//This is where you need to set your special WebSeal Auth URL
        CUSTOM_AUTH_URL: '<yourserverhostnameandport>/pkmslogin.form',
        
 The isCustomResponse method is searching for a response from ISAM to determine that the user needs to reauthenticate.  This usually happens when the session times out.  Our specific ISAM login form has text on the panel that says "pkmslogin.form". You can see us searching for that below.  If you return true, then this indicates to our framework that the user needs to login, so we present the login form within the application, and trigger the CustomChallengeHandler.login method after the login button is clicked.


         * This method looks for the PKMS response from WebSeal which indicates that we are not authenticated
         */
        isCustomResponse: function(response) {

            //Need to skip init and login in case they're blocked by the proxy, they will be resent automatically by worklight
            if (response.request.url.indexOf('init') > 0 || response.request.url.indexOf('login') > 0 || response.request.url.indexOf('loguploader') > 0) {
                return false;
            }
            
            // If there is no response just return false
            if (!response || response.responseText === null) {
                Logger.trace('[CustomChallangeHandler.isCustomResponse] - No response found');    
                return false;
            }
    
            // This is a response from the worklight server so return false, we can assume we're authenticated
            if (response.responseText.indexOf("/*-secure-") == 0) {
                Logger.trace('[CustomChallangeHandler.isCustomResponse] - found a worklight response');        
                return false;
            }            
            
            //This is the response from the WebSeal proxy
            if (response.responseText.search("pkmslogin.form") >= 0) {
                Logger.trace('[CustomChallangeHandler.isCustomResponse] - pkmslogin.form challenge');        
                return true;
            }
            
            else {
                Logger.trace('[CustomChallangeHandler.isCustomResponse] false');
                return false;
            }
        },        

 

This is the overridden login method of CustomChallengeHandler, notice that it sends the login form data to the updated CUSTOM_AUTH_URL (in this case ISAM, not MobileFirst).  It also looks for the pkmslogin.form text to determine whether the login was successful or not.

/*
         * Send Login credentials to your authentication service, you are passed a user and password from the login form
         *
         * ATTN: You do not return a response to this method, you resolve or reject the passed in deferred thread
         * based on the asynchronous response from the server.
         *
         * If you override this method, don't forget to indicate that you're in the middle of authentication
         * by setting and checking the isAuthenticating boolean to handle possible multiple threads.
         *
         */
        login: function(user, pwd, deferred) {
        
            this.isAuthenticating = true;
            var self = this;
                //Notice the new form type below.
                var loginOptions =
                {
                    headers    : {},
                    parameters : {
                        username : user,
                        password : pwd,
                        'login-form-type' : 'pwd'
                    }
                };    

                    Logger.trace('CustomChallengeHandler login calling submitLoginForm');
                    
                    var afterSubmit = function(response) {
                        Logger.trace('CustomChallengeHandler.sendLogin');
                        //Validate that the pkmslogin form is no longer prompting
                        if (response.responseText.search("pkmslogin.form") < 0) {                        
                            Logger.trace('[CustomChallengeHandler] User successfully authentication against realm "' + self.REALM + '"');                                
                            deferred.resolve(response);
                            self.isAuthenticating = false;
                        }
                        else{
                            //Still being prompted by pkmslogin, so the response must be invalid
                            deferred.reject(response);
                            self.isAuthenticating = false;
                        }
                    };
                    //Actually submit the form to PKMS
                    self.submitLoginForm(self.getAuthURL(), loginOptions, lang.hitch(self,afterSubmit));

        },

        
                

Configure the MaximoAnywhere runtime to trust the Authenticating Proxy Server:

Since the authenticating proxy is performing all of the authentication, we want for the standard Maximo Anywhere Login Module to just act as a noop pass through and allow all traffic back to the Maximo server.  We assume that your Maximo server will be looking for a cookie to be set by the proxy server.  We have provided an out of the box authentication module that supports this noop.  It merely confirms that a cookie exists in the inbound request for data.  As long as that cookie exists, we allow the request through to the Maximo server.

Change your MaximoAnywhere/server/conf/authenticationConfig.xml file to use this noop authentication module and rebuild/redeploy your MaximoAnywhere war.  It's realms and loginModule section should look like this:

 <realms>
        <!-- For other proxy servers -->
         <realm name="CustomAuthenticationRealm" loginModule="AnywhereProxyLoginModule">
            <className>com.ibm.tivoli.si.auth.AnywhereProxyCustomAuthenticator</className>
        </realm>
    </realms>

<loginModules>
        <!-- For other proxy servers -->
        <loginModule name="AnywhereProxyLoginModule">
            <className>com.ibm.tivoli.si.auth.AnywhereProxyCustomLoginModule</className>
        </loginModule>
    </loginModules>

[{"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SSLKT6","label":"IBM Maximo Asset Management"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB59","label":"Sustainability Software"}}]

UID

ibm11130493