Designing claims-enabled WCF services

The WIF SDK for .NET Framework 4.0 also provides Visual Studio 2010 templates for creating the claims-enabled WCF RP service and WCF STS. In this recipe, we will look at ways of delegating identity management to a claims-based WCF STS. In addition, we will also explore out of the box bindings in WCF to support claims-based identity and look at the federation protocols supported by WIF to assign an out-of-band token to a WCF RP.

How to do it...

To design the claims-enabled WCF services, perform the following steps:

  1. Create a Visual Studio 2010 C# WCF Service Application project, and name it as ClaimsEnabledWcfService.
    How to do it...
  2. Right-click on the project, and click on Add STS reference… to run the Federation Metadata Utility wizard, and select Create a new STS project in the current solution under the Security Token Service option. Complete the running of wizard. A new WCF STS website project is added to the solution:
    How to do it...
    • Notice that the Federation Utility wizard identifies that you are trying to create an STS for a WCF service, and it automatically picks the WCF STS template. The utility establishes trust with the WCF application and makes the necessary configuration changes.
  3. Modify the GetData method in the Service1.svc.cs file to check for the assigned role:
    public string GetData(int value)
    {
    string role = Thread.CurrentPrincipal.IsInRole("Manager") ? "Manager" : "UnAuthorized";
    return string.Format("You entered: {0} and your identity is {1}, Role: {2}", value, Thread.CurrentPrincipal.Identity.Name, role);
    }
    
  4. Add a Visual Studio 2010 C# Console Application project, and generate the Service1.svc proxy file in the project using the svcutil.exe utility from the Visual Studio 2010 Tools Command Prompt.
  5. Add an application configuration file to the console client project, and create the service model configuration:
    <configuration>
    <system.serviceModel>
    <bindings>
    <ws2007FederationHttpBinding>
    <binding name="WS2007FederationHttpBinding_ IClaimsAwareWebService">
    <security mode="Message">
    <message>
    <issuer address="http://localhost:53526/ClaimsEnabled WcfService_STS/Service.svc" binding="ws2007HttpBinding" bindingConfiguration="noSctWs2007HttpBinding" />
    <issuerMetadata address="http://localhost:53526/ ClaimsEnabledWcfService_STS/Service.svc/mex" />
    </message>
    </security>
    </binding>
    </ws2007FederationHttpBinding>
    <!--Creates a custom WS2007HttpBinding to disable the use of security context token (SCT)-->
    <ws2007HttpBinding>
    <binding name="noSctWs2007HttpBinding">
    <security>
    <message establishSecurityContext="false"/>
    </security>
    </binding>
    </ws2007HttpBinding>
    </bindings>
    <client>
    <endpoint address="http://localhost:53490/Service1.svc/"
    binding="ws2007FederationHttpBinding" bindingConfiguration="WS2007FederationHttpBinding _IClaimsAwareWebService"
    contract="ClaimsEnabledWcfServiceProxy.IService1" name="WS2007FederationHttpBinding_IClaimsAwareWebService">
    <identity>
    <certificateReference x509FindType="FindBySubjectDistinguishedName" findValue="CN=DefaultApplicationCertificate" storeLocation="LocalMachine" storeName="My" />
    </identity>
    </endpoint>
    </client>
    </system.serviceModel>
    </configuration>
    

    WS2007FederationHttpBinding is used as the service binding, and the STS address is specified under the <issuer> element. Notice that the STS also exposes a mex endpoint that is specified using the <issuerMetadata> element. The security mode is set to Message, indicating message level security.

  6. In the Main method of the console client project, create an instance of the proxy and make a call to the GetData method. Print the output in the console window:
    Service1Client client = new Service1Client();
    Console.WriteLine(client.GetData(10));
    Console.ReadLine();
    
  7. Compile and run the application. An output of 10 is displayed in the console window along with the current identity and Role, as shown in the following screenshot:
    How to do it...

    Note

    The Role was defined as Manager in the GetOutputClaimsIdentity method under the CustomSecurityTokenService class in the WCF STS project.

  8. Add another Visual Studio C# 2010 Console Application project to the solution, and name it as IdentityDelegationClient.
  9. Open the Program.cs file in the IdentityDelegationClient project and write a helper method— GetSecurityTokenFromTrustChannel—to get a SecurityToken (System.IdentityModel.Tokens) object from the WCF STS website:
    private static SecurityToken GetSecurityTokenFromTrustChannel(EndpointAddress appliesTo, EndpointAddress stsAddress)
    {
    WSTrustChannel channel = null;
    WSTrustChannelFactory channelFactory = null;
    try
    {
    WS2007HttpBinding stsBinding = new WS2007HttpBinding();
    stsBinding.Security.Message.EstablishSecurityContext = false;
    channelFactory = new WSTrustChannelFactory(stsBinding, stsAddress);
    channel = (WSTrustChannel)channelFactory.CreateChannel();
    RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue);
    rst.AppliesTo = appliesTo;
    RequestSecurityTokenResponse rstr = null;
    SecurityToken token = channel.Issue(rst, out rstr);
    ((IChannel)channel).Close();
    channel = null;
    channelFactory.Close();
    channelFactory = null;
    return token;
    }
    finally
    {
    if (channel != null)
    {
    ((IChannel)channel).Abort();
    }
    if (channelFactory != null)
    {
    channelFactory.Abort();
    }
    }
    }
    
  10. Modify the Main method to retrieve SecurityToken created in the previous step and assign it to the ChannelFactory service instance using the CreateChannelWithIssuedToken method:
    EndpointAddress stsAddress = new EndpointAddress("http://localhost:53526/ClaimsEnabledWcfService_STS/Service.svc");
    EndpointAddress stsMexAddress = new EndpointAddress("http://localhost:53526/ClaimsEnabledWcfService_STS/Service.svc/mex");
    EndpointAddress serviceAddress = new EndpointAddress("http://localhost:53490/Service1.svc/");
    EndpointAddress serviceAddressWithDnsIdentity = new EndpointAddress(new Uri("http://localhost:53490/Service1.svc/"), EndpointIdentity.CreateDnsIdentity("DefaultApplicationCertificate"));
    WS2007HttpBinding stsBinding = new WS2007HttpBinding();
    stsBinding.Security.Message.EstablishSecurityContext = false;
    SecurityToken token = GetSecurityTokenFromTrustChannel(serviceAddress, stsAddress);
    WS2007FederationHttpBinding serviceBinding = new WS2007FederationHttpBinding();
    serviceBinding.Security.Mode = WSFederationHttpSecurityMode.Message;
    serviceBinding.Security.Message.IssuerAddress = stsAddress;
    serviceBinding.Security.Message.IssuerBinding = stsBinding;
    serviceBinding.Security.Message.IssuerMetadataAddress = stsMexAddress;
    ChannelFactory<IService1> serviceChannelFactory = new ChannelFactory<IService1>(serviceBinding, serviceAddressWithDnsIdentity);
    serviceChannelFactory.ConfigureChannelFactory();
    IService1 serviceChannel = serviceChannelFactory.CreateChannelWithIssuedToken(token);
    Console.WriteLine(serviceChannel.GetData(10));
    Console.ReadLine();
    
  11. Compile and run the application. The output described in step 7 is displayed here as well indicating similar results can be achieved by adding out of band tokens via the client.

How it works...

WCF has the built-in support for federation. We have seen in the previous chapter how WSFederationHttpBinding and WS2007FederationHttpBinding are used to delegate the identity management to a WCF STS. WIF abstracts some of the implementation details so the developer can utilize time for focusing on the service logic rather than programming for claims-based identity. In this recipe, the WCF STS assigns the claims using the GetOutputClaimsIdentity method under the CustomSecurityTokenService class. It assigns Role ClaimType carrying the Manager value. The GetData method of the IService1 implementation validates the role using the Thread.CurrentPrincipal.IsInRole method. In a real scenario, this will determine the level of access for the requestor.

There is one limitation in using a federated WCF STS. The way the token is generated cannot be controlled, and providing additional details in the token becomes nearly impossible. WIF runtime introduces the extension methods on the ChannelFactory (System.ServiceModel) class to allow communication with a service provider along with an out-of-band token. The IdentityDelegationClient project in our recipe solution uses the CreateChannelWithIssuedToken extension method to assign an out-of-band token to the outgoing message. The WSTrustChannel (Microsoft.IdentityModel.Protocols.WSTrust) is used to communicate directly with the WCF STS.

Note

The out-of-band communication requires the client to include reference to the WIF runtime.

ActAs and OnBehalfOf

The WIF runtime also provides the methods for ActAs and OnBehalfOf communication with the WCF RP service. This is achieved using the CreateChannelActingAs and CreateChannelOnBehalfOf extension methods on the channel factory. You can refer to the MSDN article at http://msdn.microsoft.com/en-us/library/ee517268.aspx to learn more about this topic.

See also

The complete source code for this recipe can be found in the Chapter 2Recipe 5 folder.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset