Digest based Single-Sign-On
Updated Jun 06, 2023
Version 2.0Was this article helpful?
1/ The server nonce value might contain equal sign so the above code will chop it off in an unintended way.
2/ It would need a condition block in HTTP_REQUEST to identify if it is a request from HTTP::retry.
when RULE_INIT {
set static::user "testuser"
set static::password "testpass"
set static::client_nonce "389db6597243daf2"
set static::nonce_count "00000001"
}
when CLIENT_ACCEPTED {
set retried 0
}
when HTTP_REQUEST {
if { ${retried} == 0 } {
set vars required for Digest SSO
set uri [HTTP::uri]
set method [HTTP::method]
set retried 0
insert a dummy text. Help to inject Digest SSO
HTTP::header replace Authorization "irule-test-digest-sso"
set request [HTTP::request]
HTTP::header remove Authorization
}
}
when HTTP_RESPONSE {
if { [HTTP::status] contains "401" and [HTTP::header exists "WWW-Authenticate"] and [HTTP::header "WWW-Authenticate"] contains "Digest" and $retried == 0 } {
set www_auth [HTTP::header "WWW-Authenticate"]
basically chop the "realm=" and "nonce=" using strictly string functions
set realm [string range ${www_auth} [expr {[string first "realm=" ${www_auth}] + 7}] [expr {[string first "," ${www_auth} [string first "realm=" ${www_auth}]] - 2}]]
set nonce [string range ${www_auth} [expr {[string first "nonce=" ${www_auth}] + 7}] [expr {[string first "," ${www_auth} [string first "nonce=" ${www_auth}]] - 2}]]
retrieve username and password from wherever you want. Can be APM, Basic authentication, ...
binary scan [md5 "$static::user:$realm:$static::password"] H* ha1
binary scan [md5 "$method:$uri"] H* ha2
binary scan [md5 "$ha1:$nonce:$static::nonce_count:$static::client_nonce:auth:$ha2"] H* response
set retried 1
set auth_value "Digest username=\"$static::user\", realm=\"$realm\", nonce=\"$nonce\", uri=\"$uri\", algorithm=MD5, response=\"$response\", qop=auth, nc=$static::nonce_count, cnonce=\"$static::client_nonce\""
insert Authorization header with Digest
set updated_request [string map [list "irule-test-digest-sso" "$auth_value"] $request]
resend the request with the Authorization header filled
HTTP::retry $updated_request
} else {
set retried 0
}
}
Hopefully this would help someone working on this trick.