For developers familiar with WCF, a WCF client is already federation aware. By configuring a WCF client with a WSFederationHttpBinding or similar custom binding, it is possible to enable federated authentication to a service.
WCF takes care of obtaining the issued token behind the scenes, and uses this token to authenticate to the service. The primary limitation with this approach is that there is no visibility into the communications with the issuer. Since WCF takes care of the issuer leg behind-the-scenes, the RST to the issuer is automatically generated by WCF based on the issued token parameters on the binding. The limitations in this space include but are not limited to:
a. Not possible to vary the RST parameters per request.
b. Not possible to inspect the RSTR to get information such as display claims, etc.
c. Not easy to cache the token for future use.
As it stands today, the WCF client suffices for basic federation scenarios. However, considering that one of the mainline scenarios introduced by Windows Identity Foundation requires control over the RST at a level WCF does not easily allow, more flexibility is needed. Windows Identity Foundation ships several client side pieces that aim to remove the "magic" of WCF, and give developers complete control over communication with the issuer.
Before we go into the details of the client side pieces, understand that the following federation scenarios are supported by WIF.
1. Using a WCF client without any WIF dependencies to authenticate to a federated service.
2. Augumenting a WCF client with WIF, to insert an ActAs or OnBehalfOf element into the RST to the issuer.
3. Using WIF alone, obtain a token from the issuer. Then, enable a WCF client to authenticate with this token.
The first scenario is self explanatory. Existing WCF clients will continue to work against WIF relying parties and issuers. The remainder of this article will delve deeper into the other two scenarios made possible by WIF.
Augumenting an Existing WCF Client with ActAs / OnBehalfOf
In a typical identity delegation scenario, a client calls a middle tier service who then needs to call a backend service acting as, or acting on behalf of, the client. This information is conveyed to a WS-Trust issuer via the ActAs and OnBehalfOf token elements in the RST.
Developers familiar with WCF will know that WCF exposes an extensibility point on the binding that allows the plumbing of arbitrary XML elements into the RST. However, since this extensibility point is tied to the binding, it means that scenarios which require the RST contents to change per-call will need to recreate the client every call, which is a performance hit. A simple API which allows attaching any token obtained out of band to the RST is needed.
WIF introduces this functionality via extension methods to the ChannelFactory class. The following code snippet demonstrates how easy it is to take some token representing the client (could be X509, Username, Saml), and attach it to the RST sent to the issuer.
IHelloService serviceChannel = channelFactory.CreateChannelActingAs<IHelloService>( clientSamlToken );
Notice that there are several key benefits that WIF enables:
1. RST can be modified per-channel. This means that middle tier services do not have to re-create the channel factory for each client, a huge performance improvement.
2. Works with existing WCF clients. This allows an easy upgrade path for existing WCF middle tier services that want to enable identity delegation semantics.
Note however, that there is still one drawback. There is still no visibility into the communications leg with the STS. The APIs demonstrated above simply piggyback on WCF's implementation and injects the ActAs or OnBehalfOf token into the RST. For even more fine-grained control, we move on to the third scenario.
Communicating Directly with an Issuer, and Using the Issued Token to Authenticate
For some advanced scenarios, augumenting a WCF client is not sufficient. Developers using just WCF typically resort to using Message In / Message Out contracts and need to handle client-side parsing of the issuer response by hand.
WIF introduces new functionality that significantly improves the client side programming model. The WSTrustChannelFactory and WSTrustChannel in WIF are designed to communicate directly with a WS-Trust issuer. The sample code below demonstrates how the APIs allow for strongly-typed RST / RSTR objects to flow between client and issuer.
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory( stsBinding, stsAddress );
WSTrustChannel channel = (WSTrustChannel) trustChannelFactory.CreateChannel();
RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue);
rst.AppliesTo = new EndpointAddress(serviceAddress);
RequestSecurityTokenResponse rstr = null;
SecurityToken token = channel.Issue(rst, out rstr);
Notice that the out parameter on the Issue() call allows access to the RSTR for client-side inspection.
Keep in mind that so far, all we have seen is how to obtain a token. The token returned from the TrustChannel is a GenericXmlSecurityToken construct that contains all the information required for the next leg: authenticating to a relying party. To use this token:
IHelloService serviceChannel = channelFactory.CreateChannelWithIssuedToken<IHelloService>( token ); serviceChannel.Hello(“Hi!”);
The CreateChannelWithIssuedToken() extension method on the ChannelFactory indicates to WIF that you have obtained a token out-of-band, and to short circuit the normal WCF call to the issuer. This will simply use the token you obtained to authenticate to the relying party.
Again, the several benefits here:
1. Complete control over the token issuance process.
2. ActAs / OnBehalfOf scenarios are supported by directly setting these properties on the outgoing RST.
3. Allows dynamic client-side trust decisions to be made based on RSTR contents.
4. The token returned from the Issue() call is cachable and can be reused.
5. WSTrustChannelFactory and WSTrustChannel constructs allow for control over channel caching, fault, and recovery semantics in line with WCF best practices.
And the only drawback:
1. You have to write more code than using a WCF client.
With WIF, the WCF client side programming model for communicating with an STS has been extended significantly. Existing code will continue to work, and developers have the option to either augment existing clients, or take complete control over communications with the issuer.