Forum Discussion
Hi
This is clientless mode - https://support.f5.com/csp/article/K80934060#link_06 - if a client can't follow redirects for example then you can proxy the initial auth request and replay it all on the device.
If you need to do this in code then something like this might work....or at least provide a starting point. This will look at a HTTP Request and if an APM session doesn't exist (based on the MRHSession cookie value) then the code will either send the client a 401 asking for Basic auth details or, if the Basic Auth header is present it will store these as variables. Then, when the APM policy starts, these HTTP variables are stored as APM variables so that they can be used by APM Auth objects.
Hope this makes sense
when HTTP_REQUEST {
if { [HTTP::cookie exists "MRHSession"] } {
set apmstatus [ACCESS::session exists -state_allow [HTTP::cookie value MRHSession]]}
else {set apmstatus 0}
if { !($apmstatus)} {
if { [ string match -nocase {basic *} [HTTP::header Authorization] ] == 1 } {
set usr [ string tolower [HTTP::username] ]
set pass [HTTP::password]
} else {
HTTP::respond 401 noserver WWW-Authenticate "Basic realm=\"[HTTP::host] Authentication\"" Set-Cookie "MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/" Connection close
return
}
}
}
when ACCESS_SESSION_STARTED {
if { !($apmstatus)} {
ACCESS::session data set "session.logon.last.username" $usr
ACCESS::session data set "session.logon.last.password" $pass
ACCESS::session data set "session.logon.last.domain" "domain.local"
}
}
Hope this makes sense
Hi iaine, you're the best! 🙂
Not only does it make sense, it works straight away.
Your code is infinitely more elegant than mine, but I still do not understand why my session variable assignment did not work.
when HTTP_REQUEST {
if { [HTTP::header exists Authorization] } {
catch {
# credentials come base64 encoded in the Authorization header
set creds [b64decode [findstr [HTTP::header Authorization] "Basic " 6]]
# credentials will be in one of three formats
# - domain\user:password
# - user@domain:password format
# - user:password
if { $creds contains "\\" } {
set domain [findstr $creds "" 0 "\\"]
set usr [findstr $creds "\\" 1 ":"]
log local0. "CMPWBS iRule: Auth format: <domain>\\<user>:<password> - domain:$domain user:$usr"
} elseif { $creds contains "@" } {
set domain [findstr $creds "@" 1 ":"]
set usr [findstr $creds "" 0 "@"]
log local0. "CMPWBS iRule: Auth format: <user>@<domain>:<password> - domain:$domain user:$usr"
} elseif { $creds contains ":" } {
set domain ""
set usr [findstr $creds "" 0 ":"]
log local0. "CMPWBS iRule: Auth format: <user>:<password> - user:$usr"
} else {
log local0. "CMPWBS request coming in w/ wrong auth format"
return
}
set pass [findstr $creds ":" 1 "\r"]
}
} else {
HTTP::respond 401 WWW-Authenticate "Basic realm=\"CMP WBS\""
}
}
when ACCESS_POLICY_AGENT_EVENT {
if { [ACCESS::policy agent_id] eq "get_credentials_from_auth_header" } {
ACCESS::session data set session.logon.last.username $usr
ACCESS::session data set session.logon.last.password $pass
ACCESS::session data set session.logon.last.domain $domain
}
}
In the meantime I found out that
- the auth string is always in the format <user>:<password>
- HTTP::user and HTTP::password is far easier than manually extracting stuff with 'findstr'
- looking for an existing session is probably a good idea
However, the rough idea is not so different from yours and when I put in some 'log local0.' into the HTTP_REQUEST I saw that username and password extraction worked fine. Still, when assigning the variable content of $usr to session.logon.last.username etc. the variable did not exist, and this is the part I still do not fully understand.
I mean, the stuff works now and I do not want to unduly try your patience. 🙂
I would, however, really love to understand what the inner workings are here. I am pretty sure it has something to do with correlating the variables to the right session, something solved by the cookie. It's all very foggy to me, though.
Cheers
Dirk