Forum Discussion

Dennis_Kloosterman's avatar
Mar 23, 2021

How to terminate a second APM session using the same MFA account with OTP

Hi,

We have an access policy in place where users log in in two steps, first with a radius username and an OTP generated by a hardware token, and second with their AD account. Our security team wants us to ensure that only one session can exist for which the hardware token was used; if it is used a second time then the already existing session has to be terminated.

I have used the post https://devcentral.f5.com/s/articles/big-ip-apm-max-sessions-per-user-enable-users-to-terminate-a-specified-session as a starting point. 

The problem I'm running into is that the username logged for the session is the second one, but the session has to be identified by the first one. I haven't been able to come up with a way to achieve this.

I assigned a variable in the policy after the first authentication step:

otp_username = expr { "[mcget {session.logon.last.username}]" }. Logging shows that this is working.

In the next step I try to create a custom uuid with this new variable, but this is not possible; the uuid is always formed as [policy name].[session.logon.last.username]

This is what I have come up with so far:

when ACCESS_POLICY_COMPLETED {
  if { [ACCESS::session data get "session.server.landinguri"] starts_with "/uri1" }{
  	set radius_username [ACCESS::session data get otp_username]
  	log local0. "[PROFILE::access name].$radius_username"
  	set apm_cookie_list [ACCESS::uuid getsid "[PROFILE::access name].$radius.username"]
  	
		for {set i 0} {$i < [llength $apm_cookie_list]} {incr i} {
      log local0. "Session => [ lindex $apm_cookie_list $i]"
  	}
  	log local0. "Length of cookie list is now [llength $apm_cookie_list]"
  }
	
	if { ([ACCESS::session data get "session.server.landinguri"] starts_with "/uri1")
		&& ([llength $apm_cookie_list] >= 1)}{
  	set _sessionid[ACCESS::session data get -sid [lindex $apm_cookie_list 0] session.user.sessionid]
  	log local0. "Found sesion $_sessionid"
  	ACCESS::session remove -sid $_sessionid
  	log local0. "[PROFILE::access name].$radius_username => session number $_sessionid terminated"	
  }
}

Does anyone have an idea how to get this to work?

4 Replies

  • I have decided to stick with the original idea, after finding out that it is possible to manipulate the UUID. That was the missing piece of the puzzle.

    Two variables are assigned in the policy:

    1. After login step 1 (Radius username + OTP), custom variable otp_username is set with Custom expression expr { "[mcget {session.logon.last.username}]" }
    2. At the end of the policy, the UUID is set with Predefined variables -> Group Per-Session variable -> Variable UIID, Custom expression expr { "OTP.[mcget {otp_username}]"}

    The end result:

    when ACCESS_POLICY_COMPLETED {
        if { [ACCESS::session data get "session.server.landinguri"] starts_with "/otp" }{
        	set radius_username [ACCESS::session data get otp_username]
           	set apm_cookie_list [ACCESS::uuid getsid "OTP.$radius_username"]
        	    for {set i 0} {$i < [llength $apm_cookie_list]} {incr i} {
                    log local0. "uuid [ lindex $apm_cookie_list $i] is listed for Radius user $radius_username during session [ACCESS::session data get session.user.sessionid]"
            	}
        	    log local0. "Length of cookie list for Radius user $radius_username is now [llength $apm_cookie_list]"
        }
    	
    	if { ([ACCESS::session data get "session.server.landinguri"] starts_with "/otp") && ([llength $apm_cookie_list] >= 2)}{
        	set session_term [ACCESS::session data get -sid [lindex $apm_cookie_list 0] session.user.sessionid]
        	    log local0. "Selected session $session_term for radius user $radius_username for termination"
        	ACCESS::session remove -sid [lindex $apm_cookie_list 0]
        	    log local0. "session number $session_term terminated for Radius user $radius_username"	
        }
    }
  • This is real complex and I may not be able to help but after the first authentication and saving the seesion variable otp_username and after the second authentication has passed did you try to change/rewrite session.logon.last.username with the value of variable otp_username with a variable assign agent? In a way to make session.logon.last.username after the second authentication to be the same like in the first authentication so the UUID to match what you want.

     

     

     

    if this breaks something you can also try to use the ACCESS_POLICY_AGENT_EVENT not ACCESS_POLICY_COMPLETED and placing this event right after you saved otp_username. The ACCESS_POLICY_COMPLETED is when the policy is done so it has session.logon.last.username set to the second authentication, so this seem the issue from what you have written.

     

     

    https://clouddocs.f5.com/api/irules/ACCESS_POLICY_AGENT_EVENT.html

     

     

    This are my all ideas, if someone knows something else please share it.

  • Have you considered to use the iRule table function? See: table (f5.com). Build a table that links username to ssid. If the table entry already exists, you can get the ssid and terminate that session. You can also extend the tables so you have a relation between ssid, otp_username and ad_username.

    • Dennis_Kloosterman's avatar
      Dennis_Kloosterman
      Icon for Altostratus rankAltostratus

      That looks like just what I have been looking for, thanks! I'll see if I can get it to work this way later this week.