Forum Discussion

ddubya_152376's avatar
ddubya_152376
Icon for Nimbostratus rankNimbostratus
May 09, 2014

f5 Access Policy Manager AJAX vs Non-Ajax Request Handling with Authentication

I'm implementing a Single Page Application (Javascript/AJAX Based) leveraging the f5 as the Identity Provider and Service Provider for Single-Sign-On. The Web app sits behind the f5 in Apache, and the web services also sit behind the f5 using simple REST based HTTP calls the front end calls from the client side with Javascript.

 

When the user's session expires in the f5 AJAX calls start failing because the f5 is handling the GET/POST requests and determines the user is not authenticated. The f5 then then responds to the client request by sending a 302 Redirect Response with the Location header set to: /my.policy in order to redirect the client browser back to the login page. This works for normal HTTP requests, but not for Javascript AJAX requests.

 

The low level XHR object in the browser automatically attempts to follow the redirect to /my.policy before it hands the response back to the client javascript and the javascript is not aware that the 302 redirect occurred since it's transparently handled by the low level XHR.

 

The front-end Javascript client app includes the header: 'X-Requested-With: XMLHttpRequest' with all AJAX requests that proxy through the f5.

 

What I would like to do is customize the f5 to respond to client HTTP requests with a 401 Unauthorized response when the session is expired in the f5 when the original HTTP request has the X-Requested-With: XMLHttpRequest header. For all other requests from a client without the X-Requested-With header I want it to continue sending the 302 Redirect to /my.policy as it does currently.

 

Is this customization possible in the f5?

 

14 Replies

  • kunjan's avatar
    kunjan
    Icon for Nimbostratus rankNimbostratus

    See if this helps:

    when ACCESS_SESSION_STARTED { 
      if { [HTTP::header "X-Requested-With" ] equals "XMLHttpRequest" } {     
         ACCESS::respond 401 
      }   
    }
    
    • ddubya_152376's avatar
      ddubya_152376
      Icon for Nimbostratus rankNimbostratus
      Looks very strait forward. I'm quite novice to f5 configuration. Where would this configuration go in the f5? Will this iRule only hit when the session has expired or is invalid?
  • See if this helps:

    when ACCESS_SESSION_STARTED { 
      if { [HTTP::header "X-Requested-With" ] equals "XMLHttpRequest" } {     
         ACCESS::respond 401 
      }   
    }
    
    • ddubya_152376's avatar
      ddubya_152376
      Icon for Nimbostratus rankNimbostratus
      Looks very strait forward. I'm quite novice to f5 configuration. Where would this configuration go in the f5? Will this iRule only hit when the session has expired or is invalid?
  • Will this iRule only hit when the session has expired or is invalid?

     

    No, this will hit as long as the header matches. Assumption is the first time you hit APM you don't have this header. Again, I'm not sure how you want to handle the 401 response.

     

    Create the irule - Local Traffic ›› iRules : iRule List ›› Create

     

    Add to VS- Local Traffic ›› Virtual Servers : Virtual Server List ›› ›› iRule Manage

     

    • ddubya_152376's avatar
      ddubya_152376
      Icon for Nimbostratus rankNimbostratus
      I don't want to have every HTTP Request with the X-Requested-With header to cause a 401 Unauthorized response. I only want requests, where the f5 normally responds with a 302 redirect to /my.policy because the user's session has expired, to respond with a 401 http response when the request has the header X-Requested-With: XMLHttpRequest. I'm looking to customize the request handling behavior the f5 uses when it detects that the user's request is unauthorized. I'm wondering if something like this is possible? ``` when ACCESS_SESSION_EXPIRED { if { [HTTP::header "X-Requested-With" ] equals "XMLHttpRequest" } { ACCESS::respond 401 } } ```
  • kunjan's avatar
    kunjan
    Icon for Nimbostratus rankNimbostratus

    Will this iRule only hit when the session has expired or is invalid?

     

    No, this will hit as long as the header matches. Assumption is the first time you hit APM you don't have this header. Again, I'm not sure how you want to handle the 401 response.

     

    Create the irule - Local Traffic ›› iRules : iRule List ›› Create

     

    Add to VS- Local Traffic ›› Virtual Servers : Virtual Server List ›› ›› iRule Manage

     

    • ddubya_152376's avatar
      ddubya_152376
      Icon for Nimbostratus rankNimbostratus
      I don't want to have every HTTP Request with the X-Requested-With header to cause a 401 Unauthorized response. I only want requests, where the f5 normally responds with a 302 redirect to /my.policy because the user's session has expired, to respond with a 401 http response when the request has the header X-Requested-With: XMLHttpRequest. I'm looking to customize the request handling behavior the f5 uses when it detects that the user's request is unauthorized. I'm wondering if something like this is possible? ``` when ACCESS_SESSION_EXPIRED { if { [HTTP::header "X-Requested-With" ] equals "XMLHttpRequest" } { ACCESS::respond 401 } } ```
  • I just found this in the docs: https://devcentral.f5.com/wiki/iRules.ACCESS__session.ashx

    when HTTP_REQUEST {
       set apm_cookie [HTTP::cookie value MRHSession]
       if { $apm_cookie != "" && ! [ACCESS::session exists $apm_cookie] } {
          HTTP::respond 401 WWW-Authenticate "Basic realm=\"www.example.com\""  
          return
       }
    }
    

    It looks like it's specifically checking every HTTP Request and if the session is not active it will respond with a 401 Unauthorized Response. I think this is what I'm looking for.

  • kunjan's avatar
    kunjan
    Icon for Nimbostratus rankNimbostratus

    ..the user's session has expired, to respond with a 401 http response when the request has the header X-Requested-With: XMLHttpRequest.

    when ACCESS_SESSION_STARTED { 
      if { [HTTP::header "X-Requested-With" ] equals "XMLHttpRequest" && [HTTP::header "Referer" ] contains "my.logout.php3" } {     
         ACCESS::respond 401 
      }   
    }
    
    • ddubya_152376's avatar
      ddubya_152376
      Icon for Nimbostratus rankNimbostratus
      Well, the issue here is that the browser will never cause that Referer header to be sent because the browser application is a Javascript Single Page Application, all HTTP Requests that go to the backend are AJAX, so the client application never does the 302 redirect to the logout page or anywhere else, the javascript eats the 302 redirect transparently. Let me try and attach a screen shot of what I'm experiencing and what I would like instead.
  • ..the user's session has expired, to respond with a 401 http response when the request has the header X-Requested-With: XMLHttpRequest.

    when ACCESS_SESSION_STARTED { 
      if { [HTTP::header "X-Requested-With" ] equals "XMLHttpRequest" && [HTTP::header "Referer" ] contains "my.logout.php3" } {     
         ACCESS::respond 401 
      }   
    }
    
    • ddubya_152376's avatar
      ddubya_152376
      Icon for Nimbostratus rankNimbostratus
      Well, the issue here is that the browser will never cause that Referer header to be sent because the browser application is a Javascript Single Page Application, all HTTP Requests that go to the backend are AJAX, so the client application never does the 302 redirect to the logout page or anywhere else, the javascript eats the 302 redirect transparently. Let me try and attach a screen shot of what I'm experiencing and what I would like instead.
  • kunjan's avatar
    kunjan
    Icon for Nimbostratus rankNimbostratus

    I'm wondering how in the first place the application manages to passes the policy without 302 support.

    Assuming it's not even able do to that because of this(so not a problem of session timeout) you may want to consider the client less mode. If session cookies are not send in the following requests, APM will create a new session for each HTTP request.
    when HTTP_REQUEST {
        HTTP::header insert "clientless-mode" 1
    }