Just like all the Service Oriented approaches, metadata is the key, for example, with web services, you just have to build the service (using ASMX file or WCF) it will generate the WSDL file for your service automatically, so the client code can easily consume. We expect the same thing with WIF, unfortunately, we cannot just build a STS and then somehow it exposes the federation metadata for that.
Most of the samples in WIF SDK and the Programming WIF book are showing you how to generate the metadata from a Visual Studio template. But there is almost no documentation on how to create the federation metadata manually (or dynamically), especially when you build a custom STS using MVC (hopefully we will have the template for MVC soon, but still not solving the dynamic issue).
WIF itself does provide APIs for this task, below are some very simple codes (I copy most of them from http://netpl.blogspot.com/2011/08/quest-for-customizing-adfs-sign-in-web.html). I just tried to put thing together and see how to use the WIF metadata API. For a more complete sample, please see the link above.
const string _endpoint = "http://yoursts.com";
static void Main(string[] args)
{
string endpointId = _endpoint;
EntityDescriptor entityDescriptor = new EntityDescriptor(
new EntityId(endpointId));
// Signature, I created a certificate using portecle and installed
// it under TrustedPeople/CurrentUser
X509Certificate2 cert =
CertificateUtil.GetCertificate(
StoreName.TrustedPeople, StoreLocation.CurrentUser, "CN=HoaSTSCert, C=US");
entityDescriptor.SigningCredentials = new X509SigningCredentials(cert);
SecurityTokenServiceDescriptor roleDescriptor = new SecurityTokenServiceDescriptor();
// required protocols supported
roleDescriptor.ProtocolsSupported.Add(new Uri(WSFederationMetadataConstants.Namespace));
roleDescriptor.Contacts.Add(new ContactPerson(ContactType.Administrative));
// This section is for key descriptor
SecurityKeyIdentifierClause clause = new X509RawDataKeyIdentifierClause(cert);
SecurityKeyIdentifier ski = new SecurityKeyIdentifier(clause);
KeyDescriptor signingKey = new KeyDescriptor(ski);
signingKey.Use = KeyType.Signing;
roleDescriptor.Keys.Add(signingKey);
// This section is for endpoint
string activeSTSUrl = _endpoint;
EndpointAddress endpointAddress = new EndpointAddress(
new Uri(activeSTSUrl),
null,
null,
(XmlDictionaryReader)null,
null);
// Active endpoint
roleDescriptor.SecurityTokenServiceEndpoints.Add(endpointAddress);
// Passive endpoint
roleDescriptor.PassiveRequestorEndpoints.Add(endpointAddress);
roleDescriptor.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Role));
roleDescriptor.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Name));
entityDescriptor.RoleDescriptors.Add(roleDescriptor);
// Serialize process...
MetadataSerializer serializer = new MetadataSerializer();
//MemoryStream stream = new MemoryStream();
string fileName = @"FederationMetadata.xml";
XmlWriter writer = XmlWriter.Create(fileName);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
serializer.WriteMetadata(writer, entityDescriptor);
writer.Flush();
Console.WriteLine("done...");
Console.WriteLine(string.Format("Output: {0}",
Path.Combine(Environment.CurrentDirectory, fileName)));
}