authentication iRule
Below is an iRule which is a customized version of the standard _sys_radius_auth iRule. The purpose of the modification is to not have to make a RADIUS call for every object i.e. the result of the authentication request is stored for an hour to take load off the RADIUS servers.
Unfortunately, this rule is generating a lot of logging messages to the point of us experiencing I/O Swap thrash. The message is the following:
May 30 08:26:37 local/tmm2 err tmm2[6301]: 01220001:3: TCL error: [RULENAME_REDACTED] - can't read "tmm_auth_http_collect_count": no such variable (reading value of variable to increment) invoked from within "incr tmm_auth_http_collect_count -1"
Can anyone assist and diagnose why we are getting this message? The "incr tmm_auth_http_collect_count -1" statement happens within the AUTH_RESULT event. The message seems to indicate that tmm_auth_http_collect_count is never instantiated. The only way this could happen is if the else statement enveloping the "set tmm_auth_http_collect_count 1" doesnt execute. However, if the else statement doesnt execute, then there is no call to auth::authenticate which to me would mean that the AUTH_RESULT event wouldn't fire.
when HTTP_REQUEST {
Save the username and password for reference in the AUTH_event
set user [HTTP::username]
set pass [HTTP::password]
set pass_hash [b64encode [md5 $pass]]
set key "$user-[virtual]-[IP::remote_addr]"
set tbl "[virtual]-radius-auth"
if {not [info exists tmm_auth_http_sids(radius)]} {
set tmm_auth_sid [AUTH::start pam default_radius]
set tmm_auth_http_sids(radius) $tmm_auth_sid
if {[info exists tmm_auth_subscription]} {
AUTH::subscribe $tmm_auth_sid
}
} else {
set tmm_auth_sid $tmm_auth_http_sids(radius)
}
Check if username/password are already in the session table
if {($user ne "") && \
([session lookup uie $key] eq $pass_hash)}{
Auth was already successful on previous request
log "HTTP_REQUEST auth found in session table for $key"
} else {
log "HTTP_REQUEST auth not found in session table for $key"
AUTH::username_credential $tmm_auth_sid $user
AUTH::password_credential $tmm_auth_sid $pass
AUTH::authenticate $tmm_auth_sid
if {not [info exists tmm_auth_http_collect_count]} {
HTTP::collect
set tmm_auth_http_successes 0
set tmm_auth_http_collect_count 1
} else {
incr tmm_auth_http_collect_count
}
}
}
when AUTH_RESULT {
if {not [info exists tmm_auth_http_sids(radius)] or \
($tmm_auth_http_sids(radius) != [AUTH::last_event_session_id]) or \
(not [info exists tmm_auth_http_collect_count])} {
return
}
if {[AUTH::status] == 0} {
incr tmm_auth_http_successes
}
If multiple auth sessions are pending and
one failure results in termination and this is a failure
or enough successes have now occurred
if {([array size tmm_auth_http_sids] > 1) and \
((not [info exists tmm_auth_http_sufficient_successes] or \
($tmm_auth_http_successes >= $tmm_auth_http_sufficient_successes)))} {
Abort the other auth sessions
foreach {type sid} [array get tmm_auth_http_sids] {
unset tmm_auth_http_sids($type)
if {($type ne "radius") and ($sid != -1)} {
AUTH::abort $sid
incr tmm_auth_http_collect_count -1
}
}
}
If this is the last outstanding auth then either
release or respond to this session
incr tmm_auth_http_collect_count -1
if {$tmm_auth_http_collect_count == 0} {
unset tmm_auth_http_collect_count
if { [AUTH::status] == 0 } {
log "AUTH_RESULT addig to session table for $key"
Add the username and password to the session table for one hour
session add uie $key $pass_hash 600
add a session entry with a indefinite timeout, but with a 600sec lifetime (force the record at lifetime)
table add -subtable $tbl $key $pass_hash indefinite 60
HTTP::release
} else {
HTTP::respond 401
}
}
}