Citrix_APM

Problem this snippet solves:

Contributed by: F5 Solutions Engineering - solutionsfeedback at f5.com

===Description=== With the combination of BIG-IP Access Policy Manager (APM) and Citrix XenApp, organizations can deliver a complete remote access solution that allows for scalability, security, compliance and flexibility.

This iRule comprises the first part of two iRules that are part of the Citrix Secure Access deployment. The complete installation instructions for this setup will be located in the solutions section of F5.com shortly.

With this iRule, users can connect using BIG-IP APM's secure proxy mode, allowing for connections to XenApp from a variety of clients including Citrix Receiver, PN Agent and Dazzle.

Code :

when RULE_INIT {
       set tmm_apm_pnagent_url "/Citrix/PNAgent/config.xml"
   }
   when CLIENT_ACCEPTED {
       TCP::collect 7
   }
   when CLIENT_DATA {
       # Disable SSL if it's HTTP CONNECT request
       if { [TCP::payload 7] equals "CONNECT" } {
           SSL::disable
       }
       TCP::release
   }
   when HTTP_REQUEST {
       set tmm_apm_host [HTTP::host]
       set tmm_apm_uri_path [HTTP::path]
       set tmm_apm_user_agent [HTTP::header "User-Agent"]
       set tmm_apm_http_method [HTTP::method]
       set tmm_apm_session_id ""
       set tmm_apm_citrix_receiver 0
       set tmm_apm_citrix_pnagent  0
       set tmm_apm_citrix_nongateway 0
       set tmm_apm_citrix_ica_patching  0
       set tmm_apm_vip  "$tmm_apm_host:[TCP::local_port clientside]"

       log -noname accesscontrol.local1.debug "01490000

       if { [HTTP::cookie exists "MRHSession"] } {
           set tmm_apm_session_id [HTTP::cookie "MRHSession"]
       }
       if { $tmm_apm_user_agent contains "CitrixReceiver" } {
           set tmm_apm_citrix_receiver 1
       } elseif { ($tmm_apm_user_agent contains "PNAMAIN") or
                  ($tmm_apm_user_agent contains "PNAMain") or
                  ($tmm_apm_user_agent contains "pnamain") or
                  ($tmm_apm_user_agent contains "Dazzle") or
                  ($tmm_apm_user_agent contains "Darwin") } {
           set tmm_apm_citrix_pnagent  1
       }
       if { $tmm_apm_http_method equals "CONNECT" } {
           if { ![HTTP::header exists "Proxy-Authorization"] } {
               HTTP::respond 407 Proxy-Authenticate "Basic realm=\"123\""
               return
           }
           set authstr [lindex [ split [HTTP::header "Proxy-Authorization"] " " ] 1 ]   
           set remainder [lindex [split [expr [string length $authstr] / 4.0 ] "." ] 1]
           if { $remainder != "0" } {
               if { [regsub -all {(A=)} $authstr = newstring] > 0 } {
                   set authstr $newstring
               }
           }
           set apm_session [ lindex [ split [b64decode $authstr] ":" ] 0 ]
           if { ![ACCESS::session exists $apm_session] } {
               HTTP::respond 407 Proxy-Authenticate "Basic realm=\"123\""
               return
           }
           log -noname accesscontrol.local1.debug "01490000
           ACCESS::disable
           use virtual citrix_connect_proxy
       }
       if { ($tmm_apm_session_id == "") && ($tmm_apm_citrix_pnagent == 1) } {
           HTTP::header insert "clientless-mode" 1
           HTTP::header insert "username" ""
           HTTP::header insert "password" ""
           if { $tmm_apm_uri_path equals $::tmm_apm_pnagent_url } {
               ACCESS::disable
               return
           }
           if { ![info exists tmm_apm_citrix_username] && [HTTP::header exists "Content-Length"] } {
               HTTP::collect [HTTP::header Content-Length]
           }
       }
       if { $tmm_apm_citrix_receiver == 1 } {
    if { $tmm_apm_uri_path starts_with "/Citrix/PNAgent/" } {
               if { $tmm_apm_uri_path equals $::tmm_apm_pnagent_url } {
                   ACCESS::disable
                   return
               }
               if { ![info exists tmm_apm_citrix_username] } {
    HTTP::header insert "clientless-mode" 1
    HTTP::header insert "username" ""
    HTTP::header insert "password" ""
                   if { [HTTP::header exists "Content-Length"] } {
                       set tmm_apm_citrix_receiver 0
                       set tmm_apm_citrix_pnagent 0
                       set tmm_apm_citrix_nongateway 1
        HTTP::collect [HTTP::header Content-Length]
                   }
               } else {
    HTTP::header insert "username" $tmm_apm_citrix_username
    HTTP::header insert "password" $tmm_apm_citrix_password 
               }
    } elseif { $tmm_apm_uri_path equals "/cgi/login" } {
HTTP::header insert "clientless-mode" 1
HTTP::header insert "username" ""
HTTP::header insert "password" ""
HTTP::cookie remove MRHSession
HTTP::collect [HTTP::header Content-Length]
    } elseif { $tmm_apm_uri_path equals "/ipad" } {
set AD_only "citrixreceiver://createprofile/?s=$tmm_apm_host&pname=Profile-$tmm_apm_host&gw=1&gwt=2&gwa=1"
set RSA_only "citrixreceiver://createprofile/?s=$tmm_apm_host&pname=Profile-$tmm_apm_host&gw=1&gwt=2&gwa=2"
set AD_RSA "citrixreceiver://createprofile/?s=$tmm_apm_host&pname=Profile-$tmm_apm_host&gw=1&gwt=2&gwa=3"
HTTP::respond 200 content "

Click here for domain only authClick here for RSA onlyClick here for Two-factor auth

" } } } when HTTP_REQUEST_DATA { if { ($tmm_apm_citrix_pnagent != 1) && ($tmm_apm_citrix_receiver != 1) && ($tmm_apm_citrix_nongateway != 1) } { return } set payload [HTTP::payload] if { $tmm_apm_citrix_receiver == 1 } { log -noname accesscontrol.local1.debug "01490000 set tmm_apm_citrix_username "" set tmm_apm_citrix_password "" set tmm_apm_citrix_password1 "" set urlvars [ split $payload "&" ] foreach {u} $urlvars { set param [ lindex [ split $u "=" ] 0 ] set value [ lindex [ split $u "=" ] 1 ] if { $param equals "login" } { set tmm_apm_citrix_username $value } elseif { $param equals "passwd" } { set tmm_apm_citrix_password $value } elseif { $param equals "passwd1" } { set tmm_apm_citrix_password1 $value } } HTTP::header replace "username" $tmm_apm_citrix_username HTTP::header replace "password" $tmm_apm_citrix_password HTTP::release } elseif { ($tmm_apm_citrix_pnagent == 1) || ($tmm_apm_citrix_nongateway == 1) } { if { $tmm_apm_citrix_nongateway == 1 } { set tmm_apm_citrix_receiver 1 } log -noname accesscontrol.local1.debug "01490000 set tmm_apm_citrix_username "" set tmm_apm_citrix_password "" if { [regexp -nocase {([^<]+)} $payload dummy tmm_apm_citrix_username] == 0 } { set tmm_apm_disp_sess_id [string range $tmm_apm_session_id 24 32] log -noname accesscontrol.local1.error "01490000 return } if { [regexp -nocase {]+>([^<]+)} $payload dummy tmm_apm_citrix_password] == 0 } { set tmm_apm_disp_sess_id [string range $tmm_apm_session_id 24 32] log -noname accesscontrol.local1.error "01490000 return } binary scan $tmm_apm_citrix_password c* pass set len [llength $pass] set result {} for { set i 0 } { $i < $len } { incr i } { set hi [lindex $pass $i] set hi [ expr { $hi - 0x41 } ] set hi [ expr { $hi << 4 } ] incr i set lo [lindex $pass $i] set lo [ expr { $lo - 0x41 } ] set char [ binary format c [expr {$hi + $lo}] ] append result $char } binary scan $result H* pass binary scan $result c* pass set len [llength $pass] set result {} set first [lindex $pass 0] set char [ binary format c [expr { $first ^ 0xA5 } ] ] append result $char for { set i 1 } { $i < $len } { incr i } { set prev [ lindex $pass [expr {$i-1}] ] set curr [ lindex $pass $i ] set char [ binary format c [ expr {$curr ^ $prev ^ 0xA5} ] ] append result $char } binary scan $result H* pass set tmm_apm_citrix_password [ regsub -all {\000} $result {} ] HTTP::header replace "username" $tmm_apm_citrix_username HTTP::header replace "password" $tmm_apm_citrix_password HTTP::release } } when HTTP_RESPONSE { if { [HTTP::header Content-Type] contains "application/x-ica" } { set tmm_apm_citrix_ica_patching 1 HTTP::collect [HTTP::header Content-Length] } } when HTTP_RESPONSE_DATA { if { $tmm_apm_citrix_ica_patching == 1 } { log -noname accesscontrol.local1.debug "01490000 set payload [HTTP::payload] set payload [ regsub -all {Proxy[^\n]+\n} $payload {} ] set payload [ regsub {DoNotUseDefaultCSL[^\n]+\n} $payload {} ] if { $tmm_apm_citrix_receiver == 1 } { set payload [ regsub {CGPAddress[^\n]+\n} $payload {} ] } regexp -line {Address=(.+)} $payload dummy CtxAddrPort set CtxAddr [lindex [split $CtxAddrPort ":"] 0] set CtxPort [lindex [split $CtxAddrPort ":"] 1] regexp -line {CGPAddress=(.+)} $payload dummy CGPAddrPort if { [info exists CGPAddrPort] } { set CtxPort [lindex [split $CGPAddrPort ":"] 1] } set payload [ regsub {\[WFClient\]} $payload "&\r\nProxyType=Secure\r\nProxyUseFQDN=On\r\nProxyHost=$tmm_apm_vip\r\nProxyUsername=$tmm_apm_session_id\r\nProxyPassword=$CtxAddr-$CtxPort" ] set payload [ regsub {SSLEnable[^\n]+\n} $payload "SSLEnable=On\r\n" ] set payload [ regsub {Address[^\n]+\n} $payload "Address=$tmm_apm_host\r\nHTTPBrowserAddress=!\r\n" ] HTTP::respond 200 content $payload Content-Type [HTTP::header Content-Type] } } when ACCESS_SESSION_STARTED { if { ($tmm_apm_citrix_receiver == 0) or ![info exists tmm_apm_citrix_password1] } { return } ACCESS::session data set "session.logon.last.password1" [URI::decode $tmm_apm_citrix_password1] } when ACCESS_POLICY_COMPLETED { if { $tmm_apm_citrix_receiver == 0 } { return } set sid [ACCESS::session data get session.keydb] set result [ACCESS::policy result] if { [info exists tmm_apm_citrix_username] } { unset tmm_apm_citrix_username } if { [info exists tmm_apm_citrix_password] } { unset tmm_apm_citrix_password } if { [info exists tmm_apm_citrix_password1] } { unset tmm_apm_citrix_password1 } ACCESS::session data set "session.logon.last.password1" "" if { $result equals "allow" } { set resp "" ACCESS::respond 200 content $resp Set-Cookie "MRHSession=$sid;path=/;secure" Set-Cookie "NSC_AAAC=123;path=/;secure" } }
Published Mar 16, 2015
Version 1.0

Was this article helpful?

No CommentsBe the first to comment