PARTITION: Common

ltm rule _sys_APM_ExchangeSupport_OA_BasicAuth {
    nodelete nowrite 
    # Global variables
    # static::POLICY_RESULT_CACHE_AUTHFAILED
    #     Administrator can set this into 1, when there is a necessity to cache failed policy result.
    #     This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.
    #     One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.
    # Responses
    # On denied result
    #     Administrator can customize the responses to the device depends on more complex conditions when necessary.
    #     In those cases, please use ACCESS::respond command.
    #     The following is the syntax of ACCESS::respond
    #     ACCESS::respond <status code> [ content <body> ] [ <Additional Header> <Additional Header value>* ]
    #     e.g. ACCESS::respond 401 content "Error: Denied" WWW-Authenticate "basic realm=\"f5.com\"" Connection close
    when RULE_INIT {
        # Please set the following global variables for customized responses.
        set static::actsync_401_http_body "<html><title>Authentication Failured</title><body>Error: Authentication Failure</body></html>"
        set static::actsync_503_http_body "<html><title>Service is not available</title><body>Error: Service is not available</body></html>"
        set static::ACCESS_LOG_PREFIX                 "01490000:7:"
        # Second Virtual Server name for 401 NTLM responder
        set static::ACCESS_SECOND_VIRTUAL_NAME        "_ACCESS_401_NTLM_responder_HTTPS"
        set static::POLICY_INPROGRESS                 "policy_inprogress"
        set static::POLICY_AUTHFAILED                 "policy_authfailed"
        # The request with huge content length can not be used for starting ACCESS session.
        # This kind of request will be put on hold, and this iRule will try to use another
        # request to start the session. The following value is used for Outlook Anywhere.
        set static::OA_MAGIC_CONTENT_LEN              1073741824
        # Similar with OutlookAnywhere case, ACCESS can not use the request which is
        # larger then following size. This becomes an issue with application that using
        # Exchange Web Service as its main protocol such as Mac OS X applications
        # (e.g. Mail app, Microsoft Entourage, etc)
        # This kind of request will be put on hold, and this iRule will try to use another
        # request to start the session.
        set static::FIRST_BIG_POST_CONTENT_LEN        640000
        # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.
        set static::EWS_BKEND_BASIC_AUTH              0
        # The following variable controls the polling mechanism.
        set static::POLICY_RESULT_POLL_INTERVAL       250
        set static::POLICY_RESULT_POLL_MAXRETRYCYCLE  600
        # Set this global variable to 1 for caching authentication failure
        # Useful for avoiding account locked out.
        set static::POLICY_RESULT_CACHE_AUTHFAILED    0
        # set this global variable to set alternative timeout for particular session
        set static::POLICY_ALT_INACTIVITY_TIMEOUT     120
        set static::ACCESS_USERKEY_TBLNAME            "_access_userkey"
        set static::ACCESS_DEL_COOKIE_HDR_VAL         "MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"
        log -noname accesscontrol.local1.debug "01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH"
    }
    when ACCESS_ACL_ALLOWED {
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]"
        # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been
        # already authenticated if there is a HTTP Basic Auth in the request.
        if { [ info exists f_exchange_web_service ] && $f_exchange_web_service  == 1 }  {
            if { $static::EWS_BKEND_BASIC_AUTH == 0 } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header"
                HTTP::header remove Authorization
            }
        }
    }
    when HTTP_REQUEST {
        set http_path                       [ string tolower [HTTP::path] ]
        set f_clientless_mode               0
        set f_alt_inactivity_timeout        0
        set f_rpc_over_http                 0
        set f_exchange_web_service          0
        set f_auto_discover                 0
        set f_activesync                    0
        set f_offline_address_book          0
        set f_availability_service          0
        #  Here put appropriate pool when necessary.
        switch -glob $http_path {
        "/rpc/rpcproxy.dll" {
            # Supports for RPC over HTTP. (Outlook Anywhere)
            set f_rpc_over_http 1
        }
        "/autodiscover/autodiscover.xml" {
            # Supports for Auto Discover protocol.
            set f_auto_discover 1
            # This request does not require long inactivity timeout.
            # Don't use this for now
            set f_alt_inactivity_timeout 0
        }
        "/microsoft-server-activesync" {
            # Supports for ActiveSync
            set f_activesync 1
        }
        "/oab/*" {
            # Supports for Offline Address Book
            set f_offline_address_book 1
            # Don't use this for now
            set f_alt_inactivity_timeout 0
        }
        "/ews/*" {
            # Support for Exchange Web Service
            # Outlook's Availability Service borrows this protocol.
            set f_exchange_web_service 1
        }
        "/as/*" {
            # Support for Availability Service.
            # do nothing for now. (Untested)
            set f_availability_service 1
        }
        default {
            return
        }
        }
        set f_reqside_set_sess_id           0
        set http_method                     [HTTP::method]
        set http_hdr_host                   [HTTP::host]
        set http_hdr_uagent                 [HTTP::header User-Agent]
        set http_uri                        [HTTP::uri]
        set http_content_len                [HTTP::header Content-Length]
        set MRHSession_cookie               [HTTP::cookie value MRHSession]
        set auth_info_b64enc                ""
        if { ! [ info exists src_ip ] } {
            set src_ip                            [IP::remote_addr]
        }
        if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {
            set PROFILE_POLICY_TIMEOUT            [PROFILE::access access_policy_timeout]
        }
        if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {
            set PROFILE_MAX_SESS_TIMEOUT          [PROFILE::access max_session_timeout]
        }
        if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {
            set PROFILE_RESTRICT_SINGLE_IP        1
        }
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX method: $http_method"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Src IP: $src_ip"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP"
        # First, do we have valid MRHSession cookie.
        if { $MRHSession_cookie != "" } {
            if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie"
            } else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie"
                set MRHSession_cookie ""
                HTTP::cookie remove MRHSession
            }
        }
        set http_hdr_auth [HTTP::header Authorization]
        if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header"
            set http_hdr_auth ""
        }
        if { $http_hdr_auth == "" } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX No/Empty Auth header"
            # clean up the cookie
            if { $MRHSession_cookie == "" } {
                HTTP::respond 401 content  $static::actsync_401_http_body WWW-Authenticate "Basic realm=\"[HTTP::header Host]\"" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close
                return
            }
            # Do nothing if we have a valid MRHSession cookie.
        }
        set f_release_request           0
        # Optimization for clients which support cookie
        if { $MRHSession_cookie != "" } {
            # Default profile access setting is false
            if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                set f_release_request 1
            }
            elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie "session.user.clientip" ] ] } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP matched"
                set f_release_request 1
            }
            else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP does not matched"
                set MRHSession_cookie ""
                HTTP::cookie remove MRHSession
            }
        }
        if { $f_release_request == 0 } {
            set apm_username [string tolower [HTTP::username]]
            set apm_password [HTTP::password]
            if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                binary scan [md5 "$apm_password"] H* user_hash
            }
            else {
                binary scan [md5 "$apm_password$src_ip"] H* user_hash
            }
            set user_key    "$apm_username.$user_hash"
            unset user_hash
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX apm_username: $apm_username"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX user_key = $user_key"
            set apm_cookie_list             [ ACCESS::user getsid $user_key ]
            if { [ llength $apm_cookie_list ] != 0 } {
                set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]
                if { $apm_cookie != "" } {
                    HTTP::cookie insert name MRHSession value $apm_cookie
                    set f_release_request 1
                }
            }
        }
        if { $http_content_len ==  $static::OA_MAGIC_CONTENT_LEN } {
            set f_oa_magic_content_len 1
        }
        set f_sleep_here 0
        set retry 1
        while { $f_release_request == 0 && $retry <=  $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME"
            set apm_cookie [table lookup -subtable  $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]
            if { $apm_cookie != "" } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie"
                # Accessing SessionDB is not that cheap. Here we are trying to check known value.
                if { $apm_cookie == "policy_authfailed" || $apm_cookie == "policy_inprogress"} {
                    # Do nothing
                } elseif  { ! [ ACCESS::session exists $apm_cookie ] } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync"
                    # Table value is out of sync. Ignores it.
                    set apm_cookie ""
                }
            }
            switch $apm_cookie {
            "" {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX NO APM Cookie found"
                if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {
                    # Outlook Anywhere request comes in pair. The one with 1G payload is not usable
                    # for creating new session since 1G content-length is intended for client to upload
                    # the data when needed.
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len"
                    set f_sleep_here 1
                } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {
                    # Here we are getting large EWS request, which can't be used for starting new session
                    # in clientless-mode. Have it here waiting for next smaller one.
                    # We are holding the request here in HTTP filter, and HTTP filter automatically
                    # clamping down the TCP window when necessary.
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request"
                    set f_sleep_here 1
                } else {
                   set apm_cookie               "policy_inprogress"
                   set f_reqside_set_sess_id    1
                   set f_release_request        1
                }
            }
            "policy_authfailed" {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED"
                HTTP::respond 401 content  $static::actsync_401_http_body
                set f_release_request 1
            }
            "policy_inprogress" {
                if { [ info exists f_activesync ] && ($f_activesync == 1) } {
                    # For ActiveSync requests, aggressively starts new session.
                    set f_reqside_set_sess_id    1
                    set f_release_request        1
                } else {
                    set f_sleep_here 1
                }
            }
            default {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie"
                HTTP::header insert Cookie "MRHSession=$apm_cookie"
                set f_release_request 1
            }
            }
            if { $f_reqside_set_sess_id == 1 } {
                set f_reqside_set_sess_id 0
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT"
                set f_clientless_mode 1
                HTTP::cookie remove MRHSession
                HTTP::header insert "clientless-mode" 1
                HTTP::header insert "username" $apm_username
                HTTP::header insert "password" $apm_password
                table set -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT
            }
            if { $f_sleep_here == 1 } {
                set f_sleep_here 0
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Waiting  $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri"
                after  $static::POLICY_RESULT_POLL_INTERVAL
            }
            incr retry
        }
        if { ($f_release_request == 0) && ($retry >=  $static::POLICY_RESULT_POLL_MAXRETRYCYCLE) } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri"
            table delete -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
            ACCESS::disable
            TCP::close
            return
        }
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri"
    }
    when ACCESS_SESSION_STARTED {
        if { [ info exists user_key ] } {
            ACCESS::session data set "session.user.uuid" $user_key
            ACCESS::session data set "session.user.microsoft-exchange-client" 1
            if { [ info exists f_activesync ] && $f_activesync == 1 } {
                ACCESS::session data set "session.user.microsoft-activesync" 1
            }
            elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {
                ACCESS::session data set "session.user.microsoft-autodiscover" 1
            }
            elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {
                ACCESS::session data set "session.user.microsoft-availabilityservice" 1
            }
            elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {
                ACCESS::session data set "session.user.microsoft-rpcoverhttp" 1
            }
            elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {
                ACCESS::session data set "session.user.microsoft-offlineaddressbook" 1
            }
            elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {
                ACCESS::session data set "session.user.microsoft-exchangewebservice" 1
            }
        }
        if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {
            ACCESS::session data set "session.inactivity_timeout"  $static::POLICY_ALT_INACTIVITY_TIMEOUT
        }
    }
    when ACCESS_POLICY_COMPLETED {
        if { ! [ info exists user_key ] } {
            return
        }
        set user_key_value ""
        set f_delete_session 0
        set policy_result [ACCESS::policy result]
        set sid [ ACCESS::session sid ]
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \"$policy_result\" user_key = \"$user_key\" sid = \"$sid\""
        set inactivity_timeout [ACCESS::session data get "session.inactivity_timeout"]
        set max_sess_timeout [ACCESS::session data get "session.max_session_timeout"]
        if { $max_sess_timeout == "" } {
             set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT
        }
        switch $policy_result {
        "allow" {
            # We depends on this table record self-cleanup capability in order to
            # indirectly sync with session DB.
            set user_key_value $sid
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX sid = $sid"
        }
        "deny" {
            # When necessary the admin here can check appropriate session variable
            # and decide what response more appropriate then this default response.
            ACCESS::respond 401 content  $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close
            if {  $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {
                set user_key_value  $static::POLICY_AUTHFAILED
            } else {
                set f_delete_session  1
            }
        }
        default {
            ACCESS::respond 503 content  $static::actsync_503_http_body Connection Close
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)"
            set f_delete_session  1
        }
        }
        if { $user_key_value != "" } {
           log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME"
           table set -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout
        } else {
           log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME"
           table delete -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
        }
        if { $f_delete_session == 1 } {
           ACCESS::session remove
           set f_delete_session 0
           log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Removing the session for $user_key."
        }
    }
definition-signature CZnUb3niz9wZPWvOmjDB0Dy4ixqjBEhIZrAVGt8VYe7+wZkhcBUFTADz3S1y5uomVwhRkGL20PLH7tfanDlpr3+IppgAGQlp98sPUl5ndEoWA4Rr90QiRGNRl/V7jWK58SOdJCQOirnutVMoeYjBWLwuprXGts08PO0WML5s0xJNOY7WPuGNeG+7Ht2pIB0vu80CgnCNGZJGZH0QR3kMVOx3yUN0ro5bAOmQ/XWel4qkj0F5DN9ufvsmKtTvb+Lc3y+5PHGbbFAQIrZ7lntZUJl/F8e/d26HE3spmZzQpPzi16qYWaMOxbvT6oedxpyhwbmJLiRNGyZmnT6kHj93FA==
    verification-status signature-verified
}
ltm rule _sys_APM_ExchangeSupport_OA_NtlmAuth {
    nodelete nowrite 
when RULE_INIT {
        set static::POLICY_INPROGRESS                 "policy_inprogress"
        set static::POLICY_FAILED                     "policy_failed"
        set static::POLICY_SUCCEED                    "policy_succeed"
        set static::POLICY_DONE_WAIT_SEC              5
        set static::FIRST_BIG_POST_CONTENT_LEN        640000
        set static::POLICY_RESULT_POLL_INTERVAL       100
        set static::POLICY_RESULT_POLL_MAXRETRYCYCLE  100
        set static::ACCESS_USERKEY_TBLNAME            "_access_userkey"
        set static::ACCESS_LOG_PREFIX                 "01490000:7:"
        set static::USE_NTLM_AUTH                     0
        set static::USE_BASIC_AUTH                    1
        set static::USE_NTLM_BASIC_AUTH               2
        set static::URL_DEFAULT                       0
        set static::URL_RPC_OVER_HTTP                 1
        set static::URL_AUTODISCOVER                  2
        set static::URL_ACTIVE_SYNC                   3
        set static::URL_OFFLINEADDRESSBOOK            4
        set static::URL_EXCHANGEWEBSERVICE            5
        set static::RECVD_AUTH_NONE                   0
        set static::RECVD_AUTH_NTLM                   1
        set static::RECVD_AUTH_BASIC                  2
        set static::ACCESS_DEL_COOKIE_HDR_VAL         "MRHSession=deleted;                                                        expires=Thu, 01-Jan-1970 00:00:01 GMT;                                                       path=/"
    }
    when HTTP_REQUEST {
        set http_path                       [string tolower [HTTP::path]]
        set url_path                        $static::URL_DEFAULT
        set use_auth                        $static::USE_NTLM_AUTH
        set f_disable_sso                   0
        switch -glob $http_path {
        "/rpc/rpcproxy.dll" {
            set url_path                    $static::URL_RPC_OVER_HTTP
        }
        "/autodiscover/autodiscover.xml" {
            set url_path                    $static::URL_ACTIVE_SYNC
            # Need to support both NTLM and Basic authentication for this URL
            set use_auth                    $static::USE_NTLM_BASIC_AUTH
        }
        "/microsoft-server-activesync*" {
            set url_path                    $static::URL_ACTIVE_SYNC
            # Use only Basic authentication for this URL
            set use_auth                    $static::USE_BASIC_AUTH
            set f_disable_sso               1
        }
        "/oab*" {
            set url_path                    $static::URL_OFFLINEADDRESSBOOK
        }
        "/ews*" {
            set url_path                    $static::URL_EXCHANGEWEBSERVICE
        }
        default {
            ECA::disable
            return
        }
        }
        if { ! [ info exists f_ntlm_auth_succeed ] } {
            set f_ntlm_auth_succeed         0
        }
        if { ! [ info exists sid_cache ] } {
            set sid_cache                         ""
        }
        if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } { 
            set PROFILE_POLICY_TIMEOUT            [PROFILE::access access_policy_timeout]
        }
        if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {
            set PROFILE_MAX_SESS_TIMEOUT          [PROFILE::access max_session_timeout]
        }
        if { ! [ info exists src_ip ] } {
            set src_ip                            [IP::remote_addr]
        }
        if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {
            set PROFILE_RESTRICT_SINGLE_IP        1
        }
        set http_method                     [HTTP::method]
        set http_hdr_host                   [HTTP::host]
        set http_hdr_uagent                 [HTTP::header User-Agent]
        set http_uri                        [HTTP::uri]
        set http_content_len                [HTTP::header Content-Length]
        set MRHSession_cookie               [HTTP::cookie value MRHSession]
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX method:      $http_method"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Src IP:      $src_ip"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX User-Agent:  $http_hdr_uagent"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP uri:    $http_uri"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP len:    $http_content_len"
        if { ! [ info exists ECA_METADATA_ARG ] } {
            # Generating argument for ECA::metadata
            # The NTLM configuration name is derived from assigned virtual name with the algorithm as follows:
            # <virtual-fullpath> ::= <folder-path>"/"<virtual-basename> as "/" is the last "/" char.
            # <config-fullpath>  ::= <folder-path>"/" "exch_ntlm" "_" <virtual-basename>
            # e.g.  Let us say the virtual name is "/prod/exch/vs1", The folder path is "/prod/exch/",
            #       then object name will be "/prod/exch/exch_ntlm_vs1".
            set vs_name [virtual name]
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX virtual:     $vs_name"
            set slash_index [ string last / $vs_name ]
            if { $slash_index == -1 } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Error: the virtual name does not contain folder information"
                ACCESS::disable
                TCP::close
                return
            }
            set ECA_METADATA_ARG    "select_ntlm:"
            append ECA_METADATA_ARG [ string range $vs_name 0 $slash_index ]
            append ECA_METADATA_ARG "exch_ntlm_"
            append ECA_METADATA_ARG [ string range $vs_name [ expr { $slash_index + 1 } ] end ]
            unset slash_index
            unset vs_name
        }
        if { $use_auth == $static::USE_NTLM_AUTH } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Enable ECA: $ECA_METADATA_ARG"
            ECA::enable
            ECA::select $ECA_METADATA_ARG
            return
        } else {
            set recvd_auth                      $static::RECVD_AUTH_NONE
            set http_hdr_auth                   [HTTP::header Authorization]
            set auth_data                       [split $http_hdr_auth " "]
            if { $http_hdr_auth != "" } {
                if { [ llength $auth_data ] == 2 } {
                    set auth_scheme [ lindex $auth_data 0]
                    if { [string equal -nocase $auth_scheme "ntlm" ] == 1 } {
                        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Recv'd HTTP NTLM Authentication"
                        set recvd_auth          $static::RECVD_AUTH_NTLM
                    } elseif { [ string equal -nocase [ lindex $auth_data 0] "basic" ] == 1 } {
                        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Recv'd HTTP Basic Authentication"
                        set recvd_auth          $static::RECVD_AUTH_BASIC
                        set user                [string tolower [HTTP::username]]
                        set password            [HTTP::password]
                    }
                }
            }
            if { $use_auth == $static::USE_BASIC_AUTH } {
                if { $recvd_auth == $static::RECVD_AUTH_BASIC } {
                    # Defer the process until later
                } else {
                    HTTP::respond 401 -version 1.1 noserver WWW-Authenticate "Basic realm=\"$http_hdr_host\""                                 Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close
                    return
                }
            } elseif { $use_auth == $static::USE_NTLM_BASIC_AUTH } {
                if { ($recvd_auth == $static::RECVD_AUTH_NTLM) || ($f_ntlm_auth_succeed == 1) } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Enable ECA: $ECA_METADATA_ARG"
                    ECA::enable
                    ECA::select $ECA_METADATA_ARG
                    return
                } elseif { $recvd_auth == $static::RECVD_AUTH_BASIC } {
                    # Defer the process until later
                } else {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Request Authorization: NTLM + Basic"
                    HTTP::respond 401 -version 1.1 noserver WWW-Authenticate "Basic realm=\"$http_hdr_host\""                                 WWW-Authenticate "NTLM" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close
                    return
                }
            }
            # Disable NTLM auth
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Disable ECA"
            ECA::disable
            # Disable KCD sso
            set f_disable_sso               1
            if { $MRHSession_cookie != "" } {
                if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie"
                    # Default profile access setting is false
                    if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Release the request"
                        return
                    }
                    elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie "session.user.clientip" ] ] } {
                        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP matched. Release the request"
                        return
                    }
                    else {
                        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP does not matched"
                    }
                }
                else {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie"
                }
                set MRHSession_cookie ""
                HTTP::cookie remove MRHSession
            }
            set user_key                {}
            if { $PROFILE_RESTRICT_SINGLE_IP == 1 } {
                append user_key                    $src_ip
            }
            append user_key                 $password
            binary scan [md5 $user_key ] H* user_key
            set user_key                    "$user.$user_key"
            set apm_cookie_list             [ ACCESS::user getsid $user_key ]
            if { [ llength $apm_cookie_list ] != 0 } {
                set MRHSession_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]
                if { $MRHSession_cookie != "" } {
                    HTTP::cookie remove MRHSession 
                    HTTP::cookie insert name MRHSession value $MRHSession_cookie
                    return
                }
            }
            HTTP::cookie remove MRHSession
            HTTP::header insert "clientless-mode"       1
            HTTP::header insert "username"              $user
            HTTP::header insert "password"              $password
            return
        }
    }
    when ECA_REQUEST_ALLOWED {
        set f_ntlm_auth_succeed                 1
        if { $MRHSession_cookie == "" } {
            # Retrieve from SID cache
            set MRHSession_cookie   $sid_cache
            HTTP::cookie insert name MRHSession value $sid_cache
        }
        if { $MRHSession_cookie != "" } {
            # Destroy session ID cache. This client should not need session ID cache 
            if { ($sid_cache != "") && ($sid_cache != $MRHSession_cookie) } {
                set sid_cache   ""
            }
            if { [ ACCESS::session exists -state_allow $MRHSession_cookie ] } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie"
                # Default profile access setting is false
                if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Release the request"
                    return
                }
                elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie "session.user.clientip" ] ] } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP matched. Release the request"
                    return
                }
                else {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP does not matched"
                }
            } else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie"
            }
        }
        set MRHSession  ""
        set sid_cache   ""
        HTTP::cookie remove MRHSession
        # Build user_key
        set    user_key                 {}
        append user_key                 [string tolower [ECA::username]] "@" [ string tolower [ECA::domainname] ]
        if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
            append user_key             ":" $src_ip
        }
        append user_key                 ":" [ECA::client_machine_name]
        set apm_cookie_list             [ ACCESS::user getsid $user_key ]
        if { [ llength $apm_cookie_list ] != 0 } {
            set MRHSession_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]
            if { $MRHSession_cookie != "" } {
                set sid_cache           $MRHSession_cookie
                HTTP::cookie insert name MRHSession value $MRHSession_cookie
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX APM Cookie found: $sid_cache"
                return
            }
        }
        unset apm_cookie_list
        set try                         1
        set start_policy_str            $src_ip
        append start_policy_str         [TCP::client_port]
        while { $try <=  $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX NO APM Cookie found"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Trying #$try for $http_method $http_uri $http_content_len"
            if { $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {
                # Wait at below
            } else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX EXEC: table set -notouch -subtable  $static::ACCESS_USERKEY_TBLNAME -excl $user_key $start_policy_str $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT"
                set policy_status [table set -notouch -subtable  $static::ACCESS_USERKEY_TBLNAME -excl $user_key $start_policy_str $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT]
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX DONE: table set -notouch -subtable  $static::ACCESS_USERKEY_TBLNAME -excl $user_key $start_policy_str $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT"
                if { $policy_status == $start_policy_str } {
                    # ACCESS Policy has not started. Start one
                    HTTP::header insert "clientless-mode"    1
                    break
                } elseif { $policy_status == $static::POLICY_SUCCEED } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX table is out-of-sync retry"
                    table delete -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
                    continue
                } elseif { $policy_status == $static::POLICY_FAILED } {
                    ACCESS::disable
                    TCP::close
                    return
                }
                # Wait at below
            }
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Waiting  $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri"
            # Touch the entry table
            table lookup -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
            after  $static::POLICY_RESULT_POLL_INTERVAL
            set apm_cookie_list             [ ACCESS::user getsid $user_key ]
            if { [ llength $apm_cookie_list ] != 0 } {
                set MRHSession_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]
                if { $MRHSession_cookie != "" } {
                    set sid_cache           $MRHSession_cookie
                    HTTP::cookie insert name MRHSession value $MRHSession_cookie
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX APM Cookie found: $sid_cache"
                    return
                }
            }
            incr try
        }
        if { $try >  $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Policy did not finish in [ expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri"
            table delete -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
            ACCESS::disable
            TCP::close
            return
        }
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri"
        unset try
        unset start_policy_str
    }
    when ECA_REQUEST_DENIED {
        set f_ntlm_auth_succeed                 0
    }
    when HTTP_RESPONSE_RELEASE {
        if { ! [info exists user_key] } {
            return
        }
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP response: status:           [HTTP::status]"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP response: Server:           [HTTP::header Server]"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP response: Content-Length:   [HTTP::header Content-Length]"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP response: WWW-Authenticate: [HTTP::header WWW-Authenticate]"
    }
    when ACCESS_SESSION_STARTED {
        if { [ info exists user_key ] } {
            ACCESS::session data set "session.user.uuid" $user_key
            ACCESS::session data set "session.user.microsoft-exchange-client" 1
        }
    }
    when ACCESS_ACL_ALLOWED {
        if { [ info exists f_disable_sso ] && $f_disable_sso == 1 } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Disable WEBSSO"
            WEBSSO::disable
        }
    }
    when ACCESS_POLICY_COMPLETED {
        if { ! [ info exists user_key ] } {
            return
        }
        set user_key_value ""
        set f_delete_session 0
        set policy_result [ACCESS::policy result]
        set sid [ ACCESS::session sid ]
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \"$policy_result\" user_key = \"$user_key\" sid = \"$sid\""
        switch $policy_result {
        "allow" {
            set user_key_value          $sid
            set sid_cache               $user_key_value
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Result: Allow: $user_key"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX sid = $sid"
        }
        "deny" {
            ACCESS::respond 401 content  $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close
            set f_delete_session  1
        }
        default {
            ACCESS::respond 503 content  $static::actsync_503_http_body Connection Close
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)"
            set f_delete_session  1
        }
        }
        if { $f_ntlm_auth_succeed == 1 } {
            if { $user_key_value != "" } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Setting $user_key => $static::POLICY_SUCCEED"
                table set -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key $static::POLICY_SUCCEED
            } else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Setting $user_key => $static::POLICY_FAILED  $static::POLICY_DONE_WAIT_SEC $static::POLICY_DONE_WAIT_SEC_in table $static::ACCESS_USERKEY_TBLNAME"
                table set -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key $static::POLICY_FAILED  $static::POLICY_DONE_WAIT_SEC $static::POLICY_DONE_WAIT_SEC
            }
        }
        if { $f_delete_session == 1 } {
            ACCESS::session remove
            set f_delete_session 0
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Removing the session for $user_key."
        }
    }
definition-signature d/SlmwsO4YeDlh3eJpLqam9ytq0/EkWnAce1XTQ5bxOyla0x/VHjkr9dvoo3awaxp7lEjAenIgwGpS2jL5R1hq48WGZN2nu9LDKVjTosrq7j1MHbeKiIW8yXc3IEUtbbkhkAGNnMmfDYMD8Vg7l+iBx6B/WvRTZLr+tmppFf0BIr2Z7FWWU6c9OVl8YH1VuqqFX/lKICn2EXDhebRDRVvuXobLvbjZQxj+tqdUU2vuLzXYot/RUgClXHrg6Z2ZC6/WuAq4pp/XA2kvzWotQiY9gEceQdMC7/BxPSR8xo4VPNqkFkEPjh5hehZP0tFONTZaMaH1klVg4QbvHH5MRiBQ==
    verification-status signature-verified
}
ltm rule _sys_APM_ExchangeSupport_helper {
    nodelete nowrite 
    # The purpose of this iRule is for help the main virtual for the timing of the HTTP request retry
    # during the SSO process for OutlookAnywhere protocol request which has a Content-Length value of 1GB.
    when HTTP_REQUEST {
        #  Waiting for the first chunk of data.
        HTTP::collect 1
    }
    when HTTP_REQUEST_DATA {
        # Respond 401 and close the connection once we received the data.
        HTTP::respond 401 WWW-Authenticate NTLM Connection close
    }
definition-signature fnJWcC75FIDV4savxGjyZ5sTdRTen+3mItejhseH06qn+qBXjOl/j7wYRSLDv1IcFezF8BunbDftMHXrW7QRuPuxhjMIc4vaALE2CCGkO0xcs258F+nkPeeJKoR5mTHY/E5BWpOAISinUBUSA3/nUm8blXkMwVg/Q95360jcCOoi6csgJa97OSKIF9h9OQCylh1qGBsDRHEXCR3ycw5Eb4T2QQSdBn09vr8Hgdpi/9fUER97nzJe8T/RuoG+nQ7bc8F9yzG6nFa/CQtRYDybDrcNgllCfVloXZAHZS3dCpq6FnS/FaEWfSIujmV+lXkxY23Xz9Wf6i1h/feW9fEUiQ==
    verification-status signature-verified
}
ltm rule _sys_APM_ExchangeSupport_main {
    nodelete nowrite 
    # Global variables
    # static::POLICY_RESULT_CACHE_AUTHFAILED
    #     Administrator can set this into 1, when there is a necessity to cache failed policy result.
    #     This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.
    #     One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.
    # Responses
    # On denied result
    #     Administrator can customize the responses to the device depends on more complex conditions when necessary.
    #     In those cases, please use ACCESS::respond command.
    #     The following is the syntax of ACCESS::respond
    #     ACCESS::respond <status code> [ content <body> ] [ <Additional Header> <Additional Header value>* ]
    #     e.g. ACCESS::respond 401 content "Error: Denied" WWW-Authenticate "basic realm=\"f5.com\"" Connection close
    when RULE_INIT {
        # Please set the following global variables for customized responses.
        set static::actsync_401_http_body "<html><title>Authentication Failured</title><body>Error: Authentication Failure</body></html>"
        set static::actsync_503_http_body "<html><title>Service is not available</title><body>Error: Service is not available</body></html>"
        set static::ACCESS_LOG_PREFIX                 "01490000:7:"
        # Second Virtual Server name for 401 NTLM responder
        set static::ACCESS_SECOND_VIRTUAL_NAME        "_ACCESS_401_NTLM_responder_HTTPS"
        set static::POLICY_INPROGRESS                 "policy_inprogress"
        set static::POLICY_AUTHFAILED                 "policy_authfailed"
        # The request with huge content length can not be used for starting ACCESS session.
        # This kind of request will be put on hold, and this iRule will try to use another
        # request to start the session. The following value is used for Outlook Anywhere.
        set static::OA_MAGIC_CONTENT_LEN              1073741824
        # Similar with OutlookAnywhere case, ACCESS can not use the request which is
        # larger then following size. This becomes an issue with application that using
        # Exchange Web Service as its main protocol such as Mac OS X applications
        # (e.g. Mail app, Microsoft Entourage, etc)
        # This kind of request will be put on hold, and this iRule will try to use another
        # request to start the session.
        set static::FIRST_BIG_POST_CONTENT_LEN        640000
        # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.
        set static::EWS_BKEND_BASIC_AUTH              0
        # Set it into 1 if the backend RPC-over-HTTP handler accepts HTTP Basic Authentication.
        set static::RPC_OVER_HTTP_BKEND_BASIC_AUTH    0
        # The following variable controls the polling mechanism.
        set static::POLICY_RESULT_POLL_INTERVAL       250
        set static::POLICY_RESULT_POLL_MAXRETRYCYCLE  600
        # Set this global variable to 1 for caching authentication failure
        # Useful for avoiding account locked out.
        set static::POLICY_RESULT_CACHE_AUTHFAILED    0
        # set this global variable to set alternative timeout for particular session
        set static::POLICY_ALT_INACTIVITY_TIMEOUT     120
        set static::ACCESS_USERKEY_TBLNAME            "_access_userkey"
        set static::ACCESS_DEL_COOKIE_HDR_VAL         "MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"
        log -noname accesscontrol.local1.debug "01490000:7: RPC_OVER_HTTP_BKEND_BASIC_AUTH = $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH"
        log -noname accesscontrol.local1.debug "01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH"
    }
    when ACCESS_ACL_ALLOWED {
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]"
        if { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 }  {
            if { $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH == 0 } {
                if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Use this virtual $static::ACCESS_SECOND_VIRTUAL_NAME just once. Will be reset back after disconnection."
                    use virtual $static::ACCESS_SECOND_VIRTUAL_NAME
                }
               log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Remove HTTP Auth header"
               HTTP::header remove Authorization
            }
        }
        # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been
        # already authenticated if there is a HTTP Basic Auth in the request.
        if { [ info exists f_exchange_web_service ] && $f_exchange_web_service  == 1 }  {
            if { $static::EWS_BKEND_BASIC_AUTH == 0 } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header"
                HTTP::header remove Authorization
            }
        }
    }
    when HTTP_REQUEST {
        set http_path                       [ string tolower [HTTP::path] ]
        set f_clientless_mode               0
        set f_alt_inactivity_timeout        0
        set f_rpc_over_http                 0
        set f_exchange_web_service          0
        set f_auto_discover                 0
        set f_activesync                    0
        set f_offline_address_book          0
        set f_availability_service          0
        #  Here put appropriate pool when necessary.
        switch -glob $http_path {
        "/rpc/rpcproxy.dll" {
            # Supports for RPC over HTTP. (Outlook Anywhere)
            set f_rpc_over_http 1
        }
        "/autodiscover/autodiscover.xml" {
            # Supports for Auto Discover protocol.
            set f_auto_discover 1
            # This request does not require long inactivity timeout.
            # Don't use this for now
            set f_alt_inactivity_timeout 0
        }
        "/microsoft-server-activesync" {
            # Supports for ActiveSync
            set f_activesync 1
        }
        "/oab/*" {
            # Supports for Offline Address Book
            set f_offline_address_book 1
        }
        "/ews/*" {
            # Support for Exchange Web Service
            # Outlook's Availability Service borrows this protocol.
            set f_exchange_web_service 1
        }
        "/as/*" {
            # Support for Availability Service.
            # do nothing for now. (Untested)
            set f_availability_service 1
        }
        default {
            return
        }
        }
        set f_reqside_set_sess_id           0
        set http_method                     [HTTP::method]
        set http_hdr_host                   [HTTP::host]
        set http_hdr_uagent                 [HTTP::header User-Agent]
        set src_ip                          [IP::remote_addr]
        set http_uri                        [HTTP::uri]
        set http_content_len                [HTTP::header Content-Length]
        set MRHSession_cookie               [HTTP::cookie value MRHSession]
        set auth_info_b64enc                ""
        if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {
            set PROFILE_POLICY_TIMEOUT            [PROFILE::access access_policy_timeout]
        }
        if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {
            set PROFILE_MAX_SESS_TIMEOUT          [PROFILE::access max_session_timeout]
        }
        if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {
            set PROFILE_RESTRICT_SINGLE_IP        1
        }
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX method: $http_method"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Src IP: $src_ip"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len"
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP"
        # First, do we have valid MRHSession cookie.
        if { $MRHSession_cookie != "" } {
            if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie"
            } else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie"
                set MRHSession_cookie ""
                HTTP::cookie remove MRHSession
            }
        }
        set http_hdr_auth [HTTP::header Authorization]
        if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header"
            set http_hdr_auth ""
        }
        if { $http_hdr_auth == "" } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX No/Empty Auth header"
            # clean up the cookie
            if { $MRHSession_cookie == "" } {
                HTTP::respond 401 content  $static::actsync_401_http_body WWW-Authenticate "Basic realm=\"[HTTP::header Host]\"" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close
                return
            }
            # Do nothing if we have a valid MRHSession cookie.
        }
        set f_release_request           0
        # Optimization for clients which support cookie
        if { $MRHSession_cookie != "" } {
            # Default profile access setting is false
            if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                set f_release_request 1
            }
            elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie "session.user.clientip" ] ] } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP matched"
                set f_release_request 1
            }
            else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP does not matched"
                set MRHSession_cookie ""
                HTTP::cookie remove MRHSession
            }
        }
        if { $f_release_request == 0 } {
            set apm_username [ string tolower [HTTP::username]]
            set apm_password [HTTP::password]
            if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                binary scan [md5 "$apm_password"] H* user_hash
            } else {
                binary scan [md5 "$apm_password$src_ip"] H* user_hash
            }
            set user_key    {}
            append user_key $apm_username "." $user_hash
            unset user_hash
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX apm_username: $apm_username"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX user_key = $user_key"
            set apm_cookie_list             [ ACCESS::user getsid $user_key ]
            if { [ llength $apm_cookie_list ] != 0 } {
                set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]
                if { $apm_cookie != "" } {
                    HTTP::cookie insert name MRHSession value $apm_cookie
                    set f_release_request 1
                }
            }
        }
        if { $http_content_len ==  $static::OA_MAGIC_CONTENT_LEN } {
            set f_oa_magic_content_len 1
        }
        set f_sleep_here 0
        set retry 1
        while { $f_release_request == 0 && $retry <=  $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len"
            # This is also going to touch the table entry timer.
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME"
            set apm_cookie [table lookup -subtable  $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]
            if { $apm_cookie != "" } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie"
                # Accessing SessionDB is not that cheap. Here we are trying to check known value.
                if { $apm_cookie == "policy_authfailed" || $apm_cookie == "policy_inprogress"} {
                    # Do nothing
                } elseif  { ! [ ACCESS::session exists $apm_cookie ] } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync"
                    # Table value is out of sync. Ignores it.
                    set apm_cookie ""
                }
            }
            switch $apm_cookie {
            "" {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX NO APM Cookie found"
                if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {
                    # Outlook Anywhere request comes in pair. The one with 1G payload is not usable
                    # for creating new session since 1G content-length is intended for client to upload
                    # the data when needed.
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len"
                    set f_sleep_here 1
                } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {
                    # Here we are getting large EWS request, which can't be used for starting new session
                    # in clientless-mode. Have it here waiting for next smaller one.
                    # We are holding the request here in HTTP filter, and HTTP filter automatically
                    # clamping down the TCP window when necessary.
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request"
                    set f_sleep_here 1
                } else {
                   set apm_cookie               "policy_inprogress"
                   set f_reqside_set_sess_id    1
                   set f_release_request        1
                }
            }
            "policy_authfailed" {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED"
                HTTP::respond 401 content  $static::actsync_401_http_body
                set f_release_request 1
            }
            "policy_inprogress" {
                if { [ info exists f_activesync ] && ($f_activesync == 1) } {
                    # For ActiveSync requests, aggressively starts new session.
                    set f_reqside_set_sess_id    1
                    set f_release_request        1
                } else {
                    set f_sleep_here 1
                }
            }
            default {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie"
                HTTP::header insert Cookie "MRHSession=$apm_cookie"
                set f_release_request 1
            }
            }
            if { $f_reqside_set_sess_id == 1 } {
                set f_reqside_set_sess_id 0
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT"
                set f_clientless_mode 1
                HTTP::cookie remove MRHSession
                HTTP::header insert "clientless-mode" 1
                HTTP::header insert "username" $apm_username
                HTTP::header insert "password" $apm_password
                table set -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT
            }
            if { $f_sleep_here == 1 } {
                set f_sleep_here 0
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Waiting  $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri"
                after  $static::POLICY_RESULT_POLL_INTERVAL
            }
            incr retry
        }
        if { $f_release_request == 0 && $retry >=  $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri"
            table delete -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
            ACCESS::disable
            TCP::close
            return
        }
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri"
    }
    when ACCESS_SESSION_STARTED {
        if { [ info exists user_key ] } {
            ACCESS::session data set "session.user.uuid" $user_key
            ACCESS::session data set "session.user.microsoft-exchange-client" 1
            if { [ info exists f_activesync ] && $f_activesync == 1 } {
                ACCESS::session data set "session.user.microsoft-activesync" 1
            }
            elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {
                ACCESS::session data set "session.user.microsoft-autodiscover" 1
            }
            elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {
                ACCESS::session data set "session.user.microsoft-availabilityservice" 1
            }
            elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {
                ACCESS::session data set "session.user.microsoft-rpcoverhttp" 1
            }
            elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {
                ACCESS::session data set "session.user.microsoft-offlineaddressbook" 1
            }
            elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {
                ACCESS::session data set "session.user.microsoft-exchangewebservice" 1
            }
        }
        if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {
            ACCESS::session data set "session.inactivity_timeout"  $static::POLICY_ALT_INACTIVITY_TIMEOUT
        }
    }
    when HTTP_RESPONSE {
        if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {
            set content_len [ HTTP::header Content-Length ]
            if {  $content_len > 0 } {
                HTTP::collect $content_len
            }
        }
    }
    when HTTP_RESPONSE_DATA {
        if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {
            if { [ regsub -line {<AuthPackage>Ntlm</AuthPackage>} [ HTTP::payload ] {<AuthPackage>Basic</AuthPackage>} payload ] != 0 } {
                HTTP::payload replace 0 $content_len $payload
            }
        }
    }
    when ACCESS_POLICY_COMPLETED {
        if { ! [ info exists user_key ] } {
            return
        }
        set user_key_value ""
        set f_delete_session 0
        set policy_result [ACCESS::policy result]
        set sid [ ACCESS::session sid ]
        log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \"$policy_result\" user_key = \"$user_key\" sid = \"$sid\""
        set inactivity_timeout [ACCESS::session data get "session.inactivity_timeout"]
        set max_sess_timeout [ACCESS::session data get "session.max_session_timeout"]
        if { $max_sess_timeout == "" } {
             set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT
        }
        switch $policy_result {
        "allow" {
            # We depends on this table record self-cleanup capability in order to
            # indirectly sync with session DB.
            set user_key_value $sid
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value"
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX sid = $sid"
        }
        "deny" {
            # When necessary the admin here can check appropriate session variable
            # and decide what response more appropriate then this default response.
            ACCESS::respond 401 content  $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close
            if {  $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {
                set user_key_value  $static::POLICY_AUTHFAILED
            } else {
                set f_delete_session  1
            }
        }
        default {
            ACCESS::respond 503 content  $static::actsync_503_http_body Connection close
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)"
            set f_delete_session  1
        }
        }
        if { $user_key_value != "" } {
           log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME"
           table set -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout
        } else {
           log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME"
           table delete -subtable  $static::ACCESS_USERKEY_TBLNAME $user_key
        }
        if { $f_delete_session == 1 } {
           ACCESS::session remove
           set f_delete_session 0
           log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Removing the session for $user_key."
        }
    }
definition-signature feX9LM+vB6YOEdVF+EA1JtNyVkPaB7gwdW0JzaB083MXl4yPP2nZnjm+WAx3YQhsmLttq5UkPl1zHpr5H9cwJX1bu9BNMi/+n0bIqWOipDHhhSYQ+TH+a5jQUSeftISr52BSQxh0cQKZkzM3rFU/qRZn9D9Dbf0kDGiDC1KWwVosrdjp5tVHOiQXWx8zybbGPFfgBcIBE6IvOvGbh5ohebVL2ADZm0URRj2NM4ZvZ2T3C14k2rHGXnDdRsvhmf5USZ+FH1hoKtWRxqtFjkWIaqw8leenXeot1j2bdKy92/AVTC9oZj1HJN1ePuQo5v414zlUhMEtkVy/gaxvj1+vPQ==
    verification-status signature-verified
}
ltm rule _sys_APM_Office365_SAML_BasicAuth {
    nodelete nowrite 
when HTTP_REQUEST {
        if { [string tolower [HTTP::path]] == "/saml/idp/profile/redirectorpost/sso" } {
            set http_hdr_client_app [HTTP::header X-MS-Client-Application]
            if { $http_hdr_client_app != "" && ($http_hdr_client_app contains "Microsoft.Exchange") } {
                set http_hdr_auth [HTTP::header Authorization]
                if { ($http_hdr_auth == "") || ([ string match -nocase {basic *} $http_hdr_auth ] != 1 ) } {
                    unset http_hdr_auth
                    unset http_hdr_client_app
                    return
                }
                HTTP::header insert "clientless-mode" 1
                HTTP::header insert "username" [HTTP::username]
                HTTP::header insert "password" [HTTP::password]
                unset http_hdr_auth
            }
            unset http_hdr_client_app
        }
    }
definition-signature X3dd2mwvsY19opLav5FPu81K061a4utSwTjNKaxM+4gATCHIpjxt32J5sSQypUR3bafYFJuHy54e+D1Lo3LFy+LbvjCtk5+OGTkcyG+HmfHI6sLnrG2ZupkxAQUknNtn8uxa6qnWXlqCfkZonjXSlrqUSQwUUd4E/V82I1ZfogMCMdh4AlRIRJpQhb1PGR/reD2G6cXWlStb4ZQuLQarv0c8BBGC1U7C4dF3qpUH2x+j1hNm8E/QjUFYaKbym6QbbkqmCbR8rvrT13gXh7WPZ6kkUVHdV1U+dJY36N3xxByKPE0bOg6dq3+MGueBctNxmE/qp1B3VKc2vqi2fk/LJQ==
    verification-status signature-verified
}
ltm rule _sys_APM_activesync {
    nodelete nowrite 
when RULE_INIT {
        set static::actsync_401_http_body   "<html><title>Authentication Failured</title><body>Error: Authentication Failure</body></html>"
        set static::actsync_503_http_body   "<html><title>Service is not available</title><body>Error: Service is not available</body></html>"
        set static::ACCESS_LOG_PREFIX       "01490000:7:"
    }
    when HTTP_REQUEST {
        set http_path                       [string tolower [HTTP::path]]
        set f_clientless_mode               0
        if { $http_path == "/microsoft-server-activesync" } {
        }
        elseif { $http_path == "/autodiscover/autodiscover.xml" } {
            set f_auto_discover 1
        }
        else return
        if { ! [ info exists src_ip ] } {
            set src_ip                            [IP::remote_addr]
        }
        if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {
            set PROFILE_RESTRICT_SINGLE_IP  	  1
        }
        # Only allow HTTP Basic Authentication.
        set auth_info_b64enc                ""
        set http_hdr_auth                   [HTTP::header Authorization]
        regexp -nocase {Basic (.*)} $http_hdr_auth match auth_info_b64enc
        if { $auth_info_b64enc == "" } {
            set http_hdr_auth ""
        }
        if { $http_hdr_auth == "" } {
            log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX Empty/invalid HTTP Basic Authorization header"
            HTTP::respond 401 content $static::actsync_401_http_body Connection close
            return
        }
        set MRHSession_cookie               [HTTP::cookie value MRHSession]
        # Do we have valid MRHSession cookie.
        if { $MRHSession_cookie != "" } {
            if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie"
                # Default profile access setting is false
                if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
                    return
                }
                elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie "session.user.clientip" ] ] } {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP matched"
                    return
                }
                else {
                    log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX source IP does not matched"
                }
            }
            else {
                log -noname accesscontrol.local1.debug "$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie"
            }
            set MRHSession_cookie ""
            HTTP::cookie remove MRHSession
        }
        set apm_username                    [ string tolower [HTTP::username] ]
        set apm_password                    [HTTP::password]
        if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {
            binary scan [md5 "$apm_password$"] H* user_hash
        } else {
            binary scan [md5 "$apm_password$src_ip"] H* user_hash
        }
        set user_key {}
        append user_key $apm_username "." $user_hash
        unset user_hash
        set f_insert_clientless_mode    0
        set apm_cookie_list             [ ACCESS::user getsid $user_key ]
        if { [ llength $apm_cookie_list ] != 0 } {
            set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]
            if { $apm_cookie != "" } {
                HTTP::cookie insert name MRHSession value $apm_cookie
            } else {
                set f_insert_clientless_mode 1
            }
        } else {
            set f_insert_clientless_mode 1
        }
        if { $f_insert_clientless_mode == 1 } {
            HTTP::header insert "clientless-mode" 1
            HTTP::header insert "username" $apm_username
            HTTP::header insert "password" $apm_password
        }
        unset f_insert_clientless_mode
    }
    when ACCESS_SESSION_STARTED {
        if { [ info exists user_key ] } {
            ACCESS::session data set "session.user.uuid" $user_key
            ACCESS::session data set "session.user.microsoft-exchange-client" 1
            ACCESS::session data set "session.user.activesync" 1
            if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {
                set f_auto_discover 0
                ACCESS::session data set "session.user.microsoft-autodiscover" 1
            }
        }
    }
    when ACCESS_POLICY_COMPLETED {
        if { ! [ info exists user_key ] } {
            return
        }
        set policy_result [ACCESS::policy result]
        switch $policy_result {
        "allow" {
        }
        "deny" {
            ACCESS::respond 401 content $static::actsync_401_http_body Connection close
            ACCESS::session remove
        }
        default {
            ACCESS::respond 503 content $static::actsync_503_http_body Connection close
            ACCESS::session remove
        }
        }
        unset user_key
    }
definition-signature s9Un4H1gVmKPFbVadbNZM+hFnWssJtXmoD/SMt4LSXbWwoc2FRHmPsf4xil4pgFnm4V4hqH9dvIdlceyE0t0GIhouPPz4j9e+PcDQZZVV2K8gjT4+xRg38Rc+R0a633kMr88N5yksAujOQwv2gVdpSoeeQXwVnCnHcTBcu1qn0SwSFTkKaqHDGnDDcUmFl0yo+xtqtDKG5FR43nyAA3dHwu+QY21NAQaEBgN5zfVe4prr+AdVZK359E7ZyW6gGNPr+rhYQ5J5v2Q2NofSBgY7OGIO609GzAHWd7cvNesm34SzMNxrOfgSAdg9DieJi905cHxFn02nyPD54wn0YX2Bg==
    verification-status signature-verified
}
ltm rule _sys_auth_krbdelegate {
    nodelete nowrite 
when HTTP_REQUEST {
        set thecert ""
        set ckname F5KRBAUTH
        set ckpass abc123
        set authprofiles [PROFILE::list auth]
        # Search the auth profiles for the krbdelegate(7) and grab cookie info
        foreach profname $authprofiles {
            if { [PROFILE::auth $profname type] == 7 } {
                set tmpckname [PROFILE::auth $profname cookie_name]
                set tmpckpass [PROFILE::auth $profname cookie_key]
                if {[PROFILE::auth $profname cookie_name] != "" } {
                    set ckname $tmpckname
                    set ckpass $tmpckpass
                    break
                }
            }
        }
        set seecookie 0
        set insertcookie 0
        # check for the cookie
        if {not [info exists tmm_auth_http_sids(krbdelegate)]} {
            set tmm_auth_sid [AUTH::start pam default_krbdelegate]
            set tmm_auth_http_sids(krbdelegate) $tmm_auth_sid
            AUTH::subscribe $tmm_auth_sid
        } else {
            set tmm_auth_sid $tmm_auth_http_sids(krbdelegate)
        }
        if { [PROFILE::exists clientssl] } {
            set certcmd "SSL::cert 0"
            set thecert [ eval $certcmd ]
        }
        if { $thecert == "" } {
            # if no cert, assume old kerb delegation
            # if there is no Authorization header and no cookie, get one.
            if { ([HTTP::header Authorization] == "") and
                  (not [HTTP::cookie exists $ckname])} {
                HTTP::respond 401 WWW-Authenticate Negotiate
                return
            }
        }
        if {[HTTP::cookie exists $ckname]} {
            set ckval [HTTP::cookie decrypt $ckname $ckpass]
            AUTH::username_credential $tmm_auth_sid "cookie"
            AUTH::password_credential $tmm_auth_sid $ckval
            set seecookie 1
        } else {
            if { $thecert == "" } {
                # Kerberos Delegation - set username
                # Strip off the Negotiate before the base64d goodness
                AUTH::username_credential $tmm_auth_sid [lindex [HTTP::header Authorization] 1]
            }
            else {
                # Protocol Transition - set ttm_auth_sid
                AUTH::username_credential $tmm_auth_sid "krpprottran"
                AUTH::cert_credential $tmm_auth_sid $thecert
            }
            AUTH::password_credential $tmm_auth_sid "xxxx"
        }
        AUTH::authenticate $tmm_auth_sid
        if {not [info exists tmm_auth_http_collect_count]} {
            HTTP::collect
            set tmm_auth_http_successes 0
            set tmm_auth_http_collect_count 1
        } else {
            incr tmm_auth_http_collect_count
        }
    }
    when AUTH_RESULT {
        if {not [info exists tmm_auth_http_sids(krbdelegate)] or             ($tmm_auth_http_sids(krbdelegate) != [AUTH::last_event_session_id]) or             (not [info exists tmm_auth_http_collect_count])} {
            return
        }
        if {[AUTH::status] == 0} {
            incr tmm_auth_http_successes
        }
        # If multiple auth sessions are pending and
        # one failure results in termination and this is a failure
        # or enough successes have now occurred
        if {([array size tmm_auth_http_sids] > 1) and             ((not [info exists tmm_auth_http_sufficient_successes] or              ($tmm_auth_http_successes >= $tmm_auth_http_sufficient_successes)))} {
            # Abort the other auth sessions
            foreach {type sid} [array get tmm_auth_http_sids] {
                unset tmm_auth_http_sids($type)
                if {($type ne "krbdelegate") and ($sid != -1)} {
                    AUTH::abort $sid
                    incr tmm_auth_http_collect_count -1
               }
            }
        }
        # If this is the last outstanding auth then either
        # release or respond to this session
        incr tmm_auth_http_collect_count -1
        if {$tmm_auth_http_collect_count == 0} {
            unset tmm_auth_http_collect_count
            if { [AUTH::status] == 0 } {
                array set pamout [AUTH::response_data]
                HTTP::header replace Authorization "Negotiate $pamout(krbdelegate:attr:SPNEGO)"
                if {$seecookie == 0} {
                    set insertcookie $pamout(krbdelegate:attr:KRB5CCNAME)
                }
                HTTP::release
            } else {
                HTTP::respond 401 WWW-Authenticate Negotiate "Set-Cookie" "$ckname= ; expires=Wed Dec 31 16:00:00 1969"
            }
        }
    }
    # When the response goes out, if we need to insert a cookie, do it.
    when HTTP_RESPONSE {
        if {$insertcookie != 0} {
            HTTP::cookie insert name $ckname value $insertcookie
            HTTP::cookie encrypt $ckname $ckpass
        }
    }
definition-signature mILi/VF69pqpNg+XJ4nClBl8+zq4v9FsiBYnKjX3zLZOChRWKt5CwkwpsbCRzx5DnvHglp9uXDYrjqcAFvM5aRA2R5LAhKQSq6pVPwHdZUJluYv0t3n6af/vSyc7KYsx6gga1jLuiFZaEzmG8c+r4igxwEee874iQBjYaWhHyKYGhlhly/Ez2FE9DNRpRepz2sq/jaKzEmmMod3CCXurXVGlC/Pk8qnbNid1yC15DGosrAKW1d8lhYbVBaXVQ1ahrr/UPYnDdHB1BiWUzRSS4uOKuUyUmT/xPI14/Nwv8zdFvlu+AnnD543zH6KhdSHhJ3zCVy2HSZ5wPuN3YswcBA==
    verification-status signature-verified
}
ltm rule _sys_auth_ssl_cc_ldap {
    nodelete nowrite 
when CLIENT_ACCEPTED {
        set tmm_auth_ssl_cc_ldap_sid 0
        set tmm_auth_ssl_cc_ldap_done 0
    }
    when CLIENTSSL_CLIENTCERT {
        if {[SSL::cert count] == 0} {
            return
        }
        set tmm_auth_ssl_cc_ldap_done 0
        if {$tmm_auth_ssl_cc_ldap_sid == 0} {
            set tmm_auth_ssl_cc_ldap_sid [AUTH::start pam default_ssl_cc_ldap]
            if {[info exists tmm_auth_subscription]} {
                AUTH::subscribe $tmm_auth_ssl_cc_ldap_sid
            }
        }
        AUTH::cert_credential $tmm_auth_ssl_cc_ldap_sid [SSL::cert 0]
        AUTH::authenticate $tmm_auth_ssl_cc_ldap_sid
        SSL::handshake hold
    }
    when CLIENTSSL_HANDSHAKE {
        set tmm_auth_ssl_cc_ldap_done 1
    }
    when AUTH_RESULT {
        if {[info exists tmm_auth_ssl_cc_ldap_sid] and             ($tmm_auth_ssl_cc_ldap_sid == [AUTH::last_event_session_id])} {
            set tmm_auth_status [AUTH::status]
            if {$tmm_auth_status == 0} {
                set tmm_auth_ssl_cc_ldap_done 1
                SSL::handshake resume
            } elseif {$tmm_auth_status != -1 || $tmm_auth_ssl_cc_ldap_done == 0} {
                reject
            }
        }
    }
definition-signature O2ctQteahGXIbb4l9/vERvtwKeyl51hGNNGgccddtwme/6opsgPJu5gaiVGUXYYDkbcjFdfgDTU9oDPkLl5JmZ3VcExnlnvxLpVDuM/fKqxbgoRQZ6nl0mEceHmWxRY9AlhrODtJZxNRbQBu4OOCYS+yWioKgKkrBwQaEoIFBPSSUmeIPZHTXdNnLXwxxkY75O5Sc4sTkYQ3BvTrlu/frnwweed6qw9bWatN865CIzP3Spq0ELY0Q4bvxo+0JdLheFv2BfKUethrjEXcxiD9Ros0fnvQ83qaCHqt18xEyhakdKAf4gKZJt9UApkRn+1ZTPNJFzgQyPPYQGvU/y9JAQ==
    verification-status signature-verified
}
ltm rule _sys_auth_ssl_crldp {
    nodelete nowrite 
when CLIENT_ACCEPTED {
        set tmm_auth_ssl_crldp_sid 0
        set tmm_auth_ssl_crldp_done 0
    }
    when CLIENTSSL_CLIENTCERT {
        if {[SSL::cert count] == 0} {
            return
        }
        set tmm_auth_ssl_crldp_done 0
        if {$tmm_auth_ssl_crldp_sid == 0} {
            set tmm_auth_ssl_crldp_sid [AUTH::start pam default_ssl_crldp]
            if {[info exists tmm_auth_subscription]} {
                AUTH::subscribe $tmm_auth_ssl_crldp_sid
            }
        }
        AUTH::cert_credential $tmm_auth_ssl_crldp_sid [SSL::cert 0]
        AUTH::cert_issuer_credential $tmm_auth_ssl_crldp_sid [SSL::cert issuer 0]
        AUTH::authenticate $tmm_auth_ssl_crldp_sid
        SSL::handshake hold
    }
    when CLIENTSSL_HANDSHAKE {
        set tmm_auth_ssl_crldp_done 1
    }
    when AUTH_RESULT {
        if {[info exists tmm_auth_ssl_crldp_sid] and             ($tmm_auth_ssl_crldp_sid == [AUTH::last_event_session_id])} {
            set tmm_auth_status [AUTH::status]
            if {$tmm_auth_status == 0} {
                set tmm_auth_ssl_crldp_done 1
                SSL::handshake resume
            } elseif {$tmm_auth_status != -1 || $tmm_auth_ssl_crldp_done == 0} {
                reject
            }
        }
    }
definition-signature PhTy24ctbtx0d4kFIFO6+Fr9W3a/7OetZ7nlh18mpH6BB9t1dB2LNayATLZ3q4iT4wLLdyyxA+g4jdrNBeuZVpM2JOBlhwcyIcTBFLQN4H/mkWErH4Vz9ZMxVduUxHN6fIh8zDQuJJYoRVlz087/vIVvk6ygbPwS9KqTdYBa3Nn79YmIVn1NXKyVoCg/40EZ3iNklwIfKctwqGU5ELKbhwk8CGCvexDbJcwRqv8nAETC4B/nc61jpGcihpOJchJFb3buTiAKwfxSYkx90UG4EnwsyA4GqUNIfS02Dj5rYSMH403CNNBKG2AA+ZGy9by2O3bb9lq/VNGPDmsnMEff1g==
    verification-status signature-verified
}
ltm rule _sys_auth_ssl_ocsp {
    nodelete nowrite 
when CLIENT_ACCEPTED {
        set tmm_auth_ssl_ocsp_sid 0
        set tmm_auth_ssl_ocsp_done 0
    }
    when CLIENTSSL_CLIENTCERT {
        if {[SSL::cert count] == 0} {
            return
        }
        set tmm_auth_ssl_ocsp_done 0
        if {$tmm_auth_ssl_ocsp_sid == 0} {
            set tmm_auth_ssl_ocsp_sid [AUTH::start pam default_ssl_ocsp]
            if {[info exists tmm_auth_subscription]} {
                AUTH::subscribe $tmm_auth_ssl_ocsp_sid
            }
        }
        AUTH::cert_credential $tmm_auth_ssl_ocsp_sid [SSL::cert 0]
        AUTH::cert_issuer_credential $tmm_auth_ssl_ocsp_sid [SSL::cert issuer 0]
        AUTH::authenticate $tmm_auth_ssl_ocsp_sid
        SSL::handshake hold
    }
    when CLIENTSSL_HANDSHAKE {
        set tmm_auth_ssl_ocsp_done 1
    }
    when AUTH_RESULT {
        if {[info exists tmm_auth_ssl_ocsp_sid] and             ($tmm_auth_ssl_ocsp_sid == [AUTH::last_event_session_id])} {
            set tmm_auth_status [AUTH::status]
            if {$tmm_auth_status == 0} {
                set tmm_auth_ssl_ocsp_done 1
                SSL::handshake resume
            } elseif {$tmm_auth_status != -1 || $tmm_auth_ssl_ocsp_done == 0} {
                reject
            }
        }
    }
definition-signature mHRNmZiszQh85wPdt5PxM2ASLXyW47LE3CM5tS11M1lTe9ttjlWDc6yBdy5VFjC6H2O2DJ+fyrBmeMen16RVWPhUoq8YOJC9ZiuuLc6T/rW9GsopSHFPBLRjL/EPulNkuGB/DtxYvwXfXOyBuVRw+E/TYkKVi6cIrk4+e9mOnCo9biWycrRfemWwYyDCqouEaDK2huYnQ1rKyYAvIWxfd3rXXw6+jdpuvL/6RFXJjaLTJ/f1pVMHP5kuI2K/dkeojqDDgr1d1GnjIFFX2Azh5qZpaL1urPfn/M6C/7sXzew1PU0ow10MQtKKqAno5IpEpn+cPZlCs3d2Y1khtMqUug==
    verification-status signature-verified
}
ltm rule _sys_https_redirect {
    nodelete nowrite 
when HTTP_REQUEST {
       HTTP::redirect https://[getfield [HTTP::host] ":" 1][HTTP::uri]
    }
definition-signature mwyl4XlRKRMQc0prWs7RtpgPcNfocOKb+MaFwAnQgAuUZZyG68OaGZsOCN3poUOFdHOc6fk2XAdGRmTRiP/7BCT7thsOX5zLFzA1N1wcr57KWVzEZt3ezxVXn2Z974OmbWm7P5Lclcr7N3adrLJMWfyfPPVF1tUYn0IQPD2QNMmfbcbr1oCuO93n/5dn0s6/EacHZGG53hVibW7xQuJXdMtoQ6ArSZ4U3n4vCDTb6NLYbAj6PirVzKY2pcsWFHFUSVrphSFwERc8+0XGHUE6Cb3ihzygoZc2cQ5jk3frFY70MkDluPTShFRbHd7PlMPRezrfkVZVeUHA/iBPcYcD+w==
    verification-status signature-verified
}


