WCF, WIF and Load Balancing (and a bit of Azure)

Pablo wrote a post yesterday giving some background information on how session tokens are protected in WIF – here some additional info for WCF:

The ws* bindings in WCF establish a security session by default (via WS-SecureConversation). This has some implications, e.g.

  • You end up with a stateful service – or more important – with a stateful programming model. You have all the typical session “problems” like faulted sessions, timeout, retries etc…
  • By default SecureConversation only transmits a session identifier (like a ASP.NET session cookie) – the actual session is stored in-memory at the server. Not good for load balancing.

When you want to use WCF in a load balanced environment (e.g Azure) – you have to change the default behavior – you basically have two options:

  • Turn off SecureConversation all together. This has the advantage of being stateless (at least in that part of the communication). But this also means, that the bootstrap (SAML) token will get parsed on every request – this includes invoking the ClaimsAuthenticationManager. This might have performance implications – but depends on your scenario.
  • Force WCF into “cookie mode”. This means that the complete IClaimsPrincipal (after ClaimsAuthenticationManager has run) gets serialized and round-tripped in the SOAP header.

Turning off SecureConversation
Unfortunately WCF 3.5 does not directly allow that on the standard federation bindings. You would need to create a custom binding that uses an authentication mode of IssuedTokenOverTransport (for mixed mode) or IssuedTokenForCertificate (for message security).

In .NET 4 you can simply set establishSecurityContext to false on the standard ws-fed binding.

Cookie Mode
Forcing WCF into cookie mode requires a custom binding. The “trick” here is to set requireSecurityContextCancellation to false – which is just a fancy name for “serialize the context into the message”. Here’s the binding I am using (mixed mode security):

<customBinding>
  <binding name=federation_cookie>
    <security authenticationMode=SecureConversation
              messageSecurityVersion=WSSecurity11
                                      WSTrust13
                                      WSSecureConversation13
                                      WSSecurityPolicy12
                                      BasicSecurityProfile10

              requireSecurityContextCancellation=false>
      <secureConversationBootstrap authenticationMode=IssuedTokenOverTransport
                                   messageSecurityVersion=WSSecurity11
                                                           WSTrust13
                                                           WSSecureConversation13
                                                           WSSecurityPolicy12
                                                           BasicSecurityProfile10
>
        <issuedTokenParameters>
          <issuerMetadata address=”https://…&#8221; />
        </issuedTokenParameters>
      </secureConversationBootstrap>
    </security>
   
    <textMessageEncoding />
    <httpsTransport />
  </binding>
</customBinding>

As Pablo points out in his post, the session cookie must be protected somehow. The standard WIF behavior is to the DPAPI user key. This key cannot be easily shared between nodes in a cluster (unless the nodes are all domain members and roaming profiles are activated). Another more explicit (and practical) option is to use an RSA key. Most typically you would feed your SSL certificate or the certificate used to decrypt incoming tokens into the following session token handler:

public class WebFarmSessionSecurityTokenHandler : SessionSecurityTokenHandler
{
    public WebFarmSessionSecurityTokenHandler(X509Certificate2 protectionCertificate)
        : base(CreateRsaTransforms(protectionCertificate))
    { }
 
    private static ReadOnlyCollection<CookieTransform> CreateRsaTransforms
      (X509Certificate2 protectionCertificate)
    {
        var transforms = new List<CookieTransform>()
                        {
                            new DeflateCookieTransform(),
                            new RsaEncryptionCookieTransform(protectionCertificate),
                            new RsaSignatureCookieTransform(protectionCertificate),
                        };
 
        return transforms.AsReadOnly();
    }
}

One way of wiring up the above handler would be a service host factory for the WIF enabled WCF service. If you want to put a little more work in it you can also make the handler configuration friendly (see here).

In general I’d recommend watching Hervey’s excellent talk from PDC09 about WIF in load balanced environments (e.g. Azure).

HTH

This entry was posted in IdentityModel. Bookmark the permalink.

3 Responses to WCF, WIF and Load Balancing (and a bit of Azure)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s