Search

Signature signing method in the IdP metadata not used by LeonGrave

Active

4
0
Sign in
to vote
Type: Bug
ID: 670013
Opened: 5/23/2011 12:08:17 PM
Access Restriction: Public
2
Workaround(s)
1
User(s) can reproduce this bug
I'm using the SAML2.0 Protocol extension in a Proof of Concept to connect with an ASP.net web application frontend to a Ping Federate IdP. The metadata from Ping Federate contains an XMLDSIG element which describes which signing algoritm the IdP is using.

In my case that is SHA-1, but it seems to be ignored, because when I turn on verbose logging for WIF, I notice that the saml message contains a SHA-256 signature. When I change the setting to SHA-256 in Ping Federate everything works fine, but on SHA-1 I keep getting message ID4037 (don't have the actual message on my screen, but it says that it can't access the certificate needed to check the signature)
Details (expand)

Describe the problem that you're having.

Can't get the SAML2 extention to work as an SP on an IdP that is on SHA-1 signatures, even while it says so in the IDP metadata

What type of impact does this issue have?

Functionality
File Attachments
File Name Submitted By Submitted On File Size  
Microsoft.IdenityModel.Protocols.Extensions.cs 1/25/2012 3 KB
Sign in to post a comment.
Posted by froodien1 on 9/20/2012 at 4:02 PM
Can someone from Microsoft please confirm that this workaround is suitable or possibly post about when this can be a configuration in a future releases?
Posted by froodien1 on 1/31/2012 at 12:18 PM
I see. the attachment is available in the Details (expand)
Posted by froodien1 on 1/25/2012 at 4:01 PM
The attachment should be available in several minutes to several hours according to MS
Sign in to post a workaround.
Posted by froodien1 on 1/26/2012 at 6:09 PM
So I uploaded the code file, although looks like it is not showing up. So here is the code.

using System.IdentityModel.Tokens;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using Microsoft.IdentityModel.Protocols.Saml2;
using Microsoft.IdentityModel.Protocols.WSFederation.Metadata;
using Microsoft.IdentityModel.SecurityTokenService;
using Microsoft.IdentityModel.Web;

namespace Microsof.IdentityModel.Protocols.Extensions
{
    public class MessageDecoratorEx : Microsoft.IdentityModel.Protocols.Saml2.MessageDecorator
    {
        public MessageDecoratorEx(string entityId) : base(entityId)
        {
        }

        public MessageDecoratorEx(string entityId, X509Certificate2 signingCertificate, bool signAuthenticationRequests) : base(entityId, signingCertificate, signAuthenticationRequests)
        {
        }

        protected override SigningCredentials CreateSigningCredentials(EntityDescriptor recipientDescriptor, Saml2Message message, ProtocolEndpoint endpoint)
        {

            if (this.SigningCertificate == null)
            {
                return null;
            }
            
            //
            //This is the change from the original class constructor, where we set the default digest and
            // signature algorithm. *Please make this configurable.*
            //

            SecurityKeyIdentifier ski = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] { new X509SecurityToken(this.SigningCertificate).CreateKeyIdentifierClause<X509RawDataKeyIdentifierClause>() });
            return new X509SigningCredentials(this.SigningCertificate, ski, "http://www.w3.org/2000/09/xmldsig#rsa-sha1", "http://www.w3.org/2000/09/xmldsig#sha1");
        }
    }

    public class Saml2AuthenticationModuleEx : Microsoft.IdentityModel.Web.Saml2AuthenticationModule
    {
        protected override void InitializeModule(HttpApplication context)
        {
            //
            //Ensure the base class is initialized first since we need access after the startup configuration is completed.
            //
            base.InitializeModule(context);

            //
            //Get a reference to the module instance.
            //
            Saml2AuthenticationModule module = Saml2AuthenticationModule.Current;

            //
            //Use reflection to access the private member for the MessageDecorator instance.
            const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
            FieldInfo messageDecoratorField = typeof(Saml2AuthenticationModule).GetField("_messageDecorator", bindingFlags);
            MessageDecorator value = (MessageDecorator)messageDecoratorField.GetValue(module);

            //
            //Copy all values from the current MessageDecorator since all the heavy lifting of
            // getting the right certificate etc. are done by the base class initialization.
            //
            X509Certificate2 signingCertificate = value.SigningCertificate;
            bool signAuthenticationRequests = value.SignAuthenticationRequests;
            string entityId = value.EntityId;

            //
            // Now re-create the MessageDecorator which overrides the certificate constructor implementation.
            //
            MessageDecoratorEx messageDecoratorEx = new MessageDecoratorEx(entityId, signingCertificate, signAuthenticationRequests);

            //
            // Finally replace the base class _messageDecorator with our extended class.
            //
            messageDecoratorField.SetValue(module, messageDecoratorEx);
        }
    }

}
Posted by froodien1 on 1/25/2012 at 3:59 PM
I do have a workable solution, however, a bit of background on the core of the issue.
The Saml2AuthenticationModule provided with the Microsoft.IdentityModel.Protocols assembly does all the heavy lifting and initializes a few objects. One of them is the Microsoft.IdentityModel.Protocols.Saml2.MessageDecorator class

The MessageDecorator class implements a method called CreateSigningCredentials which ultimately constructs the X509SigningCredentials. It does so by only passing a reference to the signing certificate it picked up from the metadata.

Hence the X509SigningCredentials class calls the constructor overload which ultimately has rsa-sha256 as its default fallback like this
public X509SigningCredentials(X509Certificate2 certificate, SecurityKeyIdentifier ski) : this(new X509SecurityToken(certificate), ski, "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256")
{
}

So, now we know the root cause and it does not seem like it can be fixed with just configuration.

Since the Saml2AuthenticationModule and the MessageDecorator classes are extensible, I was able to replace the MessageDecorator class, but not without a little reflection.
The details are in the attachment Microsoft.IdentityModel.Protocls.Extensions.cs

Finally point the Saml2AuthenticationModule declaration in the web.config/<modules> section to point to your new assembly you created from Microsoft.IdentityModel.Protocls.Extensions.cs

This solutions was tested and functions well.

Hope this helps others.