Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

OWA Timeout V2

Our institution is running Exchange 2010.  Back in July I presented an irule that would provide a timeout mechanism based upon Exchange timing out the session.  Since then  this irule no longer functions as expected, and it has made it into The deployment guide.

 

Today I present you a new rule that I have been working on. It appears to work a lot better, and provides a more robust logout covering many different scenerios. 

 

when ACCESS_ACL_ALLOWED {
    set apm_mrhsession [HTTP::cookie value "MRHSession"]

    #if exchange has returned a 440(login timeout)  we must now remove the session

    if { [table lookup $apm_mrhsession] == "EXCHANGE_LOGOUT"  } {
        ACCESS::session remove
        table delete $apm_mrhsession  
    }
}




when HTTP_REQUEST {

     # If no Access Session exists and the request is to /owa/*.*  This will cover all requests to ev.owa and keepalive.owa
     if { ![ACCESS::session exists] &&  [string tolower [HTTP::uri]] starts_with "/owa/" && [string tolower [HTTP::uri]] != "/owa/"  } {
        #ensure that the web client knows its session is closed, and causes the main window to refresh /owa/
        #this mimics how the CAS nodes inform the client that their session has expired.
        set cookie_sessionid [format "sessionid=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
        set cookie_cadata [format "cadata=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
            HTTP::respond 440 "Set-Cookie" cookie_sessionid "Set-Cookie" cookie_cadata
     }

 

    
     set user_inactive 0
     if { [HTTP::header exists "X-UserActivity"] && [HTTP::header "X-UserActivity"] == 0 } {
            set mrhsession [HTTP::cookie value "MRHSession"]
            set user_inactive 1
        return
     }



}

when HTTP_RESPONSE {

   # if exchange returns a 440(login timeout) response we need to kill the session on the next request
   if { $user_inactive && [HTTP::status] == 440 } {
    table set $mrhsession "EXCHANGE_LOGOUT"
        return
   }
}

 

Feedback is greatly appreciated.  I have written about 25 variations of the above rule, all of which have varying levels of success.  I believe this rule to be the best performing thus far.

 

 

 

 

0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
So already a couple of minor modifications.
1) Check to see if the MRHSession Cookie exists before calling ![ACCESS::session exists], as there is a tcl error otherwise
2) look for /owa/ and /owa/# to initiate a new session, as owa adds a # when a user accesses calendar.(Not confirmed)

when ACCESS_ACL_ALLOWED {
set apm_mrhsession [HTTP::cookie value "MRHSession"]
if { [table lookup $apm_mrhsession] == "EXCHANGE_LOGOUT" && [ACCESS::session exists]} {
ACCESS::session remove
table delete $apm_mrhsession if { [string tolower [HTTP::uri]] != "/owa/" && [string tolower [HTTP::uri]] != "/owa/#" } {
log local0. "$apm_mrhsession: Session for [IP::client_addr] expired"

}
} if { [string tolower [HTTP::uri]] != "/owa/" && [string tolower [HTTP::uri]] != "/owa/#" } {

when HTTP_REQUEST {


log local0. "HTTP uri [HTTP::uri]"
if { [string tolower [HTTP::uri]] starts_ if { [string tolower [HTTP::uri]] != "/owa/" && [string tolower [HTTP::uri]] != "/owa/#" } {with "/owa/" } {
if { [HTTP::cookie exists "MRHSession"] && ![ACCESS::session exists]} {
if { [string tolower [HTTP::uri]] != "/owa/" && [string tolower [HTTP::uri]] != "/owa/#" } {
set cookie_sessionid [format "sessionid=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
set cookie_cadata [format "cadata=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
HTTP::respond 440 "Set-Cookie" cookie_sessionid "Set-Cookie" cookie_cadata
}
} }
set user_inactive 0
if { [HTTP::header exists "X-UserActivity"] && [HTTP::header "X-UserActivity"] == 0 } {
set mrhsession [HTTP::cookie value "MRHSession"]
set user_inactive 1
return
}



}

when HTTP_RESPONSE {
if { $user_inactive && [HTTP::status] == 440 } {
table set $mrhsession "EXCHANGE_LOGOUT"
return
}
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Hi Terry, when you say the rule no longer works, what do you mean?

The rule below has been tested with Exchange 2010 and is still working for us:

when ACCESS_ACL_ALLOWED {
set apm_mrhsession [HTTP::cookie value "MRHSession"]
if { [table lookup $apm_mrhsession] == "EXCHANGE_LOGOUT" } {
ACCESS::session remove
table delete $apm_mrhsession
}
}
when HTTP_REQUEST {
set isset 0
set request_uri [HTTP::uri]
if {[string tolower [HTTP::uri]] contains "owa" } {
if {[string tolower [HTTP::uri]] contains "logoff.aspx" } {
ACCESS::session remove
HTTP::redirect "https://[HTTP::host]/vdesk/hangup.php3"
} else {
if { [HTTP::uri] contains "UA=0" } {
set mrhsession [HTTP::cookie value "MRHSession"]
set isset 1
}
}
}
}
when HTTP_RESPONSE {
if { $isset == 1 } {
if { $mrhsession != "" && [HTTP::status] == 440 } {
table set $mrhsession "EXCHANGE_LOGOUT"
return
}
}
}

thanks
Mike
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

There are a few scenarios where a user will be presented with an "access policy already started" message and the "click here to start a new session" link will cause a redirect loop. This generally happens network connections are lost for a given period of time, so the apm session expires prior to Exchange saying that the network connection fails.

With this irule
HTTP::respond 440 "Set-Cookie" cookie_sessionid "Set-Cookie" cookie_cadata
mimics what an exchange owa node would return should the connection timeout naturally, which causes the owa app to refresh the main page, which kicks the user out to the login page.
 

Keep in mind that I am still developing this for our environment, and it may not be necessary for everybody.  But we have numerous individuals complaining of this issue, and we need to fix it.


It appears that my copy and paste got a little screwy in my prior post.

 

when ACCESS_ACL_ALLOWED {
        set apm_mrhsession [HTTP::cookie value "MRHSession"]
        if { [table lookup $apm_mrhsession] == "EXCHANGE_LOGOUT" && [ACCESS::session exists]} {
           ACCESS::session remove
           table delete $apm_mrhsession
           log local0. "$apm_mrhsession: Session for [IP::client_addr] expired"

        }
}

when HTTP_REQUEST {

     if { [string tolower [HTTP::uri]] starts_with "/owa/" } {
            if { [HTTP::cookie exists "MRHSession"] && ![ACCESS::session exists]} {
            if { [string tolower [HTTP::uri]] != "/owa/"  && [string tolower [HTTP::uri]] != "/owa/#" } {
                 set cookie_sessionid [format "sessionid=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
                 set cookie_cadata [format "cadata=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
                 HTTP::respond 440 "Set-Cookie" cookie_sessionid "Set-Cookie" cookie_cadata
            } else {
                 log local0. "HTTP uri - not redirected: [HTTP::uri]"
            }

     } }
     set user_inactive 0
     if { [HTTP::header exists "X-UserActivity"] && [HTTP::header "X-UserActivity"] == 0 } {
        set mrhsession [HTTP::cookie value "MRHSession"]
        set user_inactive 1
        return
     }
}

when HTTP_RESPONSE {
   if { $user_inactive && [HTTP::status] == 440 } {
        table set $mrhsession "EXCHANGE_LOGOUT"
        return
   }
}

 

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

The best way to reproduce the aformentioned errors, is to connect to your owa environment via apm.  Once connected locate the session from within the apm gui, and then terminate the session.

Returning to your owa session should produce error messages.

"Access policy evaluation is already in progress for your current session"

Clicking the link causes a redirect loop that ultimately fails.

 

With the irule proposed above, when you terminate the session, the user is kicked out to the login screen and a new session is created.

 

 

 

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
The current rule works in the context of Exchange 2010 and 2013, and the EAC in 2013. The rule you posted does work around the issue when the session is forcibly terminated, however the desired behavior is to bring the user back to the hangup page https://[HTTP::host]/vdesk/hangup.php3, for which we need to issue a redirect command.

I'll have to play around with this some more. The long-term fix for this is being built into TMOS, BTW.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

The simple change below does will redirect to /vdesk/hangup.php3 upon session termination.

I have opened a few tickets regarding the issues with owa timeout, and have never heard that a solution will be provided in TMOS.
I have once again resorted to writing my own irule to solve the issue.

I actually prefer HTTP::redirect "https://[HTTP::host]/my.logout.php3?errorcode=15"
 

when HTTP_REQUEST {

     if { [string tolower [HTTP::uri]] starts_with "/owa/" } {
            if { [HTTP::cookie exists "MRHSession"] && ![ACCESS::session exists]} {
            if { [string tolower [HTTP::uri]] != "/owa/"  && [string tolower [HTTP::uri]] != "/owa/#" } {
                 set cookie_sessionid [format "sessionid=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
                 set cookie_cadata [format "cadata=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
                 HTTP::respond 440 "Set-Cookie" cookie_sessionid "Set-Cookie" cookie_cadata
            } else {
                 HTTP::redirect "https://[HTTP::host]/vdesk/hangup.php3"
            }

     } }
     set user_inactive 0
     if { [HTTP::header exists "X-UserActivity"] && [HTTP::header "X-UserActivity"] == 0 } {
        set mrhsession [HTTP::cookie value "MRHSession"]
        set user_inactive 1
        return
     }
}

 

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
We also need to redirect to that hangup page when the user has clicked the logout link. When I get the chance to test variations of this, both with 2010 and 2013/EAC, I'll post back.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

I have made a few changes to the irule.  Basically now everything that is /owa/.*   will now get a HTTP::respond 440.  Once I realized that I could put content on this response,  I wanted everything that wasnt /owa/ to get this response.  The reason being, now if a user has an email open, and the attempt to interact with after there session is timed out, I can now give them a message stating that there session has timedout,  I can also tell them to log back in and give them a resubmit request link.

 

This is well down the road.

 

The only issue I have been able to find, which for me isnt really a big issue, is the following.

    -user goes to site /owa/ and is redirected to /my.policy and session is created

   - user then opens another window and goes to /owa/  a redirect loop occurs and there original session is destroyed

 

 

 

 

 when RULE_INIT {
     set static::cookie_sessionid [format "sessionid=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
    set static::cookie_cadata [format "cadata=null; path=/; Expires=Thurs, 01-Jan-1970 00:00:00 GMT;"]
}



when ACCESS_ACL_ALLOWED {
        set apm_mrhsession [HTTP::cookie value "MRHSession"]
        if { [table lookup $apm_mrhsession] == "EXCHANGE_LOGOUT" && [ACCESS::session exists]} {
           ACCESS::session remove
           table delete $apm_mrhsession
           log local0. "$apm_mrhsession: Session for [IP::client_addr] expired"
        }
}





when ACCESS_SESSION_STARTED {
    set landing_uri [ACCESS::session data get "session.server.landinguri"]
    log local0. "LANDING_URI: $landing_uri"
}



when HTTP_REQUEST {
  set user_inactive 0
  log local0. "URI: [HTTP::uri]"
  if { [string tolower [HTTP::uri]] starts_with "/owa/" } {
    if { [string tolower [HTTP::uri]] contains "/auth/logoff.aspx" } {
      HTTP::redirect "https://[HTTP::host]/vdesk/hangup.php3"
    }

    set mrhsession [HTTP::cookie value "MRHSession"]
    if {  ($mrhsession != "" && ![ACCESS::session exists]) || $mrhsession == "" } {
      if { [string tolower [HTTP::uri]] != "/owa/"  && [string tolower [HTTP::uri]] != "/owa/#" } {
        HTTP::respond 440 content "WE CAN PUT CONTENT HERE TO TELL THE USER THAT THERE SESSION IS NO LONGER ACTIVE" "Set-Cookie" $static::cookie_sessionid "Set-Cookie" $static::cookie_cadata
      } elseif { ([string tolower [HTTP::uri]] == "/owa/"  || [string tolower [HTTP::uri]] == "/owa/#" ) && $mrhsession != "" } {
         HTTP::redirect "https://[HTTP::host]/vdesk/hangup.php3"
      }
    } else {
      if { [HTTP::header exists "X-UserActivity"] && [HTTP::header "X-UserActivity"] == 0 } {
        set user_inactive 1
      }
    }
  }
}

when HTTP_RESPONSE {
   if { $user_inactive && [HTTP::status] == 440 } {
        table set $mrhsession "EXCHANGE_LOGOUT"
   }
}

 

0