Automatically generate Federation Metadata for your ASP.NET application

After having to generate Federation Metadata for the umpteenst time I decided it was time to deal with it once and for all. A tool like Thinktecture’s WS-Federation Generation Wizard is nice, but even that gets old after a while. Especially if you need to sign the metadata and the certificate is only on the hosting server. Fortunately, creating Federation Metadata for a passive endpoint is fairly easy, as the code below demonstrates. The code reads the current configuration from the system.identityModel section in web.config, so all you need to do is ensure it reflects your host configuration for a particular deployment (dev, test, acceptance, production). Of course you can manage that in Visual Studio with build management and config transforms.

private const string Saml10TokenTypeIdentifier = “urn:oasis:names:tc:SAML:1.0:assertion”;
private const string WsFederation12ProtocolIdentifier = “http://docs.oasis-open.org/wsfed/federation/200706″;

public string GenerateMetadata()
{
    return CreateMetadataString(CreateEntityDescriptor());
}

private EntityDescriptor CreateEntityDescriptor()
{
    var entityDescriptor = new EntityDescriptor();
    var applicationServiceDescriptor = new ApplicationServiceDescriptor();
    var config = FederatedAuthentication.FederationConfiguration;
    entityDescriptor.EntityId = new EntityId(config.WsFederationConfiguration.Realm);
    if (config.ServiceCertificate != null)
    {
        entityDescriptor.SigningCredentials = new X509SigningCredentials(config.ServiceCertificate);
        applicationServiceDescriptor.Keys.Add(GetSingingKey(config.ServiceCertificate));
    }
    applicationServiceDescriptor.ProtocolsSupported.Add(new Uri(WsFederation12ProtocolIdentifier));
    applicationServiceDescriptor.PassiveRequestorEndpoints.Add(new EndpointReference(config.WsFederationConfiguration.Realm));
    applicationServiceDescriptor.TargetScopes.Add(new EndpointReference(config.WsFederationConfiguration.Realm));
    entityDescriptor.RoleDescriptors.Add(applicationServiceDescriptor);
    return entityDescriptor;
}

private static string CreateMetadataString(EntityDescriptor entityDescriptor)
{
    var serializer = new MetadataSerializer();
    var stream = new MemoryStream();
    serializer.WriteMetadata(stream, entityDescriptor);
    stream.Seek(0L, SeekOrigin.Begin);
    return Encoding.UTF8.GetString(stream.ToArray());
}

private KeyDescriptor GetSingingKey(X509Certificate2 certificate)
{
    var x509Token = new X509SecurityToken(certificate);
    var x509RawDataKeyIdentifierClause = x509Token.CreateKeyIdentifierClause();
    var securityKeyIdentifierClause = new SecurityKeyIdentifierClause[]
                                            {
                                                x509RawDataKeyIdentifierClause
                                            };
    return new KeyDescriptor(new SecurityKeyIdentifier(securityKeyIdentifierClause))
    {
        Use = KeyType.Signing
    };
}

Leave a Reply

Your email address will not be published. Required fields are marked *