Ok, so the one technique that I used that proved very useful to narrow-down on the issue was to subclass and register my own Saml2SecurityTokenHandler
.
This helped me to verify that the problem was in the order of elements within SAML token - apparently WIF is inot very forgiving when it comes to location of Signature element within SAML assertion - it requires it to be immediately after Issuer element.
public class ForgivingSaml2SecurityTokenHandler : Saml2SecurityTokenHandler
{
public override SecurityToken ReadToken(XmlReader reader)
{
reader = SanitizeToken(reader);
return base.ReadToken(reader);
}
XmlReader SanitizeToken(XmlReader reader)
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
var ns = new XmlNamespaceManager(xmlDoc.NameTable);
ns.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
ns.AddNamespace("sa", "urn:oasis:names:tc:SAML:2.0:assertion");
var issuerNode = xmlDoc.SelectSingleNode("//sa:Issuer", ns);
var signatureNode = xmlDoc.SelectSingleNode("//ds:Signature", ns);
signatureNode.ParentNode.InsertAfter(signatureNode, issuerNode);
string sanitizedToken = xmlDoc.InnerXml;
return new XmlTextReader(new StringReader(sanitizedToken));
}
}
So the above would not really resolve the issue, as modifying the token caused the signature check to fail, but it allowed me to verify that the order was indeed the issue, as I was able to modify the correct token and make it fail the same way as problematic token was behaving - apparently the token structure checks are being performed before signature checks by WIF.
To register my subclassed token handler i used following registration in web.config file:
<identityConfiguration saveBootstrapContext="true">
<securityTokenHandlers>
<remove type="System.IdentityModel.Tokens.Saml2SecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<add type="ExploringSaml.ForgivingSaml2SecurityTokenHandler, ExploringSaml" ></add>
</securityTokenHandlers>