OIOSAML.net v1.76
Here are the changes required to get OIOSAML.Net v 1.7.6 (dk.nita.saml20) to work with a Shibboleth 2.x IDP.
Issues
In OIOSAML.net the output SP metadata data has this line.
<q1:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" AuthnRequestsSigned="true" WantAssertionsSigned="true">
Note theAuthnRequestSigned="true"which is hard coded to the true value in the source code but as it does not sign the AuthnRequest should be false. I changed the source code so it returns false but you may need to edit the metadata manually if you can't change the source code.Saml20MetadataDocument.cs
private void ConvertToMetadata(SAML20FederationConfig config, KeyInfo keyinfo) { // line 77 should read spDescriptor.AuthnRequestsSigned = XmlConvert.ToString(false); //changed to false as as code does not send signed AuthNRequestsUpdate 08/07/2014 After digging into this a little further it appears that OIOSAML.Net is sending the assertion signature in the querystring if it is a binding of type Redirect which is the default. When OIOSAML.net Starts the SAML Process with the Shibboleth IDP via its url http://sp.oiosaml.net/Saml/Login.ashx?cidp=https%3a%2f%2fidp.testshib.org%2fidp%2fshibboleth&ReturnUrl=http%3a%2f%2fsp.oiosaml.net%2fSaml%2fSSO.aspx it always uses Redirect. When it does the redirect the SAMLRequest is int he querystring and so is SigAlg and Signature. Example of what was posted to TestShib in the QueryString
I am not sure if this is a Shibboleth thing or just the SAML IDP I was using but they were not seeing the signature in the assertion so were rejecting the SamlRequest. My work around was to change the OIOSAML.net source code so that the default binding could be set via the web.config. I did this by adding a DefaultBindingMethod="POST" to the IDP <add element in the web.config then adding the DefaultBindingMethod property to the SAML20FederationConfig.cs and then changing TransferClient method in Saml20RemoteSignonHandler.cs to use the config value instead of being hard coded to SamlBinding.REDIRECT that way I can configure the default behavior for my Shibboleth IDP's to POST so the signature is present in the assertion like the IDP was expecting.
In the OIOSAML.net config entry for the Shibboleth IDP I had to set the attribute
omitAssertionSignatureCheck="true". The returned assertion from the Shibboleth IDP is signed but OIOSAML.net failed to find the key in metadata unless the KeyDescriptor explicitly has setuse="signing". Manually editing the Shibboleth metadata and adding the <KeyDescriptor use="signing"> allowed the source code to find the key but it still failed validation. So one issue is not accepting keys from a KeyDescriptor without any use limitations, the other is failing signature validation even with the key identified. This is not a recommended production fix as by bypassing the AssertionSignatureCheck allows for fake assertions to be accepted. I double checked the OIOSAML.net source code and they are Preserving Whitespace and are using the Microsoft.net SignedXML class to check the signature and it still failes validation. It also fails validation if I use the key that is included in the SAML Response along with the assertion. I assume this is some fundamental issue with Signature creation between the two platforms but have still not found a solution to the problem.
When I test with TestShib I get a CryptographicException SignatureDescription could not be created for the signature algorithm supplied. I believe the error with testshib is because it uses rsa-sha256 as all the other vendors I have used use rsa-sha1. When I test with another Shib IDP that uses rsa-sha1 I get a invalid Signature.The default web.config for OIOSAML.net sample code has the NameIDFormat set to
urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectNamewhich is not supported by all Shibboleth deployments (and not enabled by default). If OIOSAML.net requests a NameID format the IDP cannot satisfy the IDP may not send a NameID in the assertion's Subject at all. OIOSAML.net is coded to expect the NameID to be populated in the assertion Subject, otherwise it will throw an error.Saml20RemoteSignonHandler.cs
private void DoLogin(HttpContext context, Saml20Assertion assertion) { context.Session[IDPNameIdFormat] = assertion.Subject.Format; context.Session[IDPNameId] = assertion.Subject.Value;The OIOSAML.net source code is also coded to only parse metadata that has Bindings it understands so I also had to modify the metadata I received from the Shibboleth IDP to remove any unrecognized Bindings. Seems silly but when dk.nita.saml20 source code hits a binding it doesn't recognize it throws an error instead of just ignoring it. I had to remove from the Shibboleth IDP metadata any entry that wasn't Artifact, Post, Redirect or Soap to prevent it throwing an error.
Saml20MetadataDocument.cs
private string GetBinding(SAMLBinding samlBinding, string defaultValue) { switch (samlBinding) { case SAMLBinding.ARTIFACT: return Saml20Constants.ProtocolBindings.HTTP_Artifact; case SAMLBinding.POST: return Saml20Constants.ProtocolBindings.HTTP_Post; case SAMLBinding.REDIRECT: return Saml20Constants.ProtocolBindings.HTTP_Redirect; case SAMLBinding.SOAP : return Saml20Constants.ProtocolBindings.HTTP_SOAP; case SAMLBinding.NOT_SET: return defaultValue; default: throw new ConfigurationErrorsException(String.Format("Unsupported SAML binding {0}", Enum.GetName(typeof(SAMLBinding), samlBinding))); } }