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

Filter by:
  • Solution
  • Technology
Answers

Keep applications active after web interface logoff

Hi!

I'm trying to make a configuration with Big-ip APM to replace two old Citrix Access Gateways for our Citrix farms.
I've made a setup using the iApp for XenApp using f5.citrix_xenapp_xendesktop.2012_06_27 which load balances and authenticates users to our XenApp 5.4 web interfaces.
We are using TMOS 11.2.0 and will not replace the web interface with webtop (basically do pass-through auth if I understand this correct)

One issue I immediately ran into was that the applications I start gets disconnected when I log off the web interface and my APM session closes.
The setting "Logoff behavior: Log off all sessions" is unchecked in Citrix web interface.

If I start applications directly from the web interface servers, without going through the APM, the appications remain active when I log off.


Is there any way to get the applications to remain active even when the APM session closes, so that it mimics the behavior of the old gateways?

I've looked through the iApp deployment guide and also the settings in APM, but haven't found anything that seems to control this.


Thanks!


/Andreas
 

1
Rate this Question
Comments on this Question
Comment made 22-Nov-2016 by Tiwan Nicholson 0

Looks like this is a very popular question in F5 land...a quick Google search turned up at least a half-dozen forum posts asking for this very solution. Well count me in as someone who needs to solve this problem. I noticed that there are multiple iRule scripting approaches outlined in the comments of this post, so I'd like to know a) which of these scripts is the "most correct" for me to use, or b) if at this point (APM v12.1.1 with iApp v2.3.0) BigIP has come up with a simpler, non-scripted way of doing it. And before you ask, I did try the "Should the iApp remove the APM session when users log out of the Web Interface or StoreFront servers?" option in the iApp, and it still did not work.

My requirements are very much like those that "bhs" described on 10/17/2014:

  1. If a user manually clicks "logoff" from StoreFront, all open ICA sessions are terminated.

  2. If the StoreFront page times out (not deliberate user logoff), the ICA sessions remain open.

  3. If the user (still with existing ICA sessions open) logs into F5/SF again, they can launch new apps alongside those in the existing open ICA session.

  4. When a user logs off from StoreFront, they are redirected back to the F5 signin page.

We were able to accomplish #4 using an iRule documented in the Citrix VDI iApp Deployment Guide v2.5. But we're still facing the first 3 requirements.

As a first-time F5 implementer with no iRule scripting experience, I'd appreciate any guidance any of you are willing to provide.

1

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
After a lot of trial and error, I managed to piece together an iRule from various sources here on devcentral.

Turned out to be a bit trickier than I thought, because there may be several tcp connections open from the browser to the web interface, and all those
are authenticated in APM. So simply expiring the APM session cookies and redirecting back to the logon page did not work.
The browser would in that case use another, already establised, connection to request logon page, and (from what I can understand) APM would just send
the request through and the user ended up beeing logged on to the web interface again.
So to get around that I store the session id in a table and check subsequent requests if they are for a logged out session.

Any comments or suggestions greatly appreciated :)


when RULE_INIT {
set ::debug 0
set ::logonpage "https://logon.company.com/"
set ::logoffURI "/auth/loggedout.aspx"
}


when ACCESS_ACL_ALLOWED {

if {$::debug > 1 } { log local1. "uri=[HTTP::uri] | session=[ACCESS::session sid] | client=[IP::client_addr]:[TCP::client_port]" }

# Has the user logged off?
if {[HTTP::uri] contains $::logoffURI } {
if {$::debug} { log local1. "Detected logoff!" }

# need to track the sessionID because after the redirect has been sent, the browser may use an
# already established (access granted) tcp connection that will be allowed through ACCESS_ACL_ALLOED.
table add -subtable "ctxloggedoutsessions" [ACCESS::session sid] 1 60 90

# store the APM session cookies from the request.
if {[HTTP::cookie exists "MRHSession"]} {
set MRHSession [HTTP::cookie MRHSession]
if {$::debug} { log local1. "MRHSession=$MRHSession" }
}

if {[HTTP::cookie exists "LastMRH_Session"]} {
set LastMRH_Session [HTTP::cookie LastMRH_Session]
if {$::debug} { log local1. "LastMRH_Session =$LastMRH_Session " }
}
}
}


when HTTP_RESPONSE {

set sessionstatus [table lookup -subtable "ctxloggedoutsessions" [ACCESS::session sid]]

# check if this reponse is for a session that has been marked as logged off.
if { $sessionstatus == 1 } {
# yes, user has logged off.

if {$::debug} { log local1. "Found session [ACCESS::session sid] in table" }
set cookieheaders ""

# prepare the APM session cookies to be expired by setting the date to UNIX TS 0
if { [info exists MRHSession ] } {
set cookieheaders "MRHSession=$MRHSession;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$::debug} { log local1. "setting cookie, MRHSession" }
unset MRHSession
}

if { [info exists LastMRH_Session ] } {
set cookieheaders "$cookieheaders\r\nSet-Cookie: LastMRH_Session=$LastMRH_Session;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$::debug} { log local1. "setting cookie, LastMRH_Session" }
unset LastMRH_Session
}

# Loop through all other cookies which are set in the repsonse, and expire those as well.
# This does not seem to be needed.
#
#if {$::debug} { log local1. "looping cookies..." }
#foreach orgCookieName [HTTP::cookie names] {
# if {$::debug} { log local1. "found cookie: $orgCookieName=[HTTP::cookie value $orgCookieName]" }
#
# set cookieheaders "$cookieheaders\r\nSet-Cookie: $orgCookieName=[HTTP::cookie value $orgCookieName];expires=Thu, 01-Jan-1970 00:00:00 GMT;[HTTP::cookie path $orgCookieName];"
#}

if {$::debug} { log local1. "Custom cookies: $cookieheaders" }

# Send a redirect response to the client. With Connection: Close!
if { $cookieheaders != "" } {
HTTP::respond 302 Location "$::logonpage" "Set-Cookie" $cookieheaders "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
} else {
HTTP::respond 302 Location "$::logonpage" "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
}
}
}
1
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Nice work in figuring this out.

Make sure to use static variables in RULE_INIT to preserve CMP:

https://devcentral.f5.com/wiki/iRules.CMPCompatibility.ashx

Also, generally you should only use a subtable if you need to count the entries. You can use a prefix on the key names instead to prevent key name collisions.


when RULE_INIT {
	set static::access_debug 0
	set static::logonpage "https://logon.company.com/"
	set static::logoffURI "/auth/loggedout.aspx"
}


when ACCESS_ACL_ALLOWED {

	if {$static::access_debug > 1 } { log local1. "uri=[HTTP::uri] | session=[ACCESS::session sid] | client=[IP::client_addr]:[TCP::client_port]" }

	# Has the user logged off?
	if {[string tolower [HTTP::path]] eq $static::logoffURI } {
		if {$static::access_debug} { log local1. "Detected logoff!" }

		# need to track the sessionID because after the redirect has been sent, the browser may use an
		# already established (access granted) tcp connection that will be allowed through ACCESS_ACL_ALLOED.
		table add "ctxloggedoutsessions_[ACCESS::session sid]" 1 60 90

		# store the APM session cookies from the request.
		if {[HTTP::cookie exists "MRHSession"]} {
			set MRHSession [HTTP::cookie MRHSession]
			if {$static::access_debug} { log local1. "MRHSession=$MRHSession" }
		}

		if {[HTTP::cookie exists "LastMRH_Session"]} {
			set LastMRH_Session [HTTP::cookie LastMRH_Session]
			if {$static::access_debug} { log local1. "LastMRH_Session =$LastMRH_Session " }
		}
	}
}

when HTTP_RESPONSE {

	set sessionstatus [table lookup "ctxloggedoutsessions_[ACCESS::session sid]]"

	# check if this reponse is for a session that has been marked as logged off.
	if { $sessionstatus == 1 } {
		# yes, user has logged off.

		if {$static::access_debug} { log local1. "Found session [ACCESS::session sid] in table" }
		set cookieheaders ""

		# prepare the APM session cookies to be expired by setting the date to UNIX TS 0
		if { [info exists MRHSession] } {
			set cookieheaders "MRHSession=$MRHSession;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
			if {$static::access_debug} { log local1. "setting cookie, MRHSession" }
			unset MRHSession
		}

		if { [info exists LastMRH_Session] } {
			set cookieheaders "$cookieheaders\r\nSet-Cookie: LastMRH_Session=$LastMRH_Session;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
			if {$static::access_debug} { log local1. "setting cookie, LastMRH_Session" }
			unset LastMRH_Session
		}

		# Loop through all other cookies which are set in the repsonse, and expire those as well.
		# This does not seem to be needed.
		#
		#if {$static::access_debug} { log local1. "looping cookies..." }
		#foreach orgCookieName [HTTP::cookie names] {
		# if {$static::access_debug} { log local1. "found cookie: $orgCookieName=[HTTP::cookie value $orgCookieName]" }
		#
		# set cookieheaders "$cookieheaders\r\nSet-Cookie: $orgCookieName=[HTTP::cookie value $orgCookieName];expires=Thu, 01-Jan-1970 00:00:00 GMT;[HTTP::cookie path $orgCookieName];"
		#}

		if {$static::access_debug} { log local1. "Custom cookies: $cookieheaders" }

		# Send a redirect response to the client. With Connection: Close!
		if { $cookieheaders != "" } {
			HTTP::respond 302 Location "$static::logonpage" "Set-Cookie" $cookieheaders "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
		} else {
			HTTP::respond 302 Location "$static::logonpage" "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
		}
	}
}


Aaron
1
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Here is a slightly modified iRule that is confirmed working as of 11.6HF1

when RULE_INIT {
set static::access_debug 0
set static::logonpage "https://CTX.COMPANY.COM/YOUR_CITRIX_XENAPP/"
set static::logoff_timeout "/YOUR_CITRIX_XENAPP/site/logout.aspx?ctx_timeout"
set static::logoff_user "/YOUR_CITRIX_XENAPP/site/logout.aspx"
}
 
 
when HTTP_REQUEST {
 
 
#log "[string tolower [HTTP::path]]"
 
if {$static::access_debug > 1 } { log  "uri=[HTTP::uri] | session=[ACCESS::session sid] | client=[IP::client_addr]:[TCP::client_port]" }
 
# Has the user logged off?
if {[string tolower [HTTP::uri]] starts_with $static::logoff_timeout} {
 set ctx_timeout 1
 
 
if {$static::access_debug} { log  "Detected logoff!" }
 
# need to track the sessionID because after the redirect has been sent, the browser may use an
# already established (access granted) tcp connection that will be allowed through ACCESS_ACL_ALLOED.
table add "ctxloggedoutsessions_[ACCESS::session sid]" 1 60 90
 
# store the APM session cookies from the request.
if {[HTTP::cookie exists "MRHSession"]} {
set MRHSession [HTTP::cookie MRHSession]
if {$static::access_debug} { log  "MRHSession=$MRHSession" }
}
 
if {[HTTP::cookie exists "LastMRH_Session"]} {
set LastMRH_Session [HTTP::cookie LastMRH_Session]
if {$static::access_debug} { log  "LastMRH_Session =$LastMRH_Session " }
}
}
 
if {([string tolower [HTTP::uri]] starts_with $static::logoff_user) && ![info exists ctx_timeout]} {
                             after 2000  { ACCESS::session remove}
                            #log local0. "Session manually logging out"
             }
 
}
 
when HTTP_RESPONSE {
 
set sessionstatus [table lookup "ctxloggedoutsessions_[ACCESS::session sid]"]
 
# check if this reponse is for a session that has been marked as logged off.
if { $sessionstatus == 1 } {
# yes, user has logged off.
 
if {$static::access_debug} { log  "Found session [ACCESS::session sid] in table" }
set cookieheaders ""
 
# prepare the APM session cookies to be expired by setting the date to UNIX TS 0
if { [info exists MRHSession] } {
set cookieheaders "MRHSession=$MRHSession;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$static::access_debug} { log  "setting cookie, MRHSession" }
unset MRHSession
}
 
if { [info exists LastMRH_Session] } {
set cookieheaders "$cookieheaders\r\nSet-Cookie: LastMRH_Session=$LastMRH_Session;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$static::access_debug} { log  "setting cookie, LastMRH_Session" }
unset LastMRH_Session
}
 
# Loop through all other cookies which are set in the repsonse, and expire those as well.
# This does not seem to be needed.
#
#if {$static::access_debug} { log  "looping cookies..." }
#foreach orgCookieName [HTTP::cookie names] {
# if {$static::access_debug} { log  "found cookie: $orgCookieName=[HTTP::cookie value $orgCookieName]" }
#
# set cookieheaders "$cookieheaders\r\nSet-Cookie: $orgCookieName=[HTTP::cookie value $orgCookieName];expires=Thu, 01-Jan-1970 00:00:00 GMT;[HTTP::cookie path $orgCookieName];"
#}
 
if {$static::access_debug} { log  "Custom cookies: $cookieheaders" }
 
# Send a redirect response to the client. With Connection: Close!
if { $cookieheaders != "" } {
HTTP::respond 302 Location "$static::logonpage" "Set-Cookie" $cookieheaders "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
} else {
HTTP::respond 302 Location "$static::logonpage" "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
}
}
}
1
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Andreas,

F5 solution takes security to the next level - since we proxy all the connections through the APM, customers expressed desire to have an enhanced level of control where existing ICA sessions for the user terminate when the APM session for that user terminates. That said, in your case, there is a very easy solution to your problem.

Our default iApp setting is to tie in Web Interface Logout action to the termination of the APM session. That is accompished by the iRule that is created by the iApp. All you have to do is uncheck "Strict" updates from the Application Service you deployed, and then remote that iRule from the Virtual server- and your applications will now stay active after you log off WI, since APM session will not be terminated.

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Thanks for your quick reply!

Didn't think of looking at the iRules :)
Thanks!

I've done a few tests now, with logging off web interface, logged off and then closed browser, closed browser directly. And all work fine. Applications stays active.

The only thing is that the users will get the Citrix web interface logon page (which looks different) after logging off. They won't come back to APM logon.

Is there a way to fix that?

I looked at the iRule and it did "ACCESS::session remove"
Is it possible to change that and create a new session instead of removing the old? Would that send the user back to the APM logon?

Or would that cause other problems with old sessions filling up?


/Andreas

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Andreas,

Are you asking of it's possible for the SSO to kick back in if the APM session is still in progress and the user wants to go back to Web Interface? That should be possible - try to go to SSO config and check "Successfull Logon Detection Match" option to None, and see if SSO works after user logs off WI and then goes back in.

Or are you asking to have users authenticated by the APM again after they log out? That might be more challenging - you can try to use an iRule, but you can't remove the session because it will kill all the associated ICA sessions. You can try to remove MRHSession cookie in the HTTP_RESPONSE event(something like HTTP::cookie remove MRHSession) or better yet, set the MRHSession cookie to a date in the past so that it would expire on the browser side. This way browser would be forced to start a new APM session when they try to go back into WI - and user will end up having mutliple different APM sessions.



0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Andreas,

Are you asking of it's possible for the SSO to kick back in if the APM session is still in progress and the user wants to go back to Web Interface? That should be possible - try to go to SSO config and check "Successfull Logon Detection Match" option to None, and see if SSO works after user logs off WI and then goes back in.

Or are you asking to have users authenticated by the APM again after they log out? That might be more challenging - you can try to use an iRule, but you can't remove the session because it will kill all the associated ICA sessions. You can try to remove MRHSession cookie in the HTTP_RESPONSE event(something like HTTP::cookie remove MRHSession) or better yet, set the MRHSession cookie to a date in the past so that it would expire on the browser side. This way browser would be forced to start a new APM session when they try to go back into WI - and user will end up having mutliple different APM sessions.



0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
It would be great if the users could get back to the APM logon, and basically log back on if they wanted to.

I was looking at the reference for ACCESS:: and there is an ACCESS::session create
So I was thinking of just replacing ACCESS::session remove with ACCESS::session create in the iRule.

The MRHSession cookie, is that something APM-internal for the current session?
Is the details of MRHSession documented somewhere?
I found some info in Configuration_Guide_for_BIG-IP_Access_Policy_Manager.pdf

Thanks!


/Andreas
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
MRHSession cookie contains the sessionid that is read by APM. If the session indicated in the cookie exists, user will be allowed. ACCESS:session create will create a new session, but it will NOT insert the coookie automatically in the response.

So, best advice I can give you is play with the iRule to change the expiration date on the MRHSession cookie to something in the past so that it would be expired on the browser, but the APM session will still be active, so existing ICA sessions willl continue.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Ah ok.
Thanks for the info.

I'll take a closer look at the iRule/MRHSession and see if I can get it to work.


/andreas
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Thanks!

/Andreas
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Perfect just what I was looking for.

Had to make one adjustment to the iRule (location of the last close bracket):

when HTTP_RESPONSE {

    set sessionstatus [table lookup "ctxloggedoutsessions_[ACCESS::session sid]"]

Mark

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

I just used this iRule to address this exact issue and it worked great. Thank you for the time and effort to put this together. Here is a copy of my Rule as it stands (tested and confirmed to be working). This was for a Xen6.5 SF2.1 on BIG-IP 11.5.0HF2.

when RULE_INIT {
set static::access_debug 0
#The logonpage and logoffURI must be entered in all lower case below so when the stringtolower command compares the real path with the static variables, they match correctly
set static::logonpage "https://thisneedstobealllowercase.com/my.policy"
set static::logoffURI "/this/needsto/beall/lowercase"
}
 
 
when ACCESS_ACL_ALLOWED {
if {$static::access_debug = 1 } { log local0. "uri=[HTTP::uri] | session=[ACCESS::session sid] | client=[IP::client_addr]:[TCP::client_port]" }
 

# Has the user logged off? (Changed to http_uri instead of http_path 6-17-2014)
if {[string tolower [HTTP::uri]] eq $static::logoffURI } {
if {$static::access_debug = 1 } { log local0. "Detected logoff!" }
 
# need to track the sessionID because after the redirect has been sent, the browser may use an
# already established (access granted) tcp connection that will be allowed through ACCESS_ACL_ALLOED.
table add "ctxloggedoutsessions_[ACCESS::session sid]" 1 60 90
 
# store the APM session cookies from the request.
if {[HTTP::cookie exists "MRHSession"]} {
set MRHSession [HTTP::cookie MRHSession]
if {$static::access_debug} { log local0. "MRHSession=$MRHSession" }
}
 
if {[HTTP::cookie exists "LastMRH_Session"]} {
set LastMRH_Session [HTTP::cookie LastMRH_Session]
if {$static::access_debug} { log local0. "LastMRH_Session =$LastMRH_Session " }
}
}
}
 
when HTTP_RESPONSE {
 
set sessionstatus [table lookup "ctxloggedoutsessions_[ACCESS::session sid]"]
 
# check if this reponse is for a session that has been marked as logged off.
if { $sessionstatus == 1 } {
# yes, user has logged off.
 
if {$static::access_debug} { log local0. "Found session [ACCESS::session sid] in table" }
set cookieheaders ""
 
# prepare the APM session cookies to be expired by setting the date to UNIX TS 0
if { [info exists MRHSession] } {
set cookieheaders "MRHSession=$MRHSession;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$static::access_debug} { log local0. "setting cookie, MRHSession" }
unset MRHSession
}
 
if { [info exists LastMRH_Session] } {
set cookieheaders "$cookieheaders\r\nSet-Cookie: LastMRH_Session=$LastMRH_Session;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$static::access_debug} { log local0. "setting cookie, LastMRH_Session" }
unset LastMRH_Session
}
 
# Loop through all other cookies which are set in the repsonse, and expire those as well.
# This does not seem to be needed.
#
#if {$static::access_debug} { log local0. "looping cookies..." }
#foreach orgCookieName [HTTP::cookie names] {
# if {$static::access_debug} { log local0. "found cookie: $orgCookieName=[HTTP::cookie value $orgCookieName]" }
#
# set cookieheaders "$cookieheaders\r\nSet-Cookie: $orgCookieName=[HTTP::cookie value $orgCookieName];expires=Thu, 01-Jan-1970 00:00:00 GMT;[HTTP::cookie path $orgCookieName];"
#}
 
if {$static::access_debug > 0 } { log local0. "Custom cookies: $cookieheaders" }
 
# Send a redirect response to the client. With Connection: Close!
if { $cookieheaders != "" } {
HTTP::respond 302 Location "$static::logonpage" "Set-Cookie" $cookieheaders "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
} else {
HTTP::respond 302 Location "$static::logonpage" "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
}
}
}

BHS

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi all,

we were first lucky to find this thread and solution, because we also have a requirement, that the application should still be active, after the user logs off from webinterface or closes the browser.

Redirecting back to the APM logon page is working fine with this iRule, but applications will be disconnected when hitting the logoff button.

:EDIT: It seems to be fine for the first time. But when I close the application and re-start it again, then it disconnects when I logoff from WI.

At the moment we have no further idea where to search for, below some technical details of what we are using.

  • TMOS 11.4.1 HF4
  • iApp f5.citrix_vdi.v1.1.0
  • XenApp 6.5
  • StoreFront 2.5

Thank you for any further hints or troubleshooting steps.

Ciao Stefan :)

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

I found out that the reason for disconnecting the application is that the APM session is killed/removed. But it seems to be not 100% reproducible, means once it gets disconnected I can re-logon, start the application and when hitting the logoff button it gets disconnected again. I performed this 3-5 times in a row and always the same behavior, but sometimes it stays connected. I verified the APM log and the difference between a disconnected session and a connected one is as follows.

Connected one ends with this entry:

474a67ec: SSO disabled for '' using config '/Common/Kae-Citrix-iApp.app/Kae-Citrix-iApp_apm_sso_form_based', pass through request

Disconnected one ends with these entries:

88d66e1d: SSO disabled for '' using config '/Common/Kae-Citrix-iApp.app/Kae-Citrix-iApp_apm_sso_form_based', pass through request
88d66e1dW: Session deleted due to user logout request.
88d66e1d: Session stats update failed

So why is the logoff process from WI processed into APM and why not always? Any idea to which configuration this is related to?

Thank you!

Ciao Stefan :)

0
Comments on this Answer
Comment made 17-Oct-2014 by bhs
Hi guys, For my implementation the requirement was if the user manually clicked "logoff" and had apps open it would kill everything. This is the desired behavior that we wanted from a security perspective. If the users want to abruptly end all sessions...they click logoff on the SF page. The second challenge was when the Storefront page timed out but the user had applications open. This iRule addresses that too. The desired behavior with this iRule is ...if the SF page times out (even though in citrix land this is a logoff event) the BIG-IP will still maintain open applications. If the user logs in again, then they will be able to launch new apps along side of the apps that are still opened under the old session. The requirement was....for as long as the user does not manually click "logoff" then BIG-IP should still timeout the SF page but maintain the application sessions during SF page timeouts. I believe this is most appropriate way for this to be configured and that if a user manually clicks "logoff" then that is basically saying kill my sessions, otherwise they would have to close each app 1 at a time. Think about in a health care environment. HC Staff is working on a shared workstation. That person needs to move to another area. Does he/she have time to kill every open app? Nope they click logoff and roll. Conversely, what if they are spending a lot of time in one area and they have lots of apps open? If we killed the application sessions when the SF page times out they would be logging back in and launching every app again every 15 minutes. This iRule created the exact behaviors I described above and makes the most sense to me from a security perspective. The good news is that with iRules, you can do whatever you want. You could intercept that logoff event if you really wanted to and prevent it from being passed but what security ramifications does this present?
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
when ACCESS_ACL_ALLOWED {

    if {[string tolower [HTTP::uri]] eq "/citrix/<yourpath>/authentication/logoff"} {

        table add "ctxloggedoutsessions_[ACCESS::session sid]" 1 28800 28800
    }
}

when HTTP_REQUEST {

    set sessionstatus [table lookup "ctxloggedoutsessions_[ACCESS::session sid]"]

         if { $sessionstatus == 1 } {



            HTTP::respond 302 Location "https://www.yourcitrixapm.com/my.logout.php3"

                unset sessionstatus
                table delete "ctxloggedoutsessions_[ACCESS::session sid]"

        }
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

`

(function ($) {
    $.localization.customStringBundle('en', {
        YouAreLoggedOff: 'You have logged off successfully.'
                +'<script type="text/javascript">'
                +'window.location.replace("https://mycitrix.com/my.policy");'
                +'</script>'
    });
})(jQuery);

`

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

On version 12.0 I found I had to modify the following in order for it to work.

if {$static::access_debug = 1 } to be if {$static::access_debug == 1 }

However, after you click on the logoff it does not truly log me off the system as I click on the log back in button and it brings me back to my published application and does not bring me back to the F5 login page. Any ideas?

Gizmo

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

I had to change this iRule slightly to get it to work for me as I was getting TCL errors for unset variables as well as not getting redirected to the APM login page. My tweaked code is...

when RULE_INIT {
set static::access_debug 0
#The logonpage and logoffURI must be entered in all lower case below so when the stringtolower command compares the real path with the static variables, they match correctly
#Do not set loginpage variable to my.policy, let the APM redirects occur
set static::logonpage "https://myloginpage.com"
set static::logoffURI "/citrix/remoteappsweb/authentication/logoff"

}
when CLIENT_ACCEPTED {
#Set this variable early on to avoid TCL errors
    set ctxloggedoutsessions 0
}

when ACCESS_ACL_ALLOWED {
if {$static::access_debug > 1 } { log local0. "uri=[HTTP::uri] | session=[ACCESS::session sid] | client=[IP::client_addr]:[TCP::client_port]" }


# Has the user logged off? (Changed to http_uri instead of http_path 6-17-2014)
if {[string tolower [HTTP::uri]] eq $static::logoffURI } {
if {$static::access_debug == 1 } { log local0. "Detected logoff!" }

# need to track the sessionID because after the redirect has been sent, the browser may use an
# already established (access granted) tcp connection that will be allowed through ACCESS_ACL_ALLOWED.

set ctxloggedoutsessions ctxloggedoutsessions_[ACCESS::session sid]

table add $ctxloggedoutsessions 1 60 90

# store the APM session cookies from the request.
if {[HTTP::cookie exists "MRHSession"]} {
set MRHSession [HTTP::cookie MRHSession]
if {$static::access_debug} { log local0. "MRHSession=$MRHSession" }
}

if {[HTTP::cookie exists "LastMRH_Session"]} {
set LastMRH_Session [HTTP::cookie LastMRH_Session]
if {$static::access_debug} { log local0. "LastMRH_Session =$LastMRH_Session " }
}
}
}

when HTTP_RESPONSE {

set sessionstatus [table lookup $ctxloggedoutsessions]


# check if this reponse is for a session that has been marked as logged off.
if {$sessionstatus == 1} {
# yes, user has logged off.

if {$static::access_debug} { log local0. "Found session [ACCESS::session sid] in table" }
set cookieheaders ""

# prepare the APM session cookies to be expired by setting the date to UNIX TS 0
if { [info exists MRHSession] } {
set cookieheaders "MRHSession=$MRHSession;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$static::access_debug} { log local0. "setting cookie, MRHSession" }
unset MRHSession
}

if { [info exists LastMRH_Session] } {
set cookieheaders "$cookieheaders\r\nSet-Cookie: LastMRH_Session=$LastMRH_Session;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;"
if {$static::access_debug} { log local0. "setting cookie, LastMRH_Session" }
unset LastMRH_Session
}

# Loop through all other cookies which are set in the repsonse, and expire those as well.
# This does not seem to be needed.
#
#if {$static::access_debug} { log local0. "looping cookies..." }
#foreach orgCookieName [HTTP::cookie names] {
# if {$static::access_debug} { log local0. "found cookie: $orgCookieName=[HTTP::cookie value $orgCookieName]" }
#
# set cookieheaders "$cookieheaders\r\nSet-Cookie: $orgCookieName=[HTTP::cookie value $orgCookieName];expires=Thu, 01-Jan-1970 00:00:00 GMT;[HTTP::cookie path $orgCookieName];"
#}

if {$static::access_debug > 0 } { log local0. "Custom cookies: $cookieheaders" }

# Send a redirect response to the client. With Connection: Close!
if { $cookieheaders != "" } {
HTTP::respond 302 noserver Location "$static::logonpage" "Set-Cookie" $cookieheaders "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
TCP::close
} else {
HTTP::respond 302 noserver Location "$static::logonpage" "X-OLL-CTX-LOGOUT" "1" "Connection" "Close"
TCP::close
}
}
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

I was given a similar requirement. The backend is 7.1X Citrix which requires (according to AskF5) 13.1+. I was able to set up everything via an iApp, then replicate without the iApp ('cause I hate iApps). The problem I faced is storefront java script logged out after 20 minutes-ish and killed the APM session. The requirement I was given was to allow that timeout, but to also let active VDI's to continue (they ride the same APM session).

This is what I came up with, which works for me, YMMV:

when CLIENT_ACCEPTED {
    set citrix_logout 0
}
when HTTP_REQUEST {

    set hardlimit 86400
    set VDI_Logoff "/Citrix/yourstore/Authentication/Logoff"
    set storeWebName "/Citrix/yourstore/"

    if { [HTTP::uri] == $VDI_Logoff } {
        set cookieNames [HTTP::cookie names]
        set MRHSession [HTTP::cookie value MRHSession]
        table set -subtable loggedout [HTTP::cookie value MRHSession] limit $hardlimit
        ACCESS::disable
        set clear_cookies 1
    } else {
        if { [table lookup -subtable "loggedout" [HTTP::cookie value MRHSession]] != "" } {
                    log local0. "Rejecting MRHSession [HTTP::cookie value MRHSession]"
                    reject
        }
    }
}
when HTTP_RESPONSE {
    if { [info exists clear_cookies] } {
        foreach aCookie $cookieNames {
            HTTP::cookie insert name $aCookie value 0
            HTTP::cookie expires 1
        }
    }
}
when ACCESS_ACL_ALLOWED {
    set type [ACCESS::session data get session.client.type]
    if { !($type starts_with "citrix") } {
        set http_uri [HTTP::uri]
        if { $http_uri == "/" || ($citrix_logout eq 0 && $http_uri ends_with "login.aspx") } {
            ACCESS::respond 302 Location "https://[HTTP::host]$storeWebName"
        } elseif { $http_uri contains "Logoff" } {
            set citrix_logout 1
        } elseif { $citrix_logout eq 1 && $http_uri ends_with "login.aspx" } {
            set citrix_logout 0
            ACCESS::respond 200 content "Logged out\r\n" Connection close
            ACCESS::session remove
        } elseif { $http_uri ends_with "Disconnect" } {
           ACCESS::respond 200 content "Logged out\r\n" Connection close
           ACCESS::session remove
        }
    }
}

0
Comments on this Answer
Comment made 3 months ago by NETSEC 83

Hi Marc,

I have same the issue and with this iRule I was able to keep the session open however when I try to log back in, I was able to successfully authenticate but never get the storefront page and I noticed it is creating a new session not resuming the old session. Any help on this is sincerely appreciated.

0