on
20-Nov-2017
05:02
- edited on
05-Jun-2023
22:07
by
JimmyPackets
Problem this snippet solves:
APM variable assign is a powerful tool to manipulate APM variable during policy evaluation supporting tcl code.
On Devcentral answers, there are lots of variable assignment done with irule event ACCESS_POLICY_AGENT_EVENT.
these snippets show how to do the same as irule without irule event.
Note : I wrote most of codes, some others are from threads I found in DevCentral Answers section.
How to use this snippet:
create a variable assign box in VPE, then Add new entry
In left side,
In expression :
session.logon.last.username
extract CN from certificate subject and set it in username variable
set subject [split [mcget {session.ssl.cert.subject}] ",="]; foreach {name value} $subject { if {[string trim $name] equals "CN"} { return [string trim $value]; } }
session.logon.last.username
combine username and domain variables
expr { "[mcget {session.logon.last.domain}]\\[mcget {session.logon.last.username}]" }
session.logon.last.ntdomain
extract NT domain name from logon name
if { [mcget {session.logon.last.username}] contains "\\" } { set username [string tolower [mcget {session.logon.last.logonname}]]; return [string range $username 0 [expr {[string first "\\" $username] -1}] ]; } else { return {} }
one-line code
expr {[set username [string tolower [mcget {session.logon.last.logonname}]]] contains "\\" ? [string range $username 0 [expr {[string first "\\" $username] -1}] ] : "" }
session.logon.last.domain
static assignment from ntdomain
switch [string tolower [mcget {session.logon.last.ntdomain}]] { "domain1" { return "domain1.local" } "domain2" { return "domain2.local" } default { return "default.local" } }
session.logon.last.username
Extract username name from logonname (full username from logon page even if split domain from username is checked)
set username [string trim [mcget {session.logon.last.logonname}]]; if { $username contains "\\" } { return [string range $username [expr {[string first "\\" $username] +1}] end ]; } else { return $username }
session.logon.last.upn
Extract UPN value from Certificate X509Extension
set extension [string tolower [mcget {session.ssl.cert.x509extension}]]; return [string range $extension [expr {[string first "othername:upn<" $extension] +14}] [expr {[string last ">" $extension] -1}] ];
session.inactivity_timeout
Change inactivity session timeout based on a checkbox on the logon page (logon variable trusted)
if { [mcget {session.logon.last.trusted}] == 1 } { return {5400} } else { return {1800} }
one-line code (5400 seconds if condition before ? success, 1800 seconds else)
expr { [mcget {session.logon.last.trusted}] == 1 ? {5400} : {1800}}
session.inactivity_timeout
Change inactivity session timeout based on client type (iOS, Android and WindowsPhone : half of inactivity timeout configured in profile parameters)
expr { [mcget {session.client.platform}] == "WindowsPhone" || [mcget {session.client.platform}] == "Android" || [mcget {session.client.platform}] == "iOS" ? [mcget {session.inactivity_timeout}]/2 : [mcget {session.inactivity_timeout}] }
session.max_session_timeout
force to close the session à 17:00
expr { [clock scan "17:00"] - [mcget {session.user.starttime}] }
session.max_session_timeout
After a AD query which retreive attribute logonHours, force to close the session when user at the end of allowed logon hours
set maximumSessionSeconds 604800 if {[set logonHours [mcget {session.ad.last.attr.logonHours}]] != "" && $logonHours != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"} { #convert string to binary string binary scan [binary format H* $logonHours] b* logon_hours_binary_string # evaluate the number of seconds from last sunday set time_from_sunday [expr {[clock seconds] - [clock scan "last sunday"]}]; # search in string next hours with 0 value set current_index [expr {$time_from_sunday / 3600}]; # convert the index to number of seconds from last sunday if {[set next_denied_index [string first 0 $logon_hours_binary_string$logon_hours_binary_string $current_index]] == $current_index } {return 0} # evaluate number on seconds to disconnect time return [expr { $next_denied_index*3600 - $time_from_sunday}] } else { return $maximumSessionSeconds}
session.windows_info_os.last.fqdn
search and return FQDN hostname in computer names list after windows Info Box
foreach x [split [mcget {session.windows_info_os.last.computer}] "|"] { if { $x ends_with ".f5demo.lab" } { return $x } }
session.windows_info_os.last.computer_name
search FQDN hostname in computer names list after windows Info Box, then return shortname (without domain name)
foreach x [split [mcget {session.windows_info_os.last.computer}] "|"] { if { $x ends_with ".f5demo.lab" } { return [lindex [split $x "."] 0] } }
To allow machine certificate revocation validation, add a variable assign with 2 following variables before OCSP or CRLDP boxes.
session.ssl.cert.whole
store machine certificate as it was user certificate
expr {[mcget {session.check_machinecert.last.cert.cert}]}
session.ssl.cert.certissuer
store machine certificate issuer as it was user certificate issuer
expr {[mcget {session.check_machinecert.last.cert.issuer}]}
session.custom.http_auth_mycookie
extract from HTTP auth cookie list the cookie value of mycookie
expr { [lindex [regexp -inline {mycookie=([^;\\\r]*)} [mcget session.http.last.response_cookie]] 1] }
Webtop can be:
Full Webtop : display all assigned ressources in one page hosted on the F5.
Some customers want to assign different webtop based on assigned ressources.
one portal ressource only -> portal webtop
In Advanced ressource assign, the last assigned webtop is applied to the session. If the user is assigned non portal ressource (ex : RDP) and portal webtop, he will not be allowed to connect.
session.assigned.webtop
this code code is used if portal or network access webtop are assigned and number of resources is supported only with full webtop
set fullwt /Common/wt-Full; set wt [mcget {session.assigned.webtop}]; set pa [llength [mcget {session.assigned.resources.pa}]]; set at [llength [mcget {session.assigned.resources.at}]]; set na [llength [mcget {session.assigned.resources.na}]]; set rd [llength [mcget {session.assigned.resources.rd}]]; set saml [llength [mcget {session.assigned.resources.saml}]]; if {$rd || $at || $saml || ([expr { $pa + $na }] > 1)} {set wt $fullwt}; unset fullwt; unset pa; unset at; unset na; unset rd; unset saml; return $wt;
one-line code. Don't forget to replace "/Common/wt-Full" with your own webtop full in expression.
expr { [llength [concat [mcget {session.assigned.resources.rd}] [mcget {session.assigned.resources.at}] [mcget {session.assigned.resources.atsaml}]]] || [llength [concat [mcget {session.assigned.resources.pa}] [mcget {session.assigned.resources.na}]]] >1 ? "/Common/wt-Full" : [mcget {session.assigned.webtop}]}
Same condition for Advanced resource Assign condition. This condition doesn't match with previous rules in the same Advanced resource assign. must be in a dedicated resource assign box.
expr { [llength [concat [mcget {session.assigned.resources.rd}] [mcget {session.assigned.resources.at}] [mcget {session.assigned.resources.atsaml}]]] || [llength [concat [mcget {session.assigned.resources.pa}] [mcget {session.assigned.resources.na}]]] >1}
when working with Kerberos SSO, 2 variable sources must be set:
domain : must be equal to user FQDN domain
When working on access policy with multiple SSO method depending on the URI, Host header or some other parameters, you may have conflict on default SSO variables.
For example, for Exchange :
activesync SSO profile is basic with username format is NTDOMAIN\username
Autodiscover SSP profile can be NTLM with
OWA SSO profile can be kerberos with
default SSO variables are :
session.sso.token.last.username
to support multiple SSO on the same Access policy, I recommende to set new variables based on previous AD Query
session.krbsso.username
expr {[mcget {session.ad.last.attr.sAMAccountName}]}
session.krbsso.domain
expr {[mcget {session.ad.last.actualdomain}]}
Code :
No code
Hi,
Very useful article. I am just not sure what is proper syntax when entering such code into Variable Assign for example.
I assume that it can be entered multi line - much easier to debug than when all entered in one long line.
But what are rules when entered multi line, when ; should be used at the end of line?
I wonder as well if commands like virtual, class can be used here - I doubt but maybe I missed something when testing.
Piotr
In some versions, when entered multi line it works fine but if we edit it later, the code is merge on one line.
; is a character which means that next words are not parameters of current command but a new command.
It doesn’t change behavior in multi lines code but prevent issues.
In variable assign, only native tcl commands are allowed. For example, getfield is not allowed.
Virtual command doesn’t make sense during policy evaluation which is out of request flow but in HTTP_REQUEST OR ACCESS_ACL_ALLOWED events
Hi,
Thanks for info. I am trying to create branch expresion to change flow based on Host in request. Tried to use such code:
expr { [mcget {session.server.network.name}] == "form-ntlm.mbank.org" }
but it fails, always fallback branch is used. Using Message Box before Branch test I can see correct value in this var. If I use iRule to assign host header value to some custom session var and then perform the same expression selection is working correctly.
Is session.server.network.name some special kind of session var that can't be used for branch test?
Piotr
@Piotr : I use this expression for several customers and for my lab successfully!
are you sure this is the exact string (no special character or encoded character, uppercase / lowercase mismatch, ...)
Hi,
This is a very good topic but I am not very good in iRule...
I have a use case exemple : The user is accessing the web site protected with APM, using http://myserver.com?myparam=mycontent Once the user pass the authentication agent in APM, I need to insert "mycontent" into an APM session variable.
What is the iRule to extract the parameter content and put it in an apm session variable ?
Thank you
you can try this variable assign expression (this is not an irule but an expression you must set in variable assign box):
expr {[set id [lsearch [set params [split [lindex [split [mcget {session.server.landinguri}] ?] 1] "&="]] myparam ]] == -1 ? "" : [lindex $params $id+1]}
Hi Stanislas,
I have found your solution of variable assign to terminate APM session on particular time.
set endhour 22; set endmin 18; set starthour [clock format [mcget {session.user.starttime}] -format %H]; set startmin [clock format [mcget {session.user.starttime}] -format %M]; return [expr {( $endhour * 3600 ) + ( $endmin * 60 ) - ( $starthour * 3600 ) - ( $startmin * 60 )}]
Can we add date and month as well along with time in this format ? E.G. i want to terminate APM session on March 10, 2018 at 17:00. Can you please advise if this is possible and what will be the syntax?
This expression is the old one.
this code is optimized :
expr { [clock scan "17:00"] - [mcget {session.user.starttime}] }
and to add date information, you can use this
expr { [clock scan "2018-03-10T17:00"] - [mcget {session.user.starttime}] }
Stanislas,
I want to set the username to the CN in the session.ssl.cert.subject, BUT I just want a specific part of the CN, not the whole thing. my CN's look like this:
CN=LAST.FIRST.MIDDLE.1122334455
I just want the "LAST.FIRST" to be set to the session.logon.last.username
Additionally the entire cert subject has this format: (the "X" does not represent exact character count)
C=US, O=XXXX, OU=XXXX, OU=XXXX, OU=XXXX, CN=LAST.FIRST.MIDDLE.1122334455
Can you help?
Joe
@Joe Lupo, try this code:
set subject [split [mcget {session.ssl.cert.subject}] ",="];
foreach {name value} $subject {
if {[string trim $name] eq "CN"} {
return [join [lrange [split [string trim $value] "."] 0 1] "."];
}
}
the CN is split to a list with dot as separator (
split text "."
)... then the first 2 words (lrange list 0 1
) are converted to string with dot between list items (join list "."
) ...
if there is no dot in CN, the whole string will be returned.
@Stanislas
That appears to have worked. Thank you very much. I'll keep an eye on it, but our CN's should always have the format as mentioned above, so there should always be "." in the CN.
what would be the expression to check if the IP belongs to a specific subnet ? thx in advance
That does not work:
set current_ip [mcget session.user.clientip}] ;
if { $current_ip equals "172.20.0.0/16" } then {
return 1 ;
} else {
return 0 ;
} ;
@steph,
Try this expression
expr { [IP::addr [mcget {session.user.clientip}] equals "172.20.0.0/16"] }
The expr command returns 1 if expression is true, 0 if expression is false.
Stanislas,
Thanks for you fast response. What you explained is the way it is done today. I need this it to extend or reduce the session's timeouts.
The issue is, after the test, beside the timeouts, which are tested in a macro, I need to have the complete autorisation workflow twice, one per branch. Now, I need to add a workflow, which will complicate my policy.
I was hoping to do it in a 'variable assign' to avoid multiple branches. Any idea how to do that with only one branch out ?
If you want to change timeout based on this condition, create a variable assign for variable
session.inactivity_timeout
expr { [IP::addr [mcget {session.user.clientip}] equals "172.20.0.0/16"] ? {3600} : {900} }
when I have 2 domains Ad which would be the most effective assignment since in the domain decision box goes through the fallback
@Stansislas,
Sorry for the late reply, I did solve it like that (not the most effective way but it works):
{session.custom.internaldevice = set current_ip [mcget {session.user.clientip}] ; if { $current_ip starts_with "10.10.10.10" } then { return 2 ; Specific is 2 } elseif {$current_ip starts_with "10.10." } then { return 1 ; INTERNAL is 1 } else { return 0 ; EXTERNAL is 0 };
I need to put the result in a variable, since I need it in a pre-request policy as well.
Thanks for your feedback
I was wondering if it is away to have VMware View client when is configured via the APM to read only logon.last.logonname. When you authenticate using the view client, you get two windows one for (Radius) and the second one for (Active Directory); the issue is that when you get the AD window, the username is not in realy mode and you can change the username. Does anyone knows how to get custom variable to force it to read only? I am not talking about the Webtop... this is only with Horizon Client View...