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

Jason_41583's avatar
Jason_41583
Icon for Nimbostratus rankNimbostratus
May 12, 2013

APM authentication User ID changed by application query

Hello all.

 

 

I have kind of strange situation that I am trying to sort out, we ahve an existing application that is going to use the APM for authentication but our problem is the existing app has 1000s of users with application specfic Login User IDs that are not associated with our AD server so currently the application looks up the app specfic ID in a database to find the SAM account name then authenticates the user against AD the passwords are the same just the userid is the problem, Is there a way for the APM to replicate this function.

 

 

Proposed Application flow

 

 

User is directed to the APM for login --> user enters site username and password --> APM needs to send username to server and server will return sam accountname to be used to authenticate against AD --> APM will then take the returned sam account name and user supplied password from the login page and authenticate against AD --> Upon successful AD authentication allow user access to site adding orginal login userid to the header.

 

 

 

Please let me know if this can be accomplished and what would be the best way to accompish this.

 

 

 

thanks in advance,

 

 

Jason

 

6 Replies

  • The answer is yes, no, and possibly. Yes APM can perform lookups, but no it can't talk directly to a (SQL) database. You can, possibly, still get this to work if you're willing to stand up a web service in front of your database to handle the actual DB querying. In this fashion, APM can perform a sideband call to the web service, mid-policy, and query for the SAM. In any case, most of the authentication agents in the visual policy require the same two session variables: session.logon.last.username and session.logon.last.password. The logon page also produces the same two variables, so between the logon page, the sideband call (via iRule agent), and the AD auth agent, you'll need to store the real username into a separate variable so that the SAM value can be written into the username variable.

     

     

    Alternatively, if you can store these application account values in the AD user account (via added schema objects) then you can do an AD/LDAP query directly in APM, which would be much simpler.
  • Thanks Kevin, great suggestion. we got the development team to stand up a web API that will answer with the SAM when sent a GET request with the client username so now I have to figure out the iRule to pull it together hopefully I will get that sorted out today and post the results.

     

     

    thanks.

     

     

    Jason
  • How about something like this:

    
    when RULE_INIT {
     enable or disable debug logging
    set static::rule_debug 1
    }
    when ACCESS_POLICY_AGENT_EVENT {
         switch [ACCESS::policy agent_id] {
              "LOOKUP" {
                    set ws server connection (direct or virtual name if load balancing)
                   set server "10.70.0.1:80"
    
                    establish the connection
                   set conn [connect -timeout 3000 -idle 30 -status conn_status $server]
    
                    if the conenction fails - log and exit
                   if { $conn eq "" } {
                        if { $static::rule_debug } { log local0. "Sideband WS call failed" }
                   }
    
                    establish the query parameter (derived from access session data?)
                   set getdata "/samlookup.php?user=ted"
    
                    establish request string
                   set data "GET $getdata HTTP/1.0\r\n\r\n"
    
                    send the data
                   set send_info [send -timeout 3000 -status send_status $conn $data]
    
                    receive the data
                   set recv_data [recv -status recv_status -timeout 30 $conn]
    
                    close the connection
                   close $conn
    
                    find the payload after the response headers
                   set payload [findstr $recv_data "\r\n\r\n" 4 " "]
    
                    create a new access session variable with the paylaod data
                   if { $payload ne "" } {
                        ACCESS::session data set session.custom.sam [string trim $payload]
                        if { $static::rule_debug } { log local0. "payload = $payload" }
                   }
              }
         }
    }
    

    This is a VERY simple example of a sideband call, so you'll likely have to modify to suit your needs. Edit the server, getdata, and data variables for your own environment, and then create an iRule event agent in your APM visual polciy with an ID of "LOOKUP". If it works it'll create a new session variable called session.custom.sam.

  • Thanks Kevin for all of the help you saved me at least a couple of weeks of trial and error. Below is the iRule that I have which I think is just about right - if you have a second please look it over and let me know if I should change anything.

     

     

    Thanks again.

     

     

    Jason

     

     

     

    Irule:

     

     

     

    when ACCESS_POLICY_AGENT_EVENT {

     

    if { [ACCESS::policy agent_id] eq "change_username" } {

     

     

    get client login

     

    set SKlogin [ACCESS::session data get "session.logon.last.username"]

     

    open the connection to SK-API

     

    set conn [connect -timeout 100 -idle 30 -status conn_status 192.168.1.99:80]

     

    log local0. "Lookup Log: Connection returns $conn and status $conn_status "

     

     

    Now request the SamAccountName

     

    !!for prod use real get string!! GET /api/security/GetADUsername?skUsername=$SK-login

     

     

    set req "GET /$SKlogin HTTP/1.0\r\n\r\nConnection: Close\r\n\r\n"

     

    log local0. "Request is: $req"

     

    set send_info [send -timeout 200 -status send_status $conn $req]

     

    log local0. "Send status is: $send_status"

     

    set recv_data [recv -timeout 200 -status recv_status $conn]

     

    log local0. "Recieve status: $recv_status and data: $recv_data"

     

     

    close the connection

     

    close $conn

     

     

     

    find the payload after the response headers

     

    set SAM [findstr $recv_data "user=" 5 " "]

     

     

    create a new access session variable with the paylaod data

     

     

    if { $SAM ne "" } {

     

    Set a SamAccountName session variable to the value 'SAM'

     

    ACCESS::session data set session.temp.username [string trim $SAM]

     

    log local0. "SAM= $SAM"

     

    }

     

    }

     

    }
  • Other than maybe throwing in some catch statements and other error logic, it looks good.
  • Kevin,

     

     

    Thanks for all of your help on this, I have one last issue with this deployment the application team wants to use their login page hosted on the server the application is on. Is there a way to call their login page and preform the same lookup ? I tried using the following which needs help but it does not seem to being getting called anyway; any guidance you have is greatly appreciated.

     

     

    thanks,

     

     

    Jason

     

     

    Begin iRULE:

     

     

    when HTTP_REQUEST {

     

     

    Check the requested HTTP path

     

    switch -glob [string tolower [HTTP::path]] {

     

    "/api/*" -

     

    "api" -

     

    "/api/" {

     

    Enable APM for these paths

     

    ACCESS::enable

     

    }

     

    default {

     

    Disable APM for all other paths

     

    ACCESS::disable

     

    }

     

    }

     

     

     

     

    Check for post requests to Login URI

     

    if {[HTTP::uri] starts_with "/api/security/Login" && [HTTP::method] eq "GET"}{

     

     

    Collect up to 1Mb of request content

     

    if { [HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] < 1048577 } {

     

    set content_length [HTTP::header "Content-Length"]

     

    } else {

     

    set content_length 1048576

     

    }

     

    if { $content_length > 0 } {

     

    HTTP::collect $content_length

     

    }

     

    }

     

    }

     

     

    when HTTP_REQUEST_DATA {

     

    Parse the username and password from the collected payload

     

    set SKlogin [HTTP::username]

     

    set password [HTTP::password]

     

    HTTP::release

     

    }

     

     

    when ACCESS_SESSION_STARTED {

     

    if { [ info exists username ] } {

     

     

    get client login

     

    set SKlogin [ACCESS::session data get "session.logon.last.username"]

     

    open the connection to SK-API

     

    set conn [connect -timeout 100 -idle 30 -status conn_status 172.19.16.100:5538]

     

    log local0. "Lookup Log: Connection returns $conn and status $conn_status "

     

     

     

     

    set req " GET /api/security/GetADUsername?skUsername=$SKlogin HTTP/1.0\r\n\r\nConnection: Close\r\n\r\n"

     

    log local0. "Request is: $req"

     

    set send_info [send -timeout 200 -status send_status $conn $req]

     

    log local0. "Send status is: $send_status"

     

    set recv_data [recv -timeout 200 -status recv_status $conn]

     

    log local0. "Recieve status: $recv_status and data: $recv_data"

     

     

    close the connection

     

    close $conn

     

     

     

    find the payload after the response headers

     

    set SAM [findstr $recv_data "user=" 5 " "]

     

     

    create a new access session variable with the paylaod data

     

     

    if { $SAM ne "" } {

     

    Set a SamAccountName session variable to the value 'SAM'

     

    ACCESS::session data set session.temp.username [string trim $SAM]

     

    log local0. "SAM= $SAM"

     

     

     

    HTTP::header insert "X-USERNAME" $SAM

     

     

     

     

    }

     

    }

     

    }