In yesterdays post I have shown you how to create a basic STS using Zermatt. You can use this STS by configuring your clients to use WSFederationHttpBinding however in that case you will never see the token issued by STS. In this post I will show you a direct way to communicate with your STS by using the IssuedSecurityTokenProvider – This is useful for quick testing scenarios or when you need access to the issued token.

TokenProviders are the WCF components which provide the tokens used in message security. There is usually a TokenProvider for each type of security token (Certficate, UserName, Kerberos, IssuedToken etc). IssuedSecurityTokenProvider internally uses a ChannelFactory to communicate with the STS to get the actual token. You can configure this ChannelFactory by adding your custom behaviors to the IssuerChannelBehaviors property of the IssuedSecurityTokenProvider. Here is the code sample.

 

public static void Main()

{

    //This provider internally creates a WCF proxy (ChannelFactory) and uses it to issues RST request.

    IssuedSecurityTokenProvider provider = new IssuedSecurityTokenProvider();

    provider.SecurityTokenSerializer = new WSSecurityTokenSerializer();

 

    provider.TargetAddress = new EndpointAddress("http://localhost/IService");

    provider.IssuerAddress = new EndpointAddress("http://localhost:9000/STS");

 

    var be = new WSFederationHttpBinding().CreateBindingElements().Find<SecurityBindingElement>();

    // use the default algo & security versions used by Federation binding.

    provider.SecurityAlgorithmSuite = be.DefaultAlgorithmSuite;

    provider.MessageSecurityVersion = be.MessageSecurityVersion;

 

    // Binding used to communicate with STS.

    provider.IssuerBinding = new WSHttpBinding();

 

    // opent the internal channelfactory.

    provider.Open();

   

    // request token by issuing a WS-Trust RST request.

    var issuedToken = provider.GetToken(TimeSpan.FromMinutes(1));

   

    // print token on the console.

    WSSecurityTokenSerializer serializer = new WSSecurityTokenSerializer(be.MessageSecurityVersion.SecurityVersion);

    var writer = XmlWriter.Create(Console.OpenStandardOutput());

    serializer.WriteToken(writer, issuedToken);

    writer.Flush();

    provider.Close();

}

 

My STS requires Kerberos token to issue a SAML token – so this provider simply uses the kerberos token of the process. If you need to send different token (UserName etc) then you can do that using the IsserChannelBehaviors propery mentioned ealier.

provider.IssuerChannelBehaviors.Add(new IssuerCredBehavior());

And custom behavior looks like this.

public class IssuerCredBehavior : IEndpointBehavior

{

    #region IEndpointBehavior Members

 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

    {

        var cc = bindingParameters.Find<ClientCredentials>();

        if (cc == null)

        {

            cc = new ClientCredentials();

            cc.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

            cc.ServiceCertificate.SetDefaultCertificate("CN=localhost", StoreLocation.LocalMachine, StoreName.My);

           //Use this client certificate to get a SAML token.

            cc.ClientCertificate.Certificate = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.CurrentUser, "cn=localhost");

            bindingParameters.Add(cc);

        }

    }

 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)   {    }

 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)    {    }

 

    public void Validate(ServiceEndpoint endpoint)    {    }

 

    #endregion

}