Building a claims aware WCF Service using Windows Identity Foundation

Windows Identity Foundation (WIF) just shipped, so I decided to give it a go and see how easy it was to get started.
There’s an easy way to get started building an STS and claims aware WCF service, and there’s a hard way. The easy way is to just use the templates provided by Visual Studio. The hard way is to do everything manually. I decided to do it the hard way because of two reasons;
1: I wanted to learn the details, and 2: If I could get it working, I would WIF-enable existing projects (in my case, Silverlight projects).

So here’s the steps I went through in order to get a my basic claims aware WCF up and running:

1) In Visual Studio, create a new Web Application, let’s call it SecureWebApplication

2) Create an STS application (Security Token Service) by adding a new web application to the solution. Let’s call it SecureWebApplication_STS

3) Add a reference to Microsoft.IdentityModel.dll, System.IdentityModel.dll and System.ServiceModel.dll to the STS application.
Note! You may need to set Copy Local = true for Microsoft.IdentityModel.dll before the STS app can be called.

4) In the STS application, add the following classes: Common, AppSecurityTokenService, CertificateUtil and AppSecurityTokenServiceConfiguration. (Get implementation of classes from the web site you get when creating an ASP.NET Security Token Service Web Site. File -> New -> Web Site…).

5) Add a new text file to the STS application. Call it AppSTS.svc.

6) Edit AppSTS.svc so it contains the following line;

<%@ ServiceHost Language="C#"
                Debug="true"
                Factory="Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceHostFactory"
                Service="SecureWebApplication_STS.AppSecurityTokenServiceConfiguration"  %>


This will enable our STS to be hosted by a service host in our web application.

7) In the STS application, edit the web.config file and add configuration settings that specifies how the STS should encrypt and sign issued security tokens;

<appSettings>
    <add key="IssuerName" value="SigninSTS"/>
    <add key="SigningCertificateName" value="CN=STSTestCert"/>
    <add key="EncryptingCertificateName" value="CN=STSTestCert"/>
  </appSettings>


Note! The STSTestCert is a X509Certificate installed as part of the Windows Identity Foundation SDK. Feel free to use a different certificate, but this walkthrough assumes that STSTestCert is used.

8 ) In the STS application, edit the web.config file and add the WCF service configuration for the STS service. 

<system.serviceModel>
    <services>
      <service name="Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract"
               behaviorConfiguration="ServiceBehavior">
        <endpoint address="IWSTrust13" binding="ws2007HttpBinding"
                  contract="Microsoft.IdentityModel.Protocols.WSTrust.IWSTrust13SyncContract"
                  bindingConfiguration="ws2007HttpBindingConfiguration"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:14499/AppSTS.svc"/>
          </baseAddresses>
        </host>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <bindings>
      <ws2007HttpBinding>
        <binding name="ws2007HttpBindingConfiguration">
          <security mode="Message">
            <message establishSecurityContext="false"/>
          </security>
        </binding>
      </ws2007HttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>


9) We should now have a working STS that can be used by WCF Services. Let’s go back to your main web application and add a claims aware WCF Service.

10) Go to the main web application, SecureWebApplication, and add a reference to Microsoft.IdentityModel.dll and System.ServiceModel.dll.

Note! You may need to set Copy Local = true property for Microsoft.IdentityModel.dll before executing the app.

11) Add a Silverlight-enabled WCF Service, or just a plain WCF Service. I’ll be using a SL-enabled WCF Service in this walkthrough. Lets call the service MyService.scv.

12) Once you have added the WCF service, open the web.config-file

13) In the web.config-file, remove the default customBinding configuration added by Visual Studio and specify the service to use ws2007FederationHttpBinding instead.

Optionally, you can remove the <serviceHostingEnvironment aspNetCompatibilityEnabled=”True” /> element.

<services>
      <service behaviorConfiguration="SecureWebApplication.MyServiceBehavior"
               name="SecureWebApplication.MyService">
        <endpoint address="" binding="ws2007FederationHttpBinding"
                  bindingConfiguration="MyServiceBindingConfiguration"
                  contract="SecureWebApplication.MyService"/>
        <endpoint address="mex" binding="mexHttpBinding"
                  contract="IMetadataExchange"/>
      </service>
 </services>


14) Before we can configure the service behavior, we need to register a WCF extension for Windows Identity Foundation which allows federation.

In system.serviceModel, add an the following section

<extensions>
      <behaviorExtensions>
        <!-- This behavior extension will enable the service host to be Claims aware -->
        <add name="federatedServiceHostConfiguration"
             type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </behaviorExtensions>
 </extensions>


15) Now we’re ready to define the service behavior. Add the following behavior to system.serviceModel/behaviors/serviceBehaviors. The service certificate we specify in the behavior is the certificate used by the STS to encrypt the security token (the certificate configured in step 7)

<behavior name="SecureWebApplication.MyServiceBehavior">
          <federatedServiceHostConfiguration/>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <serviceCertificate findValue="0E2A9EB75F1AFC321790407FA4B130E0E4E223E2"
                                storeLocation="LocalMachine" storeName="My"
                                x509FindType="FindByThumbprint"/>
          </serviceCredentials>
 </behavior>


16) Finally, we need to configure our ws2007FederationBinding, which is the binding used by out STS.

Add the following binding to system.serviceModel/bindings

<ws2007FederationHttpBinding>
        <binding name="MyServiceBindingConfiguration">
          <security mode="Message">
            <message>
              <issuerMetadata address="http://localhost:14499/AppSTS.svc/mex" />
            </message>
          </security>
        </binding>
      </ws2007FederationHttpBinding>


17) Our next steps involves configuring our WCF Service to use Windows Identity Foundation, so we’ll just stay in the web.config-file.

18) The first step is to register a new WIF config section so that we can specify our WIF configuration in the web.config-file. Add the following line to configuration/configSections in the web.config-file

<section name="microsoft.identityModel"
             type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>


19) Now we’re ready to WIF-enable our WCF service. We do that by specifying the content of the microsoft.identityModel section as follows:

<microsoft.identityModel>
  <service>
    <audienceUris>
      <add value="http://localhost:14488/MyService.svc"/>
    </audienceUris>
    <federatedAuthentication>
      <wsFederation passiveRedirectEnabled="true" issuer="http://localhost:14499" realm="http://localhost:14488" requireHttps="false"/>
      <cookieHandler requireSsl="false"/>
    </federatedAuthentication>
    <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <trustedIssuers>
        <add thumbprint="0E2A9EB75F1AFC321790407FA4B130E0E4E223E2" name="http://localhost:14499"/>
      </trustedIssuers>
    </issuerNameRegistry>
  </service>
</microsoft.identityModel>


20) We now have a working claims aware WCF Service. To test it, you can create a new test web application in the same solution and add a service reference to the service.