Forum Discussion

JP_135500's avatar
JP_135500
Icon for Nimbostratus rankNimbostratus
Jan 31, 2014

Only enable access policy when server response is 401?

We have a site that is a mix of anonymous and authenticated content. The authenticated content lives all over within the site and is maintained by hundreds of content editors, so there's really no pattern to look for in the URL to determine when a user needs to be authenticated. We are migrating from ISA 2006 and we currently rely on the server to throw a 401 challenge before asking for credentials. Is there a way to do this with the F5?

 

Various business decisions have led us down the path of mixing content and it's critical that we solve this issue in order to continue migrating over to the F5. As we have the F5 APM configured right now, it's kind of all or nothing. Once you hit the site through APM, you're prompted for credentials even if the page you requested is anonymous.

 

Thanks, Josh

 

  • TO add to Josh's suggestion.

     

    If you see the 401 from the server in HTTP_RESPONSE, add some cookie or other marker and redirect client back to the VIP. If the cookie or other marker is seen, then do ACCESS::enable.

     

  • Im facing a similar issue:

     

    I want to allow all access through a VS without authentication, until one of the backend servers sends an auh request (cert, kerberos, ntlm, user&pass, etc). In that case, I want to authenicate the user.

     

    I have to test the iRule above but I believe it will acomplish what I need.

     

    The difficulties start here:

     

    I want to use SSO, so that if a second application requests authentication, I can chose an SSO method, and re-use the credentials used on the first authentication request. Im not sure this would work as each application would create a different session on APM, cookie wont be the same, so I shouldnt be able to re-use credentials for SSO. Am I right?

     

    I was thinking about Multi-Domain SSO configuration on Access Policy properties to solve this issue.

     

    Would it be viable? and how could we mix it with the above rule?

     

    Thanks!

     

  • Hi,

     

    this iRule permit to start authentication process only if the server respond a 401 code. but, if the user want to go back to an unauthenticated content, APM is requesting authentication until the cookie is removed.

     

    the following modified iRule permit the user to go back to an unauthenticated page by checking the state of session. I changed the variable landinguri instead of creating the variable session.cms.starturi to remove ACCESS_POLICY_COMPLETED event.

     

    when HTTP_REQUEST {
         store the host header for the initial /start_policy redirect
        set uri [HTTP::uri]
        set logout_req 0
        set apm_cookie [HTTP::cookie value MRHSession]
        if { ( [ACCESS::session exists -state_allow $apm_cookie] ) \
                 or ( [HTTP::uri] starts_with "/my.policy" ) } {
             initial redirect to /my.policy (starts access policy evaluation) - or a normal post-policy request
            set apm_req 1
            return
        } elseif { ( [HTTP::uri] starts_with "/start_policy" ) } {
             initial redirect to /start_policy (starts access policy evaluation)
             Remove the not established previous sessions
            ACCESS::session remove
            ACCESS::session create -timeout 1800 -lifetime 0
            ACCESS::session data set session.server.landinguri [findstr [HTTP::uri] "/start_policy?url=" 18]
            set apm_req 1
            return
        } else {
             APM session disabled until logon process is started
            ACCESS::disable
            set apm_req 0
            return
        }
    }
    when ACCESS_SESSION_STARTED {
         store the initial (redirect URI) until it's needed
        ACCESS::session data set session.server.landinguri [findstr [HTTP::uri] "/start_policy?url" 18]
    }
    
    when HTTP_RESPONSE { 
        log local0. "apm_req was $apm_req"  
         capture the redirect to authenticate
        if {  ([HTTP::status] eq "401") and ($apm_req eq 0) } {
             initiate access policy processing
            log local0. "apm_req was $apm_req so redirecting"
             HTTP::respond 302 Location "/start_policy?url=$uri"
        }
    }
  • Thank you for the update.

    I changed your iRule to remove Host and scheme in redirect.

    when HTTP_REQUEST {
         store the host header for the initial /start_policy redirect
        set uri [HTTP::uri]
        if { ( [HTTP::cookie exists MRHSession] ) or ( [HTTP::uri] starts_with "/start_policy" ) } {
             initial redirect to /start_policy (starts access policy evaluation) - or a normal post-policy request
            set apm_req 1
            return
        } else {
             APM session disabled until logon process is started
            ACCESS::disable
            set apm_req 0
            return
        }
    }
    when ACCESS_SESSION_STARTED {
         store the initial (redirect URI) until it's needed
        ACCESS::session data set session.cms.starturi [findstr [HTTP::uri] "/start_policy=" 14]
    
    } 
    
    when ACCESS_POLICY_COMPLETED {
         log local0. "uri was [ACCESS::session data get session.cms.starturi]"
         ACCESS::respond 301 Location "[ACCESS::session data get session.cms.starturi]" 
    
    }
    when HTTP_RESPONSE {  
        log local0. "apm_req was $apm_req"   
         capture the redirect to authenticate
        if {  ([HTTP::status] eq "401") and ($apm_req eq 0) } {
             initiate access policy processing
            log local0. "apm_req was $apm_req so redirecting"
             HTTP::respond 302 Location "/start_policy=$uri"
        }
    }
    
  • With help from an F5 engineer, I was able to get this working as I needed. The base of the iRule that I ended up using to get my situation solved is below. This is essentially what the F5 engineer sent along:

    when HTTP_REQUEST {
         store the host header for the initial /start_policy redirect
        set host [HTTP::host]
        set uri [HTTP::uri]
        if { ( [HTTP::cookie exists MRHSession] ) or ( [HTTP::uri] starts_with "/start_policy" ) } {
             initial redirect to /start_policy (starts access policy evaluation) - or a normal post-policy request
            set apm_req 1
            return
        } else {
             APM session disabled until logon process is started
            ACCESS::disable
            set apm_req 0
            return
        }
    }
    when ACCESS_SESSION_STARTED {
         store the initial (redirect URI) until it's needed
        ACCESS::session data set session.cms.starturi [findstr [HTTP::uri] "/start_policy=" 14]
        ACCESS::session data set session.cms.starthost [HTTP::host] 
    } 
    
    when ACCESS_POLICY_COMPLETED {
         log local0. "host was [ACCESS::session data get session.cms.starthost]"
         log local0. "uri was [ACCESS::session data get session.cms.starturi]"
         ACCESS::respond 301 Location "https://[ACCESS::session data get session.cms.starthost][ACCESS::session data get session.cms.starturi]" 
    
    }
    when HTTP_RESPONSE {  
        log local0. "apm_req was $apm_req"   
         capture the redirect to authenticate
        if {  ([HTTP::status] eq "401") and ($apm_req eq 0) } {
             initiate access policy processing
            log local0. "apm_req was $apm_req so redirecting"
             HTTP::respond 302 Location "https://${host}/start_policy=$uri"
        }
    }
    
  • Hi,

    I had the same need for one customer.

    to follow user session, I checked if APM cookie exist.

        when CLIENT_ACCEPTED {
         set request_headers ""
         set need_creds 0
    }
    
    when HTTP_REQUEST {
         set apm_cookie [HTTP::cookie value MRHSession]
         set request_headers [HTTP::request]
    
         if { $need_creds == 1 || $apm_cookie != "" } {
              ACCESS::enable
         } else {
              ACCESS::disable
         }
    }
    
    when HTTP_RESPONSE {
         if {[HTTP::status] == 401 && $need_creds == 0} {
              set need_creds 1
              HTTP::retry $request_headers
         }
    }
    
  • Below is the iRule that I am using (with the logging and comments removed for brevity). I can access the site anonymously, and the need_creds variable does get set to 1 when I browse to an authenticated page. However, after supplying credentials, need_creds resets to 0 and I am not actually logged into the site. Additionally, it 404s on a GET to /F5Networks-SSO-Resp.

    I presume that I do not want to set need_creds in CLIENT_ACCEPTED just because it appears that it resets when the AP is enabled/disabled. Though I don't know. What direction do I need to be looking now? I apologize for being pretty dumb about this...

    when CLIENT_ACCEPTED {
         set request_headers ""
         set need_creds 0
    }
    
    when HTTP_REQUEST {
         set request_headers [HTTP::request]
    
         if { $need_creds == 1 } {
              ACCESS::enable
         } else {
              ACCESS::disable
         }
    }
    
    when HTTP_RESPONSE {
         if {[HTTP::status] == 401 && $need_creds == 0} {
              set need_creds 1
              HTTP::retry $request_headers
         }
    }
    
  • I do have another two questions on this... do I use an iRule Event in the Access Profile to tie into the iRules I am creating for this, or is there another way?

     

    Essentially, I create a variable named 'needsAuth' and set it to 0. I then would have an iRule that checks the response of a request and if it returns 401, set the variable 'needsAuth' to 1. In another iRule, I think just evaluate that variable and if it is set to 1, include ACCESS::enable, otherwise do nothing and continue to have ACCESS::disable hang around.

     

    Both checks need to occur on each request, right? Tying back to my first question... since the AP would be disabled until needed, I shouldn't need to make any changes to it, should I?

     

    Again, thanks for your help!

     

    • You shouldn't have to tie that into the VPE, I think you should only have to apply the irule to the virtual server.
  • Thanks for the quick replies! That's a good idea... Let me play around with that and see if this works for us. I am extremely new to the F5 world, so it may take a little bit. I'll let you know if it works!

     

  • John_Alam_45640's avatar
    John_Alam_45640
    Historic F5 Account

    TO add to Josh's suggestion.

     

    If you see the 401 from the server in HTTP_RESPONSE, add some cookie or other marker and redirect client back to the VIP. If the cookie or other marker is seen, then do ACCESS::enable.

     

  • My thoughts on this are that you likely will have to craft an iRule that sets ACCESS::disable by default, except if the server response is a 401 or some other condition.