Reverse Proxy With Basic SSO
Problem this snippet solves:
The iRule implements a authenticated HTTPS reverse proxy.
This iRule respond to a possible use of BigIP as an authenticated HTTPS reverse proxy. At this point, the iRule rewrite Host and Location in HTTP::header, support virtual multihosting and basic single sign-on.
First, declare two classes for rewrite HTTP::header Host and HTTP::header Location
How to use this snippet:
Supporting Classes
class tab_hostrewrite extern {
type string filename "tab_hostrewrite.txt"
}
class tab_locationrewrite extern {
type string filename "tab_locationrewrite.txt"
}
- The 'extern' keyword is not required in 9.4.x versions when creating the class from the CLI.
- For "Host" rewriting, the file format is specific to our use (no DNS use), example: "host1.mydomain.com ws1.inet.mydomain.com 192.168.1.14 80", "host2.mydomain.com ws2.inet.mydomain.com 192.168.1.11 80",
- For "Location" rewriting, an example is: "ws2.inet.mydomain.com https://host2.mydomain.com",
Code :
# rule ReverseProxy
###########################################################################
## IRule Reverse Proxy (c)05 F.NOEL - No warranty, feel free to use
## v0.01: F.NOEL - create irules with basic Host and Location rewrite
## 0.02: F.NOEL - add Single Sign ON (need to set :SSO to 1 in RULE_INIT)
## 0.03: F.NOEL - build cookie domain based on HTTP Header "Host"
## - if "Host" not FQDN, cookie's domain set to ::COOKIE_DEFAULT_DOMAIN
## 0.04: F.NOEL - add SSO cookie encryption (AES)
##
###########################################################################
when RULE_INIT {
set ::DEBUG 0
set ::RP_PRIVIP "192.168.1.254"
set ::SSO 1
set ::COOKIE_DEFAULT_DOMAIN ".mydomain.com"
set ::COOKIE_NAME "WSSOMYDOMAIN"
set ::COOKIE_ENCRYPT 1
set ::AES_KEY [AES::key 256]
if { $::DEBUG } { log local0.debug "Initialyze random AES_KEY='$::AES_KEY' " }
}
when HTTP_REQUEST {
set header_auth ""
set header_host [HTTP::host]
set hostrewrite [findclass $header_host $::tab_hostrewrite " "]
if { $hostrewrite ne "" } {
set destnodeaddr [getfield $hostrewrite " " 2]
set destnodeport [getfield $hostrewrite " " 3]
set hostrewrite [getfield $hostrewrite " " 1]
HTTP::header replace "Host" $hostrewrite
if { $::DEBUG } {
log local0.debug "Header Host '$header_host' found -> rewrite with '$hostrewrite'"
}
snat $::RP_PRIVIP
node $destnodeaddr $destnodeport
}
else {
if { $::DEBUG } { log local0.debug "$header_host not found -> respond with 403..." }
HTTP::respond 403 content "HTTP Error 403 - Forbidden"
}
if { $::SSO } {
set header_auth [HTTP::header "Authorization"]
if { $::DEBUG } { log local0.debug "REQ header_auth -> '$header_auth'" }
if { [HTTP::cookie exists $::COOKIE_NAME] } {
set SSO_DO_SET_COOKIE 0
HTTP::cookie remove $::COOKIE_NAME
if { $::DEBUG } {
log local0.debug "REQ cookie_sso exist -> set SSO_DO_SET_COOKIE=0 and remove cookie"
}
}
else {
if { $header_auth ne "" } {
set SSO_DO_SET_COOKIE 1
if { $::DEBUG } { log local0.debug "REQ cookie_sso not exist -> set SSO_DO_SET_COOKIE=1" }
}
}
}
}
when HTTP_RESPONSE {
### SSO_DO_SET_COOKIE flag on, set a cookie for support Single Sign ON
if { $::SSO and $SSO_DO_SET_COOKIE } {
## extract domain name from host to set cookie domain
set cookiedomain $::COOKIE_DEFAULT_DOMAIN
for {set i 6} {$i > 1} {incr i -1} {
set tmp [getfield $header_host "." $i]
## if Host is FQDN
if { $tmp ne "" and $i > 2 } {
set cookiedomain $tmp
incr i -1
set cookiedomain ".[getfield $header_host "." $i].$cookiedomain"
break;
}
}
if { $::DEBUG } { log local0.debug "cookiedomain= '$cookiedomain' " }
if { $::COOKIE_ENCRYPT } {
set cookie_payload [b64encode [AES::encrypt $::AES_KEY $header_auth]]
}
else {
set cookie_payload $header_auth
}
if { $::DEBUG } { log local0.debug "cookie_payload= '$cookie_payload' " }
HTTP::cookie insert name $::COOKIE_NAME value $cookie_payload
HTTP::cookie domain $::COOKIE_NAME $cookiedomain
HTTP::cookie path $::COOKIE_NAME "/"
set SSO_DO_SET_COOKIE 0
if { $::DEBUG } {
log local0.debug "SSO_DO_SET_COOKIE=1 -> insert cookie $::COOKIE_NAME='$cookie_payload' in response..."
}
}
if { [HTTP::status] starts_with "3" } {
set location [HTTP::header "Location"]
if { $location ne "" } {
if { $::DEBUG } { log local0.debug "Header Location '$location' not null -> checking..." }
set loc_start ""
if { $location starts_with "http://" } { set loc_start "http://" }
elseif { $location starts_with "https://" } { set loc_start "https://" }
set loc_start_len [string length $loc_start]
if { $loc_start_len eq 0 } {
if { $::DEBUG } { log local0.debug "No absolute redirection! return... " }
return
}
set loc_end [substr $location $loc_start_len]
set loc_to_search [getfield $loc_end "/" 1]
set locationrewrite [findclass $loc_to_search $::tab_locationrewrite " "]
if { $locationrewrite ne "" } {
set loc_to_search_len [string length $loc_to_search]
set loc_end [substr $loc_end $loc_to_search_len]
set new_loc "$locationrewrite$loc_end"
HTTP::header replace "Location" $new_loc
if { $::DEBUG } { log local0.debug "Rewrite Location -> $new_loc" }
}
else {
if { $::DEBUG } { log local0.debug "Location not found in tab_locationrewrite -> return..." }
}
return
}
}
else
{ return }
}
# Finally, if you want activate the support for basic single sign-on with a ldap authentication, add rule SSO_Auth_Ldap on your authentication profile
# rule SSO_Auth_Ldap
###########################################################################
## IRule Reverse Proxy - AuthLdap (c)05 F.NOEL - No warranty, feel free to use
## v0.01: create irule for support Single Sign ON with LDAP authentication
##
###########################################################################
when CLIENT_ACCEPTED {
set tmm_auth_ldap_sid [AUTH::start pam default_ldap]
}
when HTTP_REQUEST {
if { [HTTP::cookie exists $::COOKIE_NAME] } {
set cookie_payload [HTTP::cookie value $::COOKIE_NAME]
if { $::COOKIE_ENCRYPT } {
set cookie_payload [AES::decrypt $::AES_KEY [b64decode $cookie_payload]]
}
if { $::DEBUG } { log local0.debug "cookie $::COOKIE_NAME exist -> set Authorization credential" }
HTTP::header replace "Authorization" $cookie_payload
}
else
{
if { $::DEBUG } { log local0.debug "cookie $::COOKIE_NAME doesn't exist -> authenticate user" }
AUTH::username_credential $tmm_auth_ldap_sid [HTTP::username]
AUTH::password_credential $tmm_auth_ldap_sid [HTTP::password]
AUTH::authenticate $tmm_auth_ldap_sid
HTTP::collect
}
}
when AUTH_SUCCESS {
if {$tmm_auth_ldap_sid eq [AUTH::last_event_session_id]} {
HTTP::release
}
}
when AUTH_FAILURE {
if {$tmm_auth_ldap_sid eq [AUTH::last_event_session_id]} {
HTTP::respond 401
}
}
when AUTH_WANTCREDENTIAL {
if {$tmm_auth_ldap_sid eq [AUTH::last_event_session_id]} {
HTTP::respond 401
}
}
when AUTH_ERROR {
if {$tmm_auth_ldap_sid eq [AUTH::last_event_session_id]} {
HTTP::respond 401
}
}Published Mar 18, 2015
Version 1.0CodeCentral_194
Cirrostratus
Joined May 05, 2019
CodeCentral_194
Cirrostratus
Joined May 05, 2019
No CommentsBe the first to comment