Forum Discussion

jk20004_44080's avatar
jk20004_44080
Icon for Nimbostratus rankNimbostratus
Aug 22, 2016

clientless-mode and 401 for poor client

i tried to create a APM Policy for a poor webclient which cannot follow a 302. my try was to use the clientless-mode and an very simple APM Policy.

and a even easier iRule

The Problem is that APM always uses the Negotiate exit although the "HTTP Auth Level" is set to Basic and with klist you can see that he will not request a Kerberos Ticket and also NTLM will fail.

On the client side the consistent result is a 302 to /vdesk/hangup.php3

also the APM log shows the same:

01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 3, name = From, value = Start
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 4, name = To, value = HTTP 401 Response
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 5, name = Rule, value = fallback
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 6, name = Agent, value = /Common/ap-git-test-intern_act_http_401_response_ag
01490000:7: modules/LogonPage/SimpleLogonPage/SimpleLogonPageAgent.cpp func: "SimpleLogonPageAgentexecuteInstance()" line: 1283 Msg: SCIM session state variables: Request Type : Request Domain : GroupName : UserName : ClearCache:0
01490000:7: ./AccessPolicyProcessor/SessionState.h func: "clearTempSessionAgentState()" line: 110 Msg: Agent did not initiated the scheduled agent
01490000:7: AccessPolicyProcessor/AccessPolicy.cpp func: "execute()" line: 532 Msg: Let's evaluate rules, total number of rules for this action=3
01490000:7: AccessPolicyProcessor/AccessPolicy.cpp func: "execute()" line: 538 Msg: Rule to evaluate = "expr {[mcget {session.logon.last.authtype}] == "Basic"} "
AccessPolicyProcessor/AccessPolicy.cpp func: "execute()" line: 538 Msg: Rule to evaluate = "expr { [mcget {session.logon.last.authtype}] == "Negotiate" }"
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 7, name = From, value = HTTP 401 Response
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 8, name = To, value = Deny
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 9, name = Rule, value = Negotiate
01490005:5: /Common/ap-git-test-intern:Common:1e9097c6: Following rule 'Negotiate' from item 'HTTP 401 Response' to ending 'Deny'
01490000:7: queue.cpp func: "setMarker()" line: 377 Msg: queue::setMarker: thread id 1628416880, step 10, name = Agent, value = /Common/ap-git-test-intern_end_deny_ag
01490102:5: /Common/ap-git-test-intern:Common:1e9097c6: Access policy result: Logon_Deny

i started with a multidomain sso version (Company default) but after reading some DevCentral contributions about the clientless-mode i switch to the Single Domain version first and i also found and tested a note about the need of a Logon-Page in front without any result, the APM always uses the Negotiate exit.

To send the 401 via irule and set the username/password in the APM Session works a little bit better but the SSO Config to the backend Server fails.

  • Hi,

    When clientless mode is enable, VPE become non-interactive.

    You must include in the irule how to respond. you can use this irule (replace the 401 response by a logon page box)

    when HTTP_REQUEST {
        set apmsessionid [HTTP::cookie value MRHSession]
            if { [HTTP::cookie exists "MRHSession"] } {set apmstatus [ACCESS::session exists -state_allow $apmsessionid]} else {set apmstatus 0}   
            if { !($apmstatus)} {
                if { [ string match -nocase {basic *} [HTTP::header Authorization] ] == 1 } {
                    set clientless(insert_mode) 1
                    set clientless(username)    [ string tolower [HTTP::username] ]
                    set clientless(password)    [HTTP::password]
                    binary scan [md5 "$clientless(password)"] H* clientless(hash)
                    set user_key "$clientless(username).$clientless(hash)"
                    set clientless(cookie_list)             [ ACCESS::user getsid $user_key ]
                    if { [ llength $clientless(cookie_list) ] != 0 } {
                        set clientless(cookie) [ ACCESS::user getkey [ lindex $clientless(cookie_list) 0 ] ]
                        if { $clientless(cookie) != "" } {
                            HTTP::cookie insert name MRHSession value $clientless(cookie)
                            set clientless(insert_mode) 0
                        }
                    }
                 if { $clientless(insert_mode) } {
                    HTTP::header insert "clientless-mode" 1
                    HTTP::header insert "username" $clientless(username)
                    HTTP::header insert "password" $clientless(password)
                }
                unset clientless
              } else {
                HTTP::respond 401 noserver WWW-Authenticate "Basic realm=\"[HTTP::host] Authentication\"" Set-Cookie "MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/" Connection close
                return
                }
       }
    }
    when ACCESS_SESSION_STARTED {
        if { [info exists user_key] } then {
            ACCESS::session data set {session.user.uuid} $user_key
        }
    }
    
    when ACCESS_POLICY_COMPLETED {
       if { ([ACCESS::policy result] equals "deny") } {
        set host [ACCESS::session data get "session.network.name"]
          ACCESS::respond 401 noserver WWW-Authenticate "Basic realm=\"$host Authentication\"" Connection close
          ACCESS::session remove
       } 
    }