Forum Discussion
Post to external web page
This one was a little tricky, but I think I have something that'll work. The biggest issues were that 1) after the APM SP consumes the assertion, it redirects back to the originally requested URI, which is a GET request, 2) the only way to change a GET to a POST is to replace it in the TCP payload (HTTP::method is read-only), and 3) you cannot simply capture the TCP payload and replace the GET with a POST and add the payload, because APM still needs to be able to see the session cookie on ingress. Here's what I have:
when ACCESS_ACL_ALLOWED {
if { [ACCESS::session data get session.saml.last.sent] == "" } {
ACCESS::session data set session.saml.last.sent 1
ACCESS::respond 302 Location "[ACCESS::session data get session.server.landinguri]" "Set-Cookie" "SAMLASSERT=true; path=/; secure" "Connection" "Close"
}
}
when CLIENTSSL_HANDSHAKE {
SSL::collect
}
when CLIENTSSL_DATA {
if { [SSL::payload] contains "SAMLASSERT" } {
set mrhsession [findstr [SSL::payload] "MRHSession=" 11 ";"]
set assertion "SAMLResponse=[b64encode [ACCESS::session data get -sid $mrhsession session.saml.last.assertion]]"
regsub -all -nocase "GET" [SSL::payload] "POST" newdata
regsub -all -nocase "Cookie:" $newdata "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: [string length $assertion]\r\nCookie:" newdata1
SSL::payload replace 0 [SSL::payload length] "${newdata1}$assertion"
SSL::release
}
SSL::release
}
when HTTP_RESPONSE {
if { [info exists mrhsession] } {
unset mrhsession
HTTP::header insert "Set-Cookie" "SAMLASSERT=false; path=/; expires=Tuesday, 29-Mar-1970 00:15:00 GMT;"
}
}
Here's the idea:
-
The ACCESS_POLICY_COMPLETED event redirects the user back to the original URI. Once there, the ACCESS_ACL_ALLOWED event is triggered for each subsequent request. This event looks for a special session value, and if it doesn't exist (the first time through), sets it, and then generates a redirect to itself with a new cookie (SAMLASSERT). The added Connection: Close header guarantees that the next request will start a new TCP session.
-
Because this is presumably SSL data, I'm using the CLIENTSSL_HANDSHAKE and CLIENTSSL_DATA events instead of CLIENT_ACCEPTED and CLIENT_DATA to first capture the payload and then evaluate it for the cookie.
-
If the request contains the SAMLASSERT cookie, I grab the MRHSession cookie from the request and use that to fetch the SAML assertion data from the session table. I then change the GET to POST, add POST-specific headers (Content-Length and Content-Type), and then add the base64-encoded SAMLResponse payload, being careful not to touch the APM session token.
-
On first HTTP response after the GET/POST transformation, the mrhsession variable exists, so I delete that variable and the SAMLASSERT cookie to prevent a loop.
This generates a POST request to the original URI and inserts the SAMLReponse payload data. Because I'm forcing the client to return via redirect to start a new TCP session, I needed something that the client would relay, like a cookie or URI. I had originally chosen a URI trigger, but then switched to a cookie so that the client wouldn't see any of the magic. This POST request only happens once (at the first request), so the application needs to be able to consume the SAML payload and react accordingly.
This was also developed with APM as both IdP and SP, so your mileage may vary.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)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