2
votes

(UPDATE added at end)

I have a native iOS MobileFirst (7.0) client written in Swift. The MobileFirst Server is behind a firewall and accessed though a junction on IBM Security Access Manager for Web (ISAM). ISAM is being used for adapter authentication. I've already tested the app without ISAM in the middle (no authentication), and it works fine.

A custom challenge handler is registered:

let myCH = MyChallengeHandler(vc: self) 
WLClient.sharedInstance().registerChallengeHandler(myCH)

MyChallengeHandler sets the realm in its init() function:

init(vc: LoginViewController){
   self.vc = vc
   super.init(realm: "HeaderAuthRealm")
}

The app first connects to the server using wlConnectWithDelegate:

WLClient.sharedInstance().wlConnectWithDelegate(ConnectListener(vc: self))

And once the connection is made, it should call a adapter method on the server to look up the user info (using invokeProcedure):

    let invocationData = WLProcedureInvocationData(adapterName: "login", procedureName: "lookUpRole")
    invocationData.parameters = [userid]
    WLClient.sharedInstance().invokeProcedure(invocationData, withDelegate: LoginListener(vc: self))

However it's not getting that far.

When ISAM is involved, it is protecting everything, include the connect URL, so the challenge handler is first getting called when the wlConnectWithDelegate() is attempted because ISAM returns a login page.

The challenge handler is properly detecting the login page and the handleChallenge() function is being called. Userid/password is collected from the user if necessary, and then it calls a function that calls submitLoginForm(). The custom onConnect() and onFailure() functions are defined in the challenge handler as well:

override func handleChallenge(response: WLResponse!)
{
    handleChallengeISAM(response)
}

func handleChallengeISAM(response: WLResponse!)
{
    //HPDIA0200W Authentication failed. You have used an invalid user name, password or client certificate.
    let failedLogin = response.responseText.rangeOfString("HPDIA0200W") != nil

    if vc.security.authDataSet && !failedLogin
    {
        println("=========== Sending login data directly")
        submitISAMAuthData()
    }
    else
    {
        println("=========== A login screen form should appear")
        if failedLogin {
            needCredentials("Please check your credentials.")
        } else {
            needCredentials(nil)
        }
    }
}

func submitISAMAuthData()
{
    let loginPostUrl = "https://wstest.clearlake.ibm.com/pkmslogin.form"
    let params = ["username" : vc.security.userid , "password" : vc.security.password, "login-form-type" : "pwd"]

    println("=========== Sending submitLoginForm request")
    self.submitLoginForm( loginPostUrl, requestParameters: params, requestHeaders: nil, requestTimeoutInMilliSeconds: -1, requestMethod: nil)
    println("=========== submitLoginForm request Sent")

}

override func onSuccess(response: WLResponse!)
{
    println("=========== onSuccess")
    let  isLoginResponse = isCustomResponse(response)
    if isLoginResponse {
        println("=========== RE-challenged")
        handleChallenge(response)
    } else {
        println("=========== Challenge success")
        submitSuccess(response)
    }
}

override func onFailure(response: WLFailResponse!)
{
    println("=========== Challenge failure")
    println("\(response.errorMsg)")
    submitFailure(response)
}

The problem is that is as far as it gets. The request never gets to the ISAM device, and the onSuccess() or onFailure() functions are never called. The iOS simulator log states that the request was made, but that's it. No indication that it actually did anything.

=========== Sending submitLoginForm request
2015-04-09 15:00:12.866 ThirdPartyCompliance[54200:2903010] [DEBUG] [WL_AFHTTPCLIENTWRAPPER_PACKAGE] +[WLAFHTTPClientWrapper requestWithURL:] in WLAFHTTPClientWrapper.m:46 :: Request url is https://wstest.clearlake.ibm.com/pkmslogin.form
2015-04-09 15:00:12.871 ThirdPartyCompliance[54200:2903010] [DEBUG] [WL_REQUEST] -[WLRequest sendRequest:path:withOptions:] in WLRequest.m:141 :: Request timeout is 10.000000
2015-04-09 15:00:12.876 ThirdPartyCompliance[54200:2903010] [DEBUG] [WL_REQUEST] -[WLRequest sendRequest:path:withOptions:] in WLRequest.m:220 :: Sending request (https://wstest.clearlake.ibm.com/pkmslogin.form) with headers: 
{
    "Accept-Language" = en;
    "User-Agent" = "ThirdPartyCompliance/1 (iPad Simulator; iOS 8.2; Scale/2.00)/WLNativeAPI/7.0.0.0";
    "X-Requested-With" = XMLHttpRequest;
    "x-wl-app-version" = "1.0";
    "x-wl-device-id" = "C1CFD648-C648-439C-AC9F-8292FDAC20E6";
    "x-wl-platform-version" = "7.0.0.0";
}
You can see the request body in the Analytics platform logs.
=========== submitLoginForm request Sent

The ISAM logs don't show the submitLoginForm request ever being sent despite what the iOS MobileFirst API logs say. Is something wrong with submitLoginForm() in v7.0?

UPDATE:

It seems that WLClient.sharedInstance().wlConnectWithDelegate() has to succeed before ChallengeHandler.submitLoginForm() will work. I verified this by using a proxy server in front of the ISAM device to send adapter service requests through ISAM, and all other MobileFirst server connections bypass ISAM. In this architecture, the submitLoginForm() function works fine, since wlConnectWithDelegate() is succeeding without login.

This is a little confusing since the ChallengeHandler is called when using wlConnectWithDelegate(), but some of the ChallengeHandler's methods don't yet work until after wlConnectWithDelegate() finishes. Also I can't find it documented anywhere that it works this way.

1
Did you inspect the network using Wireshark (try though w/out HTTPS) to see where/what the request is and if it's containing everything it should? - Idan Adar
BTW, I am not sure how it goes with ISAM but typically in an authentication scenario you'll need to set the submit authentication adapter procedure with securityTest="wl_unprotected" because that specific request can't be protected, as it's the one which starts the negotiations. - Idan Adar
Yeah, I'm wondering if the submitLoginForm() call doesn't work because the API hasn't yet connected to the server. We're considering trying to make the app connect-related URLs unprotected, but it's not trivial. I was hoping for an authoritative word on how it works. - Todd Phillips
Also, we haven't done any packet analysis. I was hoping I wouldn't have to, but I'll look into it. - Todd Phillips
I installed Wireshark. I am connected to the server network using a VPN so I can't inspect packets. However I was able to determine that there was no network traffic when the app called submitLoginForm(). - Todd Phillips

1 Answers

1
votes

When ISAM is protecting all the resources between the Mobile app and MFP server, the initial call by wlConnectWithDelegate() will fail, as the call will not go up to the MFP Server. The initial connection URL/s have to be left unprotected (unauth in ISAM).

This link http://www-01.ibm.com/support/docview.wss?uid=swg24034222 contains the integration solution between ISAM and worklight/Mobile First 7.x. In v3.6 integration solution, there is a guide for Form Based Login integration (isam_impf_loginform_int_guide.pdf). The URLs given below are the ones that need to be left unprotected, without which the initial connection/certificate based connection/DirectUpdate will be unsuccessful.

/WebSEAL/<webseal-host-name>-<instance-name>/<context-root>/apps/services/api/<application_name>/<platform>/init 

/WebSEAL/<webseal-host-name>-<instance-name>/<context-root>/apps/services/api/<application_name>/<platform>/authenticate 

/WebSEAL/<webseal-host-name>-<instance-name>/<context-root>/directUpdate/<application_name>/<platform> 

/WebSEAL/<webseal-host-name>-<instance-name>/<context-root>/authorization/v1/clients/instance 

I hope this helps.