Geneva Framework (aka Zermatt) has clean separation between token issuance object model (SecurityTokenService, RequestSecurityTokenRequest etc) and the protocol used to request token. By exploiting this separation, I will show you how to share a single SecurityTokenService object between active (WS-Trust) and passive (WS-Federation) clients. I have already written about Geneva and active clients here so in this post I will focus on passive clients. 

Geneva Framework comes with a sample which implements WS-Federation protocol handler in an ASPX page and for most of the scenarios you will use the same approach. Please refer to "Federation Scenario For Passive Clients" sample for details. The approach I am highlighting here is specific to those scenarios where you want to share the STS object between active & passive clients (Or you don't want to take a dependency on asp.net pipeline). To achieve this I will create a WCF based protocol handler (using the WCF http support) for WS-Federation protocol. In this handler I will convert the WS-Federation token issuance request into Zermatt token issuance object model (which is very much similar to WS-Trust protocol) and will then forward the request to a shared STS object. 

The service contract for my WS-Federation protocol handler looks like following: 

[ServiceContract] 

public interface IWSFederationService 

{ 

    [OperationContract] 

    [WebGet] 

    Message Issue(string wa, string wtrealm, string wreply, string wctx, string wct); 

} 

I have deliberately named the parameters of this method based on the elements of WS-Federation protocols. This enables WCF QueryStringFormatter to correctly map the values from the HTTP Get “query string” on to these parameters. 

public class ProcessService : IWSFederationService 

{ 

    public Message Issue(string wa, string wtrealm, string wreply, string wctx, string wct) 

    { 

        var col = OperationContext.Current.IncomingMessageProperties["UriTemplateMatchResults"] as UriTemplateMatch; 

        // Get the shared STS object. 

        var sts = SingletonSTS.Instance; 

         

        var fedSerializer = new WSFederationSerializer(); 

        //create a WS-Federation message for the input data. 

        SignInRequestMessage fedRequest = (SignInRequestMessage)WSFederationMessage.CreateFromUri(col.RequestUri); 

        //convert the federation request into the common WS-Trust based STS model. 

        var rst = fedSerializer.CreateRequest(fedRequest, new WSTrustSerializationContext()); 

        var rstr = sts.Issue(ClaimsPrincipal.Current,rst); 

         

        var rstrStr = fedSerializer.GetResponseAsString(rstr, new WSTrustSerializationContext()); 

        //serialize the token response back into WS-Federation message. 

        var fedResponse = new SignInResponseMessage(new Uri(wreply), rstrStr); 

        fedResponse.Write(Console.Out); 

        // Set appropriate content-type etc. 

        var httpMsg =  Message.CreateMessage(MessageVersion.None, "",new BinaryBodyWriter(fedResponse)); 

        httpMsg.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw)); 

        HttpResponseMessageProperty rmp = new HttpResponseMessageProperty(); 

        rmp.Headers[HttpResponseHeader.ContentType] = "text/html"; 

        httpMsg.Properties.Add(HttpResponseMessageProperty.Name, rmp); 

  

        return httpMsg; 

    } 

} 

With that I can host this service as any other WCF service and I’m ready to issue tokens based on WS-Federation protocol. 

class Program 

{ 

    static CustomSecurityTokenService sts; 

    static void Main(string[] args) 

    { 

        string stsAddress = "http://localhost:9000/STS"; 

        SingletonSTS.Init(stsAddress); 

        // For active clients, simply expose this sts over a WS-Trust endpoint. 

        WSTrustServiceHost wsTrustSTSHost = new WSTrustServiceHost(new WSTrustServiceContract(SingletonSTS.Instance), new Uri(stsAddress)); 

        wsTrustSTSHost.AddServiceEndpoint(typeof(IWSTrustFeb2005SyncContract), 

           new WSHttpBinding(), new Uri(stsAddress)); 

        // Make the Active STS ready. 

        wsTrustSTSHost.Open(); 

        Console.WriteLine("STS is now ready ..."); 

        foreach(var ep in wsTrustSTSHost.Description.Endpoints) 

            Console.WriteLine(ep.Address.Uri.AbsoluteUri); 

  

        //make passive STS ready. 

        var wsFedSTSHost = new WebServiceHost(typeof(ProcessService), new Uri("http://localhost/wcf/federation")); 

        wsFedSTSHost.AddServiceEndpoint(typeof(IWSFederationService), new WebHttpBinding(), ""); 

        wsFedSTSHost.Open(); 

        Console.ReadLine(); 

  

        wsFedSTSHost.Close(); 

        wsTrustSTSHost.Close(); 

    } 

}