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.
To design the claims-enabled WCF services, perform the following steps:
ClaimsEnabledWcfService
. 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); }
Service1.svc
proxy file in the project using the svcutil.exe
utility from the Visual Studio 2010 Tools Command Prompt.<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.
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();
IdentityDelegationClient
. 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(); } } }
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();
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.
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.