Per Partner SSO Error Pages in PingFederate

| | Comments (2) | TrackBacks (0)
At the moment, I spend most of my time setting up federation connections for big banks. These financial institutions are super concerned about their image and brand, as any large organization is. One thing that they all worry about is what happens when an error occurs while a user is SSOing from them to their service provider (SP). It's not good enough that the SP brands their service with custom URLs to make it look like they are in the bank's domain. That's a given. If an error page is shown, it must be branded w/ their graphics, logos, colors, and text. Regardless of the minuscule chance of such an error occurring, the image of the bank must not be tarnished if it actually does.

To be specific, these are the cases I'm talking about:
  • The XML of the SAML message is malformed or invalid.
  • The digital signature on the SAML message or assertion is invalid.
  • The digital signature is missing.
  • The assertion or SAML message is expired.
  • The assertion has been submitted before.
  • The assertion can't be decrypted.
  • The audience restriction of the assertion is missing or incorrect.
  • The assertion is a holder-of-key (HoK) rather than bearer type.
To complicate things, some banks want to know exactly what went wrong. They want a different error code for each of these conditions printed on the page together with their toll-free support number. Others just want a generic SSO error code. Even more challenging, some banks want the user redirected back to their Web site while others are OK with the user being left on the SP's server (as long as the page is branded). The requirements are all over the map, and it's very difficult for an SP to accommodate all of these needs. Coming up w/ a solutions for this that works for all partners is really, really hard. Here's the best I've been able to do using PingFederate for just the SAML IdP-initiated SSO scenario.

PingFederate uses the Apache Velocity templating framework to render HTML pages, including those displayed when SSO errors occur. It also allows you to provide information that should be displayed when errors happen during SSO (both IdP- and SP-initiated though I'm only talking about the former). This info can be configured on a per federation connection basis. As shown in the following screenshot, it is usually just text.


The trick though is to use text and HTML, and to alter the Velocity template to output it as such.

The other trick is not really a trick; it's a dirty hack, but it's needed to meet the requirement that some IdPs have to display or pass back an error code indicating what exactly went wrong. (Please don't rail me for doing this if you're an enterprise architect.) To accomplish this, you have to parse the error message that is made available to you in the Velocity template. Based on that, you can set a variable and use it in the HTML configured for a connection. Specifically, you need to change the template named which is located in $PINGFEDERATE_HOME/server/default/config/template. It needs to be something like this:

#set($m = $escape.escape($exception.getMessage()))

#if ($m.startsWith("Missing or invalid signature (INVALID") || $m == "Invalid signature")
    #set($errorCode = 0)
#elseif ($m.startsWith("Missing or invalid signature (NOT_PRESENT"))
    #set($errorCode = 1)
#elseif ($m.matches("(?sm).*Assertion with ID of.*has previously been processed.*"))
    #set($errorCode = 2)
#elseif ($m.matches("(?sm).*Time condition: now.*is on/after NotOnOrAfter.*"))
    #set($errorCode = 3)
#elseif ($m.matches("(?sm).*Assertion audience condition validation failed.*"))
    #set($errorCode = 4)
    #set($errorCode = -1)


Nasty, I know, but stay w/ me. What this is doing is looking through the error message passed from PingFederate to the Velocity template used for SSO errors that happen on the SP side. The variable $errorText contains whatever is in the error message text box shown in the screenshot above. So, rather than the default text, you need to use some HTML like this:


Notice how the variable $errorCode is used in the configured HTML. Federation partner with config like this are those wanting to display the error code on the SP's server. Others that don't want to show the error code would be configured with HTML that doesn't use the variable at all. To render the value of the variable that is set in the previously shown template code, the Velocity function, #evaluate, is called. Using #evaluate requires the Velocity JAR to be upgraded unless you're using PingFederate 6.3 or higher. (If you do upgrade, use the JAR that contains all its dependencies.) For other partners that want the end user to be redirect back to their server, the HTML could contain a meta refresh tag or JavaScript to ship them over. If desired, the error code could be provided as a query string argument.

Not that this won't catch errors where the SAML message is malformed or invalid. PingFederate doesn't make the configured error message available to the template that's used to render errors in that case (to the best of my knowledge). It also doesn't handle incorrect HoK assertion types. (I didn't think of that case till writing this post.)

So, what we have here is a really ugly solution to an archaic use case that will have your enterprise architect hopping mad. Oh, well, at least the bank's image will be as pristine as possible when problems arise.