1
votes

I have an issue trying to add an idp to the authentication service.

My client is using forgerock login, and wants us to use SSO with SAML.

I have this working in an older project using Jitbit's simple SAML 2.0 component for ASP.NET https://github.com/jitbit/AspNetSaml/

But I am redesigning my application in .net core with identityserver4, and wanted to take advantage of the sustainsys implementation with the extra bells and whistles.

The type of SSO login is a simple redirect with ACS callback.

The information I have: SamlEndpoint - The URL to redirect to EntityId - My Entities Id AcsUrl - the URL to return to Certificate (string) (Taken from the metadata, which is not publicly available)

I have tried to do the following:

services.AddAuthentication()
            .AddSaml2(Saml2Defaults.Scheme,
                   options =>
                   {
                       options.SPOptions.EntityId = new EntityId("{MyEntityId}");
                       options.SPOptions.ReturnUrl = new Uri($"ACS URL");
                       options.SPOptions.AuthenticateRequestSigningBehavior = Sustainsys.Saml2.Configuration.SigningBehavior.Never;
                       //options.SPOptions.ServiceCertificates.Add(new ServiceCertificate { 
                       //    Use = CertificateUse.Signing, 
                       //    Certificate = new X509Certificate2(bytes), 
                       //    Status = CertificateStatus.Current 
                       //});
                       var idp =
                           new IdentityProvider(new EntityId("IDP ID"), options.SPOptions)
                           {                                   
                               Binding = Sustainsys.Saml2.WebSso.Saml2BindingType.HttpRedirect,
                               LoadMetadata = false,
                               AllowUnsolicitedAuthnResponse = true, 
                               SingleSignOnServiceUrl = new Uri("Redirect URL") 
                           };
                       options.IdentityProviders.Add(idp);
                   });

The exception I am getting is: System.Configuration.ConfigurationErrorsException: 'Missing signing certificate configuration on Idp

But I cannot see how to add my certificate? as it has no private/public key:

From the metadata

<ds:X509Data>                    
    <ds:X509Certificate>
        MIIDYTCCAk..........7tOxUus=                    
    </ds:X509Certificate>                
</ds:X509Data>

Looking for a steer in the right direction as I am failing to work it out.

If I try and add the certificate (commented out above) then I get no private key provided exception.

Cheers guys

1

1 Answers

2
votes

This issue appears to be a "chicken and egg" issue where assigning the value for LoadMetadata is not a "safe" operation to perform while constructing a new instance of IdentityProvider.

The set property method for IdentityProvider also calls Validate() against your newly constructed IdentityProvider instance. In this case, you can see here the Validate() method being called: https://github.com/Sustainsys/Saml2/blob/develop/Sustainsys.Saml2/IdentityProvider.cs#L123. Not to worry too much since the private backing field, loadMetadata, is already false (default value).

The problem here is that you're not yet given the ability to add your IdP signing certificate (idp.SigningKeys.Add(...)) before Validate() is called.

You need to:

  1. Create your idp, do not yet set LoadMetadata
  2. Add your signing keys or make any other configuration settings you need
  3. If desired, you can explicitly set LoadMetadata (optional in your case since it's already false)

That should resolve this error and get you on your way.

BTW, your signing certificate needs to have a private key. I would suggest generating something like a PFX (PKCS#12, PKCS#8, etc.) and you can import that file directly into an X509Certificate2 with the password set, be sure to set the options with MachineKeySet | Exportable so your private key is accessible: e.g.

byte[] pfx = null; // TODO: Get your actual certificate, read from file, DB, memory, etc.
var signingCert = new X509Certificate2(
    pfx,
    "password",
    X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);