APM Kerberos Auth or fallback to another authentication method
Problem this snippet solves: This iRule can be used when it is required to offer both Kerberos authentication and for example SAML or another authentication method in a mixed environment for devices that are domain joined and devices that are not domain joined. This iRule uses javascript and HTML5 Web Workers to determine if the browser can successfully authenticate by using Kerberos or will need to fallback to another authentication method. I've been testing this iRule with Internet Explorer, Edge, Firefox and Chrome. All these browsers seem to be working fine. Only Chrome seems to do things a bit differently and is showing a login prompt for a split second, but it's working. How to use this snippet: The screenshot below shows an example of an Access Policy that uses either Kerberos or SAML authentication. The first agent in the policy is an 'Empty Agent' which will read the session.custom.domainjoined variable to determine which authentication method to use. The session.custom.domainjoined variable is set by the kerberos_auth_or_fallback_auth iRule. Tested this on version: 13.0 Link to iRule https://github.com/nvansluis/f5.kerberos_auth_or_fallback_auth715Views1like0CommentsTransparent Kerberos Authentication and APM fallback authentication
Problem this snippet solves: This iRule can be used when it is required to offer both Kerberos authentication (transparent, non-APM) and for example SAML or another APM authentication method in a mixed environment for devices that are domain joined and devices that are not domain joined. This iRule uses javascript and HTML5 Web Workers to determine if the browser can successfully authenticate by using Kerberos or will need to fallback to another authentication method. I've been testing this iRule with Internet Explorer, Edge, Firefox and Chrome. All these browsers seem to be working fine. Only Chrome seems to do things a bit differently and is showing a login prompt for a split second, but it's working. How to use this snippet: Create a Virtual Server that delivers a webserver that uses Kerberos Authentication. Create APM Access Policy that will perform the fallback authentication. Add this iRule to the Virtual Server that holds the APM access policy to perform the fallback authentication. Tested this on version: 13.0 Location of iRule https://github.com/nvansluis/f5.transparent_kerberos_auth_or_apm_authentication806Views0likes2CommentsSubsequent Form Based SSO
Problem this snippet solves: After performing a successful APM Form Based SSO it can happen that the backend website will expire the user session while the APM session is still active. When this happens, the user will see the logon page of the backend website and needs to login again. This code snippet will try to detect that the user is being redirected to the backend website login page and will perform a Form Based SSO again by using the credentials from the active APM session. How to use this snippet: When using this code snippet, make sure you set the below shown variables to match your environment. set static::start_uri set static::form_action You should also use the Variable Assign agent in the VPE to set the APM session variable session.custom.form_based.password with the users password. This password will be used to perform the subsequent Form Based SSO. Use the following custom expression: return [mcget -secure {session.logon.last.password}] . Code : when RULE_INIT { set static::start_uri "login.html" set static::form_action "/F5/form_based_login/login.php" set static::form_html { Your browser does not support JavaScript, press the Continue button once to proceed. } set static::form_html [string map "form_action $static::form_action" $static::form_html] } when HTTP_REQUEST { if { [HTTP::cookie exists MRHSession] and [ACCESS::session exists -state_allow -sid [HTTP::cookie MRHSession]] } { set active_session 1 if { [HTTP::method] equals "POST" && [HTTP::uri] equals $static::form_action } { set collect_length 2048 if { [HTTP::header Content-Length] eq "" } { set collect_length $collect_length } elseif { [HTTP::header Content-Length] == 0 } { unset collect_length } elseif { [HTTP::header Content-Length] > $collect_length } { set collect_length $collect_length } else { set collect_length [HTTP::header Content-Length] } if { [info exists collect_length] } { HTTP::collect $collect_length } } } } when HTTP_REQUEST_DATA { # the session.custom.form_based.password variable needs to be set via a variable assign agent in the VPE. set username [ACCESS::session data get session.logon.last.username] set password [ACCESS::session data get session.custom.form_based.password] HTTP::payload replace 0 [HTTP::payload length] "username=$username&password=$password" } when HTTP_RESPONSE { if { [info exists active_session] } { if { [HTTP::header "Location"] equals $static::start_uri } { if { [ACCESS::session data get session.custom.first_redirect] == 1 } { # this is the subsequent redirect which is not covered by APM Form Based SSO HTTP::respond 200 content $static::form_html } else { # this is the initial redirect which is covered by APM Form Based SSO ACCESS::session data set session.custom.first_redirect 1 } } unset active_session } } Tested this on version: 13.0343Views0likes2CommentsForm Based SSO for Dynamically built HTTP forms
Problem this snippet solves: This snippet solves a challenge where Client Initiated Form Based SSO is required but you have no available trigger that you can configure to allow APM to detect the form. This is typically something you can face when you try to configure SSO Forms for some version of the Citrix Storefront Web UI. when digging in the html and javascript, you can see that a single Javascript build the HTML content and thus the forms, so no ways to detect the form when data are in transit. How to use this snippet: You have to install a single irule on the Virtual Server protecting the web application. This irule use ACCESS commands so assuming you have APM and an access profile is attached to the Virtual Server. Code : when HTTP_REQUEST { if { [ACCESS::policy result] eq "allow" } { if { [HTTP::path] ends_with “/Citrix/Company/ExplicitAuth/LoginAttempt" and [HTTP::method] eq "POST" } { HTTP::collect [HTTP::header Content-Length] } if { [HTTP::path] ends_with "/Citrix/Company/" } { set var 1 } } } when HTTP_REQUEST_DATA { set payload [HTTP::payload] set newpayload [string map [list "f5-sso-token" "[ACCESS::session data get -secure session.sso.token.last.password]"] $payload] HTTP::payload replace 0 [string length $payload] $newpayload } when HTTP_RESPONSE { if { [info exists var] and $var } { HTTP::collect [HTTP::header values "Content-Length"] } } when HTTP_RESPONSE_DATA { set payload [HTTP::payload] set username [ACCESS::session data get session.sso.token.last.username] set password "f5-sso-token" set sso " var user = '$username'; var password = '$password'; var t = null; t = setInterval(function() { var \$userField = \$('#username'); var \$passwdField = \$('#password'); var \$submitBtn = \$('#loginBtn'); if (\$userField.length === 0 || \$passwdField.length === 0 || \$submitBtn.length === 0) { return; }; clearInterval(t); \$userField.val(user); \$passwdField.val(password); \$submitBtn.trigger('click');}, 100); " ### This code requires JQuery. Uncomment those lines if you need to load the library # # set jquery " " # set newpayload [string map [list "" $jquery] $payload] # ### END set newpayload [string map [list "" $sso] $payload] HTTP::payload replace 0 [string length $payload] $newpayload } Tested this on version: 11.51KViews0likes4CommentsSupport for POST preservation when APM Multidomain SSO is configured
Problem this snippet solves: F5 doesn't support the preservation of the initial POST request when the Virtual Server has an access profile configured for Multidomain SSO. After authentication, the user is redirected to the initial URL endpoint and issue a GET request instead of a POST request. How to use this snippet: We share a code sample to demonstrate how to support POST preservation in this typical scenario. This irule may need some additional configuration and settings to work properly. As a PoC, we configured two endpoints : sp.expertlab.net and idp.expertlab.net on the same Virtual Server and access profile. The access profile is configured for Multidomain SSO and we prompt the user for a form based authentication. We also added a dummy form prompted to the user after authentication to simplify our testing. Please note that the irule has been successfully tested with Chrome and Firefox. We are still running tests for Internet Explorer and Edge Browsers. Note : APM behave differently between v11, v12 and v13. To make POST preservation work for v11 and v12, you need to add the following variable assign settings before the Allow ending in your access policy : session.server.body = Session Variable session.server.initial_req_body session.policy.result.redirect.url = Session Variable session.server.landinguri_base64 Please note that the order of variable assignment is very important. Moreover, you need to change the name of the request body session variable in the irule too (static::body_var) Flow in v13.x POST https://sp.example.net/post_action.php 307 Temporary Redirect - Location: https://idp.example.net/F5Networks-SSO-Req?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA POST https://idp.example.net/F5Networks-SSO-Req?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA 302 Found - Location: /my.policy GET https://idp.example.net/my.policy 200 OK POST https://idp.example.net/my.policy 302 Found - Location: https://sp.example.net/F5Networks-SSO-Resp?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA&TOKEN=123954 GET https://sp.example.net/F5Networks-SSO-Resp?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA&TOKEN=123954 302 Found - Location: https://sp.example.net/post_action.php?ct=application%2Fx-www-form-urlencoded GET https://sp.example.net/post_action.php?ct=application%2Fx-www-form-urlencoded 200 OK - Body contains JS to force an auto-POST action POST https://sp.example.net/post_action.php ... Flow in v12.x POST https://sp.example.net/post_action.php 307 Temporary Redirect - Location: https://idp.example.net/F5Networks-SSO-Req?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA POST https://idp.example.net/F5Networks-SSO-Req?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA 302 Found - Location: /my.policy GET https://idp.example.net/my.policy 200 OK POST https://idp.example.net/my.policy 302 Found - Location: https://idp.example.net/F5Networks-SSO-Req?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA GET https://idp.example.net/F5Networks-SSO-Req?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA 302 Found - Location: https://sp.example.net/F5Networks-SSO-Resp?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA&TOKEN=123954 GET https://sp.example.net/F5Networks-SSO-Resp?SSO_ORIG_URI=aHR0cHM6Ly9zcC5leGFtcGxlLm5ldC9wb3N0X2FjdGlvbi5waHA&TOKEN=123954 302 Found - Location: https://sp.example.net/post_action.php?ct=application%2Fx-www-form-urlencoded GET https://sp.example.net/post_action.php?ct=application%2Fx-www-form-urlencoded 200 OK - Body contains JS to force an auto-POST action POST https://sp.example.net/post_action.php ... Code : ### # POST preservation feature # for Virtual Server with Multidomain SSO configured # # require : APM ### ### # Special notes # To support POST preservation in v11 and v12, # the administrator needs to configure special session variable assignment before the Allow ending in a Access policy # session.server.body = Session Variable session.server.initial_req_body # session.policy.result.redirect.url = Session Variable session.server.landinguri_base64 ### ### # Release notes # # 2017/11/23 # * Basic support for POST preservation in v13 # * Add support for v11 and v12 environments # # 2017/11/24 # * Replace static::idp_host by [PROFILE::access primary_auth_service] # * Add a static var to enable or disable the dummy form designed for testing purposes # * Avoid POSTing real body multiple times. A dummy var is used to retrieve the original POST content # # 2017/11/25 # * Remove some coding errors # * Refactoring of some parts of the irule ### when RULE_INIT { set static::md_start_uri "/F5Networks-SSO-Req?SSO_ORIG_URI=" # for v11.x and v12.x deployment # set static::body_var "session.server.body" # for v13.x deployment set static::body_var "session.server.initial_req_body" # enable or disable autogenerated testing forms set static::dummy_form 1 } when HTTP_REQUEST { if { ![ACCESS::session exists [HTTP::cookie MRHSession]] and !([HTTP::path] eq "/F5Networks-SSO-Resp") } { if { [HTTP::method] eq "POST" } { # save post data set ct [HTTP::header Content-Type] set uri [HTTP::uri] if { [URI::query $uri] != "" } { set uri $uri&ct=[URI::encode $ct]&f5-mdsso-post=1 } else { set uri $uri?ct=[URI::encode $ct]&f5-mdsso-post=1 } HTTP::respond 307 noserver Location "[PROFILE::access primary_auth_service]$static::md_start_uri[URI::encode [b64encode https://[HTTP::host]$uri]]" Connection Close return } else { HTTP::respond 302 noserver Location "[PROFILE::access primary_auth_service]$static::md_start_uri[URI::encode [b64encode https://[HTTP::host][HTTP::uri]]]" Connection Close return } } if { [ACCESS::session exists [HTTP::cookie MRHSession]] and [HTTP::query] contains "f5-mdsso-post=1" and [ACCESS::session data get $static::body_var] != "" } { set ct [URI::decode [URI::query [HTTP::uri] ct]] set dummy [getfield [expr {rand()}] "." 2] ACCESS::session data set session.server.dummy $dummy ACCESS::session data set session.server.ct $ct HTTP::respond 200 content " this page is used to hold your data while you are being authorized for your request. you will be forwarded to continue the authorization process. if this does not happen automatically, please click the continue button below. " noserver Content-Type "text/html" return } if { [ACCESS::session exists [HTTP::cookie MRHSession]] and [HTTP::method] eq "POST" and [HTTP::payload] contains "dummy" and [ACCESS::session data get session.server.dummy] eq [URI::query "/?[HTTP::payload]" dummy] } { HTTP::header replace Content-Type [ACCESS::session data get session.server.ct] HTTP::payload replace 0 [HTTP::header Content-Length] [ACCESS::session data get $static::body_var] } }1.5KViews0likes8CommentsWebtop Return Without Reauthentication
Problem this snippet solves: By default if you hit "/" on a VS with a webtop assigned it will terminate the session and require reauthentication. This iRule will cause the user hitting "/" to be redirected to the previously assigned webtop without needing to reauthenticate if their session is still valid. Here are a few example scenarios this iRule helps with: 1. User goes to a webtop, leaves, and later tries to return 2. User performs SP initiated SAML auth, authenticates to the webtop VS but never sees the webtop, and later tries to go to the webtop directly 3. User leverages SAML autolaunch iRule for IdP initiated SAML, then later tries to return and get the webtop How to use this snippet: Apply to the virtual server hosting the webtop. Code : when HTTP_REQUEST { if { ( [HTTP::cookie exists MRHSession] ) && ( [HTTP::uri] equals "/" ) && ( [ACCESS::session exists -state_allow [HTTP::cookie value MRHSession]] ) } then { HTTP::redirect "/vdesk/webtop.eui?webtop=[ACCESS::session data get "session.assigned.webtop"]&webtop_type=webtop_full" } }307Views0likes2CommentsApache mod_auth_tkt Single Sign On
Problem this snippet solves: This iRule is designed to parse and verify the digest from a auth_tkt cookie. This is a proof-of-concept that can be leveraged to offload authentication and/or verification from the apache servers when used in conjunction with the LTM authentication module. Using "AUTH::response_data", you can include additional tokens from the authentication server in the cookie that can help LTM to make more intelligent load-balancing decisions based on the users. As these cookies are unique per user, you can use them as a source of persistence information as well. If performance is a must, you can use the session table to cache verified cookies and store necessary information about the authenticated user and look them up by hash. This session entry could be used to maintain a precision based inactivity timeout as well. Code : rule mod_auth_tkt { when RULE_INIT { set cookie_name "auth_tkt_sso" set secret "auth_tkt_shared_secret" set tokens "AUTH_TKT_TOKEN1,AUTH_TKT_TOKEN2" set data "" } when HTTP_REQUEST { if { ! [HTTP::cookie exists $::cookie_name] } { return } set cookie [HTTP::cookie $::cookie_name] set ticket [b64decode $cookie] scan $ticket {%32s%8s%[^!]!} master_digest time_stamp user_id set rawip "\000\000\000\000" set rawts [binary format H* $time_stamp] binary scan $rawts H* rets set rawstring $rawip$rawts$::secret$user_id\000$::tokens\000$::data binary scan [md5 $rawstring] H* digest0 binary scan [md5 $digest0$::secret] H* digest if { $digest ne $master_digest } { reject } } }533Views0likes1Comment