Validating a SAML assertion in .NET
SAML is an XML based standard for authorization commonly used in web based, single sign-on applications. The other day at work, we had to build SAML support for one of our applications. We wasted a lot of time debugging the validation of the digital signature on the SAML response. I am documenting some of the issues we faced along the way so that it might be helpful for some other soul.
*[ Warning: I am a noob when it comes to SAML and I will not cover all the steps in validating a SAML assertion. I am documenting only the XMLDSig portion of the validation process. The rest of the steps are pretty straight forward. Just read the SAML documentation to find out more. ] *
A sample SAML assertion would look like this:
As you can see, we have a signature block which is used for validating the authenticity of the response. A signature block looks like this:
Validating the signature
As it turns out, the .net framework has built-in support for verifying XML signatures. It’s all done using a simple class called SignedXml. You can use the below code to verify the digital signature.
The code as such is very simple, but the problem with CheckSignature is that all it returns is a true or a false if it is not able to validate the signature. If it returns a false, you are screwed!
Some Gotchas
Here are some problems we ran into while validating our SAML response.
-
Adding or removing whitespaces – Like most people we also believed that adding whitespaces to the XML document (mainly for readability) will not affect it in anyway. After wasting hours, we learned our lesson : “Don’t mess with the document when you are dealing with signature - even if it is XML”.
-
Make sure the reference id parameter used by the signature is exactly
Id
. (You can read more about this in msdn )
As for the last part, our response had ResponseID
instead of Id
. Since the SAML response was generated by a third-party, we did not have any control over this. So we had to overload the GetIdElement method in SignedXml to look for elements with attribute ResponseID instead of Id.