Forum Discussion
SAML SLO request ignored on iRules
Hello all,
the F5 still doesn't pass the relay state on single logout (see https://devcentral.f5.com/questions/saml-logout-relaystate), I've tried to go around using an iRule (store the RelayState in a session and inject the value into the response POST form). IMHO the idea is good, but there's a little problem.
The HTTP_REQUEST event is NOT invoked on SLO (single logout POST to "/saml/idp/profile/post/sls"). I assume other events are skipped too..
Is there another way to handle/enable the events? Using BIG-IP 11.4.1 Build 635.0 Hotfix HF2
Best regards Gabriel
irule to fix SLO bug (not adding RelayState to the response)
when HTTP_REQUEST {
set uri [HTTP::uri]
set method [HTTP::method]
log local0. "aether req: $method $uri"
check if SLO request is invoked
if so, collect the posted content to process
if {$method equals "POST" and $uri equals "/saml/idp/profile/post/sls"} {
if { [HTTP::header Content-Length] ne "" and [HTTP::header value Content-Length] <= 1048576 } {
set content_length [HTTP::header value Content-Length]
} else {
set content_length 1048576
}
if { $content_length > 0 } {
HTTP::collect $content_length
}
}
}
at the SLO request, find the RelayState and store into the session
when HTTP_REQUEST_DATA {
Do stuff with the payload
set uri [HTTP::uri]
set method [HTTP::method]
if {$method equals "POST" and $uri equals "/saml/idp/profile/post/sls"} {
set payload [HTTP::payload]
set relaystate ""
foreach x [split [ string tolower $payload] "&"] {
if { $x starts_with "relaystate=" } {
set relaystate [lindex [split $x "="] 1]
}
}
log local0. $relaystate
session add uie relaystate $relaystate
log local0. "SAML SLO fix: stored relaystate [session lookup uie relaystate]"
}
}
if relaystate is stored (we assume SLO in progress)
we will inject the realystate into the response
when HTTP_RESPONSE {
set relaystate [session lookup uie relaystate]
if {$relaystate ne ""} {
set clen [HTTP::header Content-Length]
log local0. "SAML SLO fix: stored relaystate $relaystate , injecting into the response"
set payload [HTTP::payload]
regsub -all { } $payload" " " newpayload
log local0. "new payload: $newpayload"
session delete uie relaystate
HTTP::payload replace 0 $clen $newpayload
HTTP::release
}
}
You can define a layered VS that apply your irule :
-
Change the IP address of your current VS (for example: 1.1.1.1) and remove your irule
-
Create a new VS (with published IP) and add your irule.
-
just add
to the end of the HTTP_REQUEST event of your irule (where Internal_VS is your VS with IP 1.1.1.1)virtual /Common/Internal_VS
Thus, you will be able to manipulate REQUEST and RESPONSE (HTTP_RESPONSE) without any issues.
-
Hello,
Can you retry by adding the following line of codes on your irule :
when CLIENT_ACCEPTED { ACCESS::restrict_irule_events disable }
This peace of irule will allow you to manage with internal APM URIs.
Moreover, if you would be able to handle response coming from APM, you should change the HTTP_RESPONSE event by HTTP_RESPONSE_RELEASE.
- Hello, you were right * command "ACCESS::restrict_irule_events disable" enabled most of the events * /saml/idp/profile/post/sls fires only the HTTP_RESPONSE_RELEASE event problem stays, that in the HTTP_RESPONSE_RELEASE event we have no means (or do we?) manipulate the response. Only thing I've managed was to inject data BEFORE the response ( HTTP::payload 0 0 ".....") however trying to change anything INSIDE failed (or I just don't know how to do that). Mostly I got an APM error in access_sanitize_portal_headers.c (Line: 11767) :( Apparently - modifying response would work having the HTTP_RESPONSE event too, where we could call HTTP::collect to fill the payload.. but HTTP_RESPONSE is not called. Any hint around that? Best regards Gabriel
- Yann_Desmarest_Nacreous
Hello,
Can you retry by adding the following line of codes on your irule :
when CLIENT_ACCEPTED { ACCESS::restrict_irule_events disable }
This peace of irule will allow you to manage with internal APM URIs.
Moreover, if you would be able to handle response coming from APM, you should change the HTTP_RESPONSE event by HTTP_RESPONSE_RELEASE.
- Hello, you were right * command "ACCESS::restrict_irule_events disable" enabled most of the events * /saml/idp/profile/post/sls fires only the HTTP_RESPONSE_RELEASE event problem stays, that in the HTTP_RESPONSE_RELEASE event we have no means (or do we?) manipulate the response. Only thing I've managed was to inject data BEFORE the response ( HTTP::payload 0 0 ".....") however trying to change anything INSIDE failed (or I just don't know how to do that). Mostly I got an APM error in access_sanitize_portal_headers.c (Line: 11767) :( Apparently - modifying response would work having the HTTP_RESPONSE event too, where we could call HTTP::collect to fill the payload.. but HTTP_RESPONSE is not called. Any hint around that? Best regards Gabriel
You can define a layered VS that apply your irule :
-
Change the IP address of your current VS (for example: 1.1.1.1) and remove your irule
-
Create a new VS (with published IP) and add your irule.
-
just add
to the end of the HTTP_REQUEST event of your irule (where Internal_VS is your VS with IP 1.1.1.1)virtual /Common/Internal_VS
Thus, you will be able to manipulate REQUEST and RESPONSE (HTTP_RESPONSE) without any issues.
- Thank you Yann, that actually solved the problem.. Carpe diem g.
-
- Yann_Desmarest_Nacreous
You can define a layered VS that apply your irule :
-
Change the IP address of your current VS (for example: 1.1.1.1) and remove your irule
-
Create a new VS (with published IP) and add your irule.
-
just add
to the end of the HTTP_REQUEST event of your irule (where Internal_VS is your VS with IP 1.1.1.1)virtual /Common/Internal_VS
Thus, you will be able to manipulate REQUEST and RESPONSE (HTTP_RESPONSE) without any issues.
- Thank you Yann, that actually solved the problem.. Carpe diem g.
-
posting a complete solution
rule saml-inject rule
irule to store the relay state at the logout (or predefined link) and inject the relay state to the reply this irule is to be applied to a front layer VS thus intercepting all HTTP events when RULE_INIT { set static::virtual_SAML_server /Common/auth-test-vs } when HTTP_REQUEST { log local0. "[HTTP::host] [HTTP::method] [HTTP::uri]" set uri [HTTP::uri] set method [HTTP::method] if {$method equals "POST" and $uri equals "/saml/idp/profile/post/sls"} { if { [HTTP::header Content-Length] ne "" and [HTTP::header value Content-Length] <= 1048576 } { set content_length [HTTP::header value Content-Length] } else { set content_length 1048576 } if { $content_length > 0 } { HTTP::collect $content_length log local0. "request content collected: $content_length" } else { log local0. "cannot collect the content, length: $content_length" } } else { unset uri unset method } virtual $static::virtual_SAML_server } at the SLO request, find the RelayState and store into the session triggered by HTTP::collect when HTTP_REQUEST_DATA { if { [info exists "uri"] and [info exists "method"] } { if {$method equals "POST" and $uri equals "/saml/idp/profile/post/sls"} { set payload [HTTP::payload] set relaystate "" foreach x [split [ string tolower $payload] "&"] { if { $x starts_with "relaystate=" } { set relaystate [lindex [split $x "="] 1] } } log local0. "found relaystate: $relaystate" unset payload HTTP::release } } } when HTTP_RESPONSE { log local0. "response" if { [info exists "uri"] and [info exists "method"] } { if {$method equals "POST" and $uri equals "/saml/idp/profile/post/sls"} { if { [HTTP::header Content-Length] ne "" and [HTTP::header value Content-Length] <= 1048576 } { set content_length [HTTP::header value Content-Length] } else { set content_length 1048576 } if { $content_length > 0 } { HTTP::collect $content_length log local0. "response content collected: $content_length" } else { log local0. "cannot collect the content, length: $content_length" } } } } when HTTP_RESPONSE_DATA { log local0. "response data" if { [info exists "uri"] and [info exists "method"] } { if {$method equals "POST" and $uri equals "/saml/idp/profile/post/sls"} { set payload [HTTP::payload] set index [string first " 0 } { HTTP::payload replace $index 0 "" } unset payload unset index unset content_length unset relaystate } } } when HTTP_RESPONSE_RELEASE { log local0. "response release" HTTP::release }
- This workaround works only with a single SP. With multiple SPs it will be more complex.
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com