For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

James_Wright_02's avatar
James_Wright_02
Icon for Nimbostratus rankNimbostratus
May 01, 2014

Single sign-on to my IIS Web service

I'm trying to figure out single sign-on for what I thought would be a simple scenario. My F5 (Big-IP 5000, 11.4) is in front of my IIS web service. I want it to authenticate credentials with my radius (to two-factor) authentication then pass the credentials to the web service. The developers tell me that the service has a method for logging in like this:

 

http://webapiurl/api/Authentication/Login?username=username&password=password

 

I tried various random SSO configurations within the F5, then found Collin Walker's article: https://devcentral.f5.com/articles/web-application-login-integration-with-apm.U2KsNPldU25

 

I've tried replicating what he had with the iRule he wrote, but no luck. I'm coming up to speed on the F5, but slowly. Can anyone point me to a resource or a path that can walk me through what I need to do to get this SSO scenario working? There are so many options that I'm a bit lost.

 

Thanks in advance,

 

Jim

 

9 Replies

  • If you do truly authenticate to the web service via user/pass in the URI (yikes by the way), then none of the built-in APM SSO configurations will help you. For this you'll need an iRule and perhaps a little more information about how the web service works. For example, after this (presumably) first request to the web service, are the credentials ever passed again, or 1) does the service generate a session token for subsequent requests, or 2) is the web service intended to be atomic and therefore expects the user/pass in every request?

     

  • I also yiked when I saw that. But, at least it's over an encrypted SSL tunnel. SSL communications never get compromised...

     

    Anyways, I am told that "This function returns some XML with a SessionTokenID which the user has to include in all their subsequent requests."

     

    Thank you for your time, and your response!

     

    Jim

     

  • There might be a few options here, but best to know what the dialog is supposed to look like. Any way you can get a capture of a known good interaction?

     

  • The best I can get at this point is the following email from the developer:

     

    Step 1: Client makes a PUT request to the login method (with username and password in the query string). -http://WebAPI/api/Authentication/Login?username=username&password=password Step 2: WebAPI responds with the SessionDetail XML, containing the SessionTokenID assigned to that user. -GUID… Step 3+: Client makes requests to WebAPI with SessionTokenID in the query string. -http://WebAPI/api/SomeController/SomeMethod?sessiontokenid=GUIDfromStep2

     

  • Okay, so a few additional questions for clarification:

     

    Step 2: WebAPI responds with the SessionDetail XML, containing the SessionTokenID assigned to that user.

     

    1. Does this mean the session token is buried in an XML document?

       

    2. Are you attempting to abstract the user form the initial logon? Is the user no longer a web services client, or do you want to pass an alternate credential form, validate with RSA, and then transform to the required format, or will the web services client continue to communicate as if there's no proxy and you just need to validate the credentials in the URI against RSA before allowing it to pass?

       

  • In regard to question 1, I am trying to extract the user from the initial logon information provided. We are going to have the username from the app be the same as the username in the radius two-factor auth. So I thought I would have the client app provide username, hardwaretoken password, and app password. I’d authenticate the user through the radius, and if it passes, then I would pass on the username and app password to the web service. After that, I just want to let the client program and the web service communicate as they normally would. Although, if I’m proxying with the F5, I assume I would need to store that sessionTokenID too.

     

    In regard to question 2, the developer states: 1.The SessionTokenID is contained in an XML document returned from the server. a. 0VieNR5ZEc3feRNLAAB2PFwpXXUn2usBP3VOvgFGcESV7NtAZAkaxy/lZHu97l8DaHMUMsI/OM3RMfeHfZ26rJdDEiQ1etg45uOiH2N/kseJRb5heTV5yTe8k69gjg== false Demo User Power User

     

    But, if you are going to set it up like you say, you probably do not even care about the XML returned.

     

    We would change the developer guides and the WebAPI help documents to say that the logon request must contain their hardware token password as well, e.g: http://WebAPI/api/Authentication/Login?username=username&password=password&hardwaretokenpassword=hardwaretokenpassword

     

    The F5 could grab the username and hardware token password from the request, do the authentication, and then allow the request to go through to the WebAPI, either stripping the hardware token password off or not (I do not think the WebAPI will care either way).

     

    I really appreciate that you are taking the time to help with this. Thank you!

     

    Jim

     

  • Well, there are two ways to look at this:

     

    1. Provide a complete separate front-end for the client, different auth, and store the SessionTokenID, or

       

    2. Change the initial client request to include user, pass, and token, validate user/pass, strip token, and let every thing else happen naturally. This would probably be the easier option.

       

  • I forgot to ask. Is the client able to consume and relay HTTP cookies? The following is a very crude first stab at this:

    when HTTP_REQUEST {
        HTTP::header insert "clientless-mode" 1
    }
    when ACCESS_SESSION_STARTED {
        if { [HTTP::uri] starts_with "/api/Authentication/Login.php?" } {
            set username [URI::query [HTTP::uri] username]
            set password [URI::query [HTTP::uri] password]
    
            ACCESS::session data set session.logon.last.username $username
            ACCESS::session data set session.logon.last.password $password
        }
    }
    when ACCESS_ACL_ALLOWED {
        HTTP::header replace UPN [ACCESS::session data get session.ldap.last.attr.userPrincipalName]
    }
    

    The idea is this:

    1. The clientless-mode header is inserted within an HTTP_REQUEST event to tell APM to not throw the initial redirect to /my.policy. This is usually an important requirement for non-browser clients.

    2. Assuming the very first request to the APM VIP is the login URI, we'll grab the username and password in the ACCESS_SESSION_STARTED event and assign those to session variables.

    3. With clientless-mode enabled, your visual policy must be "headless", meaning no logon pages, message boxes, or anything that is browser-dependent. At this point we have the two session variables that be plugged directly into an authentication agent (AD/LDAP auth, RSA, etc.).

    4. If all is good, data flow passes to the allow branch in the policy. For demonstration purposes I added an ACCESS_ACL_ALLOWED event that sends an HTTP header to the server in every request, in this case the result of an LDAP query. In your case, you may not need this and simply fail if RSA auth fails.