xenapp
2 TopicsCitrix VDI iApp template
Problem this snippet solves: You can use this F5 supported iApp template to configure availability and Secure ICA proxy remote access for Citrix XenApp or XenDesktop environments. This iApp template configures BIG-IP LTM, APM, and AFM for XenApp or XenDesktop services. When used with BIG-IP APM, this iApp template supports proxy authentication and secure remote access for all XenApp and XenDesktop HTTP-based protocols without requiring a VPN client. The iApp template includes the ability to configure BIG-IP APM for two factor authentication with RSA SecurID, and supports smart card authentication. The link below takes you to the official AskF5 SOL for Citrix VDI with instructions on downloading and using the iApp template. For the Deployment Guide, see http://www.f5.com/pdf/deployment-guides/citrix-vdi-iapp-dg.pdf Code : https://support.f5.com/kb/en-us/solutions/public/13000/700/sol13738.html641Views0likes0CommentsCitrix XenApp Secure Access Deployment
Problem this snippet solves: 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. The following iRule provides the functionality for a secure proxy connection from various Citrix clients (PN Agent, Dazzle, Receiver and Web Browser) without the need for additional clients installed on the devices. How to use this snippet: Deployment Guide: https://f5.com/solutions/deployment-guides/citrix-xenapp-or-xendesktop-release-candidate-big Code : rule APM_Citrix { 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_ica_patching 0 set tmm_apm_vip "$tmm_apm_host:[TCP::local_port clientside]" log -noname accesscontrol.local1.debug "01490000:3: Request [HTTP::request]" 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 "Dazzle" } { set tmm_apm_citrix_pnagent 1 } if { $tmm_apm_http_method equals "CONNECT" } { # Handle the secure proxy connect requests. Return a Proxy-Authenticate header # field with a challenge if the user is not authenticated. if { ![HTTP::header exists "Proxy-Authorization"] } { HTTP::respond 407 Proxy-Authenticate "Basic realm=\"123\"" return } set authstr [lindex [ split [HTTP::header "Proxy-Authorization"] " " ] 1 ] # Seems like the Citrix base64 encoding logic has a bug that terminates # the input string with a null byte when the extra padding characters are # added. We remove the extra null character before we decode it. set remainder [lindex [split [expr [string length $authstr] / 4.0 ] "." ] 1] if { $remainder != "0" } { if { [regsub -all {(A=)} $authstr = newstring] > 0 } { set authstr $newstring } } #Decoded string format: 52553eb5b18572cdbe7dda4a8220bf35:172.30.6.197-1494 set apm_session [ lindex [ split [b64decode $authstr] ":" ] 0 ] if { ![ACCESS::session exists $apm_session] } { HTTP::respond 407 Proxy-Authenticate "Basic realm=\"123\"" return } # User is authenticated, send the traffic to the connect proxy virtual. log -noname accesscontrol.local1.notice "01490000:3: Request for citrix resource received from session: $apm_session" ACCESS::disable use virtual citrix_connect_proxy } if { ($tmm_apm_session_id == "") && ($tmm_apm_citrix_pnagent == 1) } { if { $tmm_apm_uri_path equals $::tmm_apm_pnagent_url } { ACCESS::disable return } # If the client is PNAgent or Dazzle, extract the credentials from the # payload and insert them in HTTP headers. HTTP::header insert "clientless-mode" 1 HTTP::header insert "username" "" HTTP::header insert "password" "" if { ![info exists tmm_apm_citrix_username] && [HTTP::header exists Content-Length] } { HTTP::collect [HTTP::header Content-Length] } } if { $tmm_apm_citrix_receiver == 1 } { # Collect the user credentials and set ready for access policy validation if { $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 "<html><h2><a href=\"$AD_only\">Click here for domain only auth</a><a href=\"$RSA_only\">Click here for RSA only</a><a href=\"$AD_RSA\">Click here for Two-factor auth</a></h2></html>" } } } when HTTP_REQUEST_DATA { if { ($tmm_apm_citrix_pnagent != 1) && ($tmm_apm_citrix_receiver != 1) } { return } set payload [HTTP::payload] if { $tmm_apm_citrix_receiver == 1 } { # Parse the user credentials from the payload log -noname accesscontrol.local1.debug "01490000:3: Parsing credentials for Citrix receiver" 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 } } # Insert the parsed credentials into the HTTP request as headers HTTP::header replace "username" $tmm_apm_citrix_username HTTP::header replace "password" $tmm_apm_citrix_password HTTP::release } elseif { $tmm_apm_citrix_pnagent == 1 } { # Parse the user credentials from the payload log -noname accesscontrol.local1.debug "01490000:3: Parsing credentials for Citrix PNAgent" set tmm_apm_citrix_username "" set tmm_apm_citrix_password "" if { [regexp -nocase {<username>([^<]+)</username>} $payload dummy tmm_apm_citrix_username] == 0 } { log -noname accesscontrol.local1.error "01490000:3: $tmm_apm_session_id: Username not found in the PNAgent POST body" return } if { [regexp -nocase {<password[^>]+>([^<]+)</password>} $payload dummy tmm_apm_citrix_password] == 0 } { log -noname accesscontrol.local1.error "01490000:3: $tmm_apm_session_id: Password not found in the PNAgent POST body" return } # Decode the password 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 {} ] # Insert the parsed credentials into the HTTP request as headers 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 { # ICA patching: if { $tmm_apm_citrix_ica_patching == 1 } { # ICA file patching: Add entries to point citrix clients to the # Citrix ICA patching virtual as their HTTP proxy. It also sets # the ProxyUsername to the APM session id to let the Citrix clients # to connect to the proxy without requesting the user to authenticate # again. log -noname accesscontrol.local1.debug "01490000:3: ICA file patching" 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\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\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 } # Pass the domain password as a session variable. Logon page agent doesn't # take it from HTTP headers in clientless mode. 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] # Remove the user credential variables 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 } # Clear the domain password session variable created at the session validation start. ACCESS::session data set "session.logon.last.password1" "" if { $result equals "allow" } { set resp "<html><head><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"0; URL=$::tmm_apm_pnagent_url\"></head><body></body></html>" ACCESS::respond 200 content $resp Set-Cookie "MRHSession=$sid;path=/;secure" Set-Cookie "NSC_AAAC=123;path=/;secure" } } }405Views0likes0Comments