DevX HomePage

Fundamentals of WCF Security

The labyrinth of security features for WCF is intricate and at times even overwhelming. At its core, however, are a basic set of security principals for authentication, authorization, and message transfer protection.
indows Communication Foundation (WCF) is a secure, reliable, and scalable messaging platform for the .NET Framework 3.0.

With WCF, SOAP messages can be transmitted over a variety of supported protocols including IPC (named pipes), TCP, HTTP and MSMQ. Like any distributed messaging platform, you must establish security policies for protecting messages and for authenticating and authorizing calls. This article will discuss how WCF accomplishes this.

A consistent set of fundamental security concepts apply in any distributed messaging system. Consider a message from sender (the calling application) to receiver (the target service receiving the message for processing):

A consistent set of fundamental security concepts apply in any distributed messaging system.
WCF provides a rich and configurable environment for creating security policies and setting runtime behaviors to control these security features. A variety of mutual authentication mechanisms are supported using token formats such as Windows tokens, username and password, certificates and issued tokens (in a federated environment). Authorization can be based on Windows roles, ASP.NET roles or you can provide custom authorization policies. Message protection (integrity and confidentiality) can be based on symmetric session keys, or asymmetric keys for single-hop protection.

In the following sections, I'll show you how to configure WCF security and then take you through some common WCF deployment scenarios and their specific security configurations that employ these fundamental security concepts.

Security, WCF Style
The first step to securing a WCF service is defining the security policy. Once you have established requirements for authentication, authorization, and message protection it is a matter of service configuration to enforce it.

Your binding selection will influence the available configuration options for the service security policy. When you expose a service endpoint you select a binding that represents the appropriate communication protocol and message encoding format. For example, for intranet communications or systems behind the firewall, TCP protocol with binary message encoding is usually preferred. For Internet access, HTTP protocol is a typical choice using text or MTOM encoding (depending on the message size).

A standard set of bindings satisfy these protocol and encoding choices. NetTcpBinding is the right choice for binary TCP communications that cross machine boundaries, BasicHttpBinding is the right choice for HTTP communications that must support legacy Web service protocols, and WSHttpBinding or WSFederationHttpBinding are the right choice for Web services that can leverage a richer set of standards including those for secure communications (the latter is used for federated security scenarios).

Beyond bindings, behaviors also provide information about client and service credentials, and affect how authorization is handled.

You can configure bindings and behaviors declaratively or through the runtime object model—but in the following sections I'll focus on how you declaratively configure core security settings.




Default Security Settings
Each binding has a default set of security settings. Consider the following service endpoint that supports NetTcpBinding.

 <system.serviceModel>
<services>
<service name="HelloIndigo.HelloIndigoService" >
<endpoint contract="HelloIndigo.IHelloIndigoService"
binding="netTcpBinding" />
</service>
</services>
</system.serviceModel>
NetTcpBinding is secure by default. Specifically, callers must provide Windows credentials for authentication and all message packets are signed and encrypted over TCP protocol. Look at the expanded binding configuration illustrating these default settings.

 <netTcpBinding>
<binding name="netTcp">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
When the security mode is set to message security, you can customize the default security settings for NetTcpBinding by configuring different values for clientCredentialType or algorithm suite. Other bindings such as WSHttpBinding also allow you to determine if a secure session will be established and control how service credentials are negotiated. Each of the standard WCF bindings supports only relevant security options for their typical usage. In the next sections, I'll review some of the security-specific binding options available, and how you configure them.

Security Mode
Across all service bindings there are five possible security modes:

You can turn off security completely, or allocate authentication and message protection between transport and message-level security. Each transport protocol (TCP, IPC, MSMQ, or HTTP) has its own mechanism for passing credentials and handling message protection. Message security supports passing credentials as part of the SOAP message using interoperable standards, and also makes it possible to protect the message independent of transport all the way through to the ultimate message receiver. Transport message protection is only good from point to point.

NetTcpBinding is secure by default. Specifically, callers must provide Windows credentials for authentication and all message packets are signed and encrypted over TCP protocol.
To control the security mode used for a particular binding, set the mode property for the binding's <security> section. For Transport or modes that use transport security, the <transport> section should be expanded. You can see this illustrated in the <netTcpBinding> section shown earlier. For Message mode, settings are supplied in the expanded <message> section. For example, this <wsHttpBinding> snippet illustrates how to require UserName credentials be passed with the message.

 <wsHttpBinding>
<binding name="wsHttp">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
Note that not all bindings support all security modes.

Client Credential Type
The choice of client credential type depends on the security mode in place. For transport security you can require a Windows credential or certificate—and there are variations on how Windows credentials are passed via TCP, HTTP and MSMQ. Message security supports any of the following settings for clientCredentialType:

BasicHttpBinding only supports UserName and Certificate credentials since it is intended to be interoperable with Basic Security Profile per WS-I.

This code snippet illustrates how to select a clientCredentialType for message security.

 <basicHttpBinding>
<binding name="basicHttp">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
Your choice of credential type may affect other configuration settings for the service. For example, UserName credentials require either transport message protection or a service certificate be used to protect the exchange.

Protection Level
By default, all secure WCF bindings will encrypt and sign messages. You cannot disable this for transport security, however, for message security you may wish to disable this for debugging purposes, or when an alternate method of protection is used such as IPSec.

Protection-level settings are controlled by the contract. You can specify protection level for all operations in the service contract using the ServiceContractAttribute. The following example illustrates disabling encryption.

 [ServiceContract(Name="HelloIndigoContract",
Namespace= "http://www.thatindigogirl.com/2006/06/Samples",
ProtectionLevel=ProtectionLevel.Sign)]
public interface IHelloIndigoService
{
string HelloIndigo(string inputString);
}
For more granular control, you can also indicate message protection per operation using the OperationContractAttribute.

 [ServiceContract(Name="HelloIndigoContract",
Namespace=http://www.thatindigogirl.com/2006/06/Samples]
public interface IHelloIndigoService
{
[OperationContract(ProtectionLevel= ProtectionLevel.Sign)]
string HelloIndigo(string inputString);
}
You can also control protection level on message contracts providing granular control over specific headers or body elements.

ProtectionLevel options are: None, Sign, and EncryptAndSign. None disables message protection. EncryptAndSign provides full message protection and is the default behavior. Sign indicates the message should be signed but not encrypted.

The ProtectionLevel property serves a dual role. First, it specifies the minimum requirements for message protection. If the property is not specified, the default behavior is to encrypt and sign, but not enforce those settings on the binding. By specifying a value for the property using one of the attributes I mentioned, messages that don't meet the requirement will be rejected for not satisfying the security policy. The second role is to control how message-level protection is applied (since it has no direct affect on transport protection).

Algorithm Suite
Choice of algorithm suite can be particularly important for interoperability. Each binding uses Basic256 as the default algorithm suite for message-level security. This suite defines the algorithms and key lengths for cryptographic operations such as key signatures, encryption, and key wrap. Algorithm suites are described in the WS-SecurityPolicy specification, and can be applied by setting the algorithm attribute of the <message> section.

 <wsHttpBinding>
<binding name="wsHttp">
<security mode="Message">
<message clientCredentialType="UserName"
algorithmSuite="TripleDes" />
</security>
</binding>
</wsHttpBinding>
Service Credentials and Negotiation
To support mutual authentication and message protection, services must provide credentials to the caller. When transport security is used, service credentials are negotiated through the transport protocol. Service credentials for message security can also be negotiated when Windows credentials are used; otherwise a service certificate must be specified in the <behaviors> section under <serviceCredentials>.

 <behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior" >
<serviceCredentials>
<serviceCertificate findValue="RPKey"
storeLocation="LocalMachine" storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
In this case, the caller must have access to the public key portion of the service certificate to encrypt messages sent to the service. This can be specified out of band, or negotiated with an initial handshake.

The default behavior for message security supports negotiation. That means that the service is dynamically asked for the correct token before any messages are exchanged. For Windows client credentials SPNego protocol is used, and for UserName, Certificate or Anonymous credentials, TLSNego protocol is used. Today these are not interoperable protocols, so it may be desirable to disable this negotiation.

You can set negotiateServiceCredential to false in the <message> section to accomplish this.

 <wsHttpBinding>
<binding name="wsHttp">
<security mode="Message">
<message clientCredentialType="UserName"
negotiateServiceCredential="false" />
</security>
</binding>
</wsHttpBinding>
When negotiation is disabled for Windows client credentials, a Kerberos domain must exist. For other credential types the client must have access to the service public key to encrypt messages.

When you generate a service proxy with configuration settings for the client (using svcutil.exe) an encoded version of the public certificate is supplied in the <identity> section to handle this case.

 <client>
<endpoint address="http://localhost:8000/HelloIndigo"
binding="wsHttpBinding" bindingConfiguration="wsHttp"
contract="Client.localhost.HelloIndigoContract"
name="WSHttpBinding_HelloIndigoContract">
<identity>
<certificate encodedValue="
AwAAAAEAAAAUAAAAreiGqilku9hngWEQL1g+
...
oBd0vDwZaqjy47g0jFV9pF0VHhoVbTtOA=="/>
</identity>
</endpoint>
</client>
It is also possible to install the public key of the service in the client certificate store and retrieve it from there at run time.

Secure Session
Another feature of message security is the ability to establish a secure session to reduce the overhead of one-off key exchange and validation. By default, secure sessions are enabled for message security. A security context token (SCT) is generated through an initial exchange between caller and service. This token is used to authorize and secure subsequent message exchanges.

If the caller plans to make several calls to a service, secure sessions are more efficient. For a single call, however, you can disable this feature by setting establishSecurityContext to false.

 <wsHttpBinding>
<binding name="wsHttp">
<security mode="Message">
<message clientCredentialType="UserName"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>




Authentication, Authorization, and Identities
From the discussion so far, you should gather that messages are secured according to service security policy. Mutual authentication is performed based on the supplied client and service credentials. Message protection is applied according to transport or message security configuration—which normally means that messages are both signed and encrypted. Token authentication, runtime identities, security principals, and authorization policies also play an important role in the WCF security story.

Access to resources during a service operation is influenced by three key elements:

Figure 1 illustrates the relationship of these security elements. While the process identity is constant, each operation is executed on a request thread that contains a unique security principal and security context. In the following sections I'll elaborate on the authorization process and the role of these and other security elements.

 
Figure 1: Operations execute within a security context that includes a set of claims and an identity. The identity of the security principal attached to the executing thread is equivalent to the primary identity of the security context.
Claims-Based Identity Model
The identity model in WCF supports a rich, claims-based approach to authorization. A claim describes an individual right or action applicable to a particular resource. For example, an identity claim could represent a Windows token, a non-Windows user account, an X509 certificate or some other identity type. Claims can also be proof of possession of other information such as an e-mail address, birth date, or first and last name. Custom claims can be created to indicate the ability to access specific business entities or their storage location.

Claims are generated from security tokens. Security tokens are abstractions of credentials that are passed in the security headers of a message and validated against the security policy. When security tokens are validated and processed at the service, claims are extracted and placed into the security context for the operation being executed. Each credential type will result in a different set of claims (called a claimset) to evaluate—but you could unify the claimset by mapping the default claims to custom claims that will be evaluated by your code at run time.

Ultimately, a claimset is attached to the ServiceSecurityContext and available for any custom authorization code involved in the execution of the operation. Although traditional role-based security is still supported, a customized claims-based authorization model can add a welcome layer of granularity.

ServiceSecurityContext
ServiceSecurityContext provides access to claims at run time. Some key properties of the ServiceSecurityContext type are:

You can access the ServiceSecurityContext through the OperationContext.

 ServiceSecurityContext security =
OperationContext.Current.ServiceSecurityContext;
With that reference, you could implement a custom authorization check that is based on claims. For example, you could check to see that the user was authenticated and that an e-mail claim was also provided.

 string user = security.PrimaryIdentity.Name;
string email = null;
IEnumerable<Claim> claims =
security.AuthorizationContext.ClaimSets[0].FindClaims(
ClaimTypes.Email,Rights.PossessProperty);
foreach (Claim c in claims)
{
email = c.Resource as string;
}
if (string.IsNullOrEmpty(user) || email == null)
throw new SecurityException(
"Unauthorized access. Email claim not found.");
This code illustrates using the ServiceSecurityContext for custom authorization inside an operation—but it can also be wrapped into a custom authorization policy to decouple from operation code and provide a unit of reuse.

The ServiceSecurityContext is also used during role-based authorization, to be discussed shortly.

Security Token Authentication
Claims are added to the security context while tokens are authenticated. One or more security tokens can be present in a message. Each token is authenticated by its own SecurityTokenAuthenticator type. Table 1 provides a list of commonly used token authenticators with a short description.

Table 1: A subset of commonly used SecurityTokenAuthenticator types for authenticating security tokens.

SecurityTokenAuthenticator Type

Description

WindowsSecurityTokenAuthenticator

Ensures a valid Windows token. Generates a WindowsClaimSet for authorization.

KerberosSecurityTokenAuthenticator

Ensures a valid Kerberos token. Generates a WindowsClaimsSet for authorization.

X509SecurityTokenAuthenticator

Validates the certificate and maps it to a Windows identity if applicable. Generates an X509ClaimSet and possibly a WindowsClaimSet.

WindowsUserNameSecurityTokenAuthenticator

Creates a Windows token for the username and password provided. Generates a WindowsClaimSet for authorization.

CustomUserNameSecurityTokenAuthenticator

Validates the username and password against the configured membership provider or password validator. Generates a UserNameClaimSet for authorization.

SamlSecurityTokenAuthenticator

Validates the SAML token (timestamp, signature, etc.). Resolves claims directly from the token for authorization.


Windows tokens are authenticated against the Windows domain. Certificate credentials are authenticated against the certificate store based on authentication rules specified in the <clientCertificate> section of the service behavior. For example, the following configuration does not map certificates to Windows accounts, and will trust certificates placed in the TrustedPeople store—otherwise it will try to validate the chain of trust online.

 <behavior name="serviceBehavior">
<serviceCredentials>
<clientCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"
trustedStoreLocation="LocalMachine"
revocationMode="Online"
mapClientCertificateToWindowsAccount="false" />
</clientCertificate>
</serviceCredentials>
</behavior>
By default, UserName tokens authenticate against the Windows domain, but you can use the membership provider model of ASP.NET by changing the userNamePasswordValidationMode from "Windows" to "MembershipProvider" (see Listing 1). This setting engages the default ASP.NET provider model unless you specify an alternate membership provider, or a custom password validator in the <userNameAuthentication> section.

SAML tokens are not authenticated against a provider model, but the token itself is validated and its claims presented for authorization.

Clearly, token authentication is specific to the token type, and each has a specific set of behavioral settings appropriate to the token that control how authentication is carried out. The end result for successful authentication is a claimset that can later be used for authorization, and an identity attached to the security context and the thread.

Role-Based Authorization
Despite the importance and granularity of the claims-based authorization model in WCF, role-based security is still alive and well, and is useful for controlling access to service operations and business classes used downstream. This type of authorization is based on the security principal for the request.

The identity model in WCF supports a rich, claims-based approach to authorization.
The identity of the caller is attached to the executing request thread in the form of a security principal, accessible through the CurrentPrincipal property.

 System.Threading.Thread.CurrentPrincipal
The security principal is a wrapper for an identity—its type is directly related to the token type received. For example, it could be a WindowsIdentity, X509Identity, GenericIdentity, or a custom type that implements System.Security.Principal.IIdentity. The identity is created during authentication as I discussed.

The actual security principal is a type that implements System.Security.Principal.IPrincipal. This interface has two members:

The choice of role provider for a request influences the type of security principal attached to the thread. Options for role provider include:

The default role provider is "Windows," therefore a WindowsPrincipal is the default type. For Windows, UserName or Certificate credentials (when Certificates are mapped to Windows accounts) this will contain an authenticated WindowsPrincipal, otherwise the principal is unauthenticated and has no runtime use for role-based security.

If you aren't expecting Windows credentials, you can change the role provider by setting the principalPermissionMode value of the <serviceAuthorization> behavior (see Listing 1). If you are using the ASP.NET credentials database, you can set it to "UseAspNetProvider." This causes a RoleProviderPrincipal to be attached to the thread instead of a WindowsPrincipal. This IPrincipal type is new to WCF, and holds a reference to the ServiceSecurityContext. When the identity is requested from the principal, it actually returns a reference to the ServiceSecurityContext's PrimaryIdentity property (discussed earlier). When IsInRole() is invoked, it uses the configured RoleProvider (in this case, the default ASP.NET role provider) to check if this identity is in the specified role.

You can also customize this behavior with a custom ASP.NET RoleProvider or with a custom authorization policy.

In any case, .NET role-based security relies on the IPrincipal object attached to the thread to perform authorization checks. So, even with WCF you can use the PrincipalPermission type to discover things such as:

At runtime, this can be done with an imperative permission demand within the WCF operation or any business component. Just create a PrincipalPermission object, initialize the values you want to enforce, and issue the Demand().

 public string AdminsOnly()
{
// unprotected code
PrincipalPermission p = new
PrincipalPermission(null, "Administrators");
p.Demand();
// protected code
}
In this example, an exception will be thrown if the user is not in the Administrators group.

You can also place a declarative PrincipalPermissionAttribute on any WCF operation or business component method to apply the demand before the operation or method is invoked:

 [PrincipalPermission(SecurityAction.Demand, Role =
"Administrators")]
public string AdminsOnly()
{
// protected code
}
This approach is preferable since it decouples the security requirements from the actual code within the operation.

In both scenarios, the IsAuthenticated property of the identity is verified, and the IsInRole() method is invoked to check membership using the IPrincipal object attached to the thread.




Custom Authorization Policies
Credential authentication, default claimset generation, and access to the security principal for role-based demands are all features that are configurable as I've discussed so far in this section. These are features that you get "for free", with little extra coding effort.

I also mentioned earlier that you can create custom authorization policies for your WCF services. These are types that implement the IAuthorizationPolicy interface from the System.IdentityModel.Policy namespace. Here are a few useful reasons to create a custom authorization policy:

The code sample for this article includes an advanced sample that illustrates an IAuthorizationPolicy implementation.

Impersonation
With all this talk about authentication and authorization, impersonation is worth discussing. When Windows credentials are used, the service can be configured to impersonate callers so that the request thread operates under the impersonated Windows token. This makes it possible for services to access protected Windows resources under the identity of the caller, instead of the process identity of the service—for that request.

Using the OperationBehaviorAttribute you can apply impersonation rules per operation by setting the Impersonation property to one of the following:

This behavior is applied to service operations.

 [OperationBehavior(Impersonation =
ImpersonationOption.Allowed)]
public string DoSomething()
{
...
}
You can also set this for all operations by declaratively configuring the impersonateCallerForAllOperations attribute for the service authorization behavior.

 <behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceAuthorization
impersonateCallerForAllOperations="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
Clients can also control impersonation, to prevent services from using their identity to access resources. Windows credentials have an AllowedImpersonationLevel property that can be set to one of the following:

None and Anonymous protect the caller's identity but aren't useful for authentication. Identify is the default and preferred setting since it allows services to identify the caller but disallows impersonation. Impersonate and Delegate will allow impersonation across one machine, or delegation with a Kerberos ticket, respectively.

You set the value on the proxy as follows:

 localhost.HelloIndigoServiceClient proxy = new
Client.localhost.HelloIndigoServiceClient();
...
proxy.ClientCredentials.Windows.AllowedImpersonationLevel =
TokenImpersonationLevel.Identification;
In a federated scenario, the service can require that client applications send a security token generated and signed by a specific, trusted identity provider.
Applied WCF Security
At this point you should have a pretty good idea of the security-related settings that affect how authentication, authorization and message protection are applied. You should also have a clearer picture of the authentication and authorization process, and the relevance of identities to and role-based security. Still, it helps to look at concrete examples that apply these security features.

If you take into consideration interoperability and the sheer number of custom situations disparate applications call for—it would be impossible to elaborate on every scenario. That said, in this section I'll walk you through some common situations that require different bindings, security settings, and authorization techniques, to give you an idea of how that maps to an implementation in the sample code for this article.




Intranet Applications
Internal applications that run on the intranet (and share the same Windows domain as the service) can generally take advantage of a faster transfer protocol like TCP. In terms of security settings, the following may apply:

Figure 2 illustrates this scenario. The NetTcpBinding service model configuration for this scenario is shown below.

 <system.serviceModel>
<services>
<service name="HelloIndigo.HelloIndigoService"
behaviorConfiguration="serviceBehavior">
<endpoint contract="HelloIndigo.IHelloIndigoService"
binding="netTcpBinding" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceAuthorization
impersonateCallerForAllOperations="false"/>
<serviceCredentials>
<windowsAuthentication
allowAnonymousLogons="false"
includeWindowsGroups="true" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
 
Figure 2: Intranet clients on the same Active Directory domain can rely on TCP protocol and use Windows credentials for mutual authentication and message protection.
The client binding configuration to consume this service is equivalent but the behaviors are local to the service. Windows credentials of the logged in user will automatically be passed by the client channel. If you use a login dialog to collect credentials, set the Windows credentials on the proxy this way:

 HelloIndigoServiceClient proxy = new
HelloIndigoServiceClient();
NetworkCredential creds = new NetworkCredential(
"username", "password", "domain");
proxy.ClientCredentials.Windows.AllowedImpersonationLevel =
TokenImpersonationLevel.Identification;
proxy.ClientCredentials.Windows.AllowNtlm = false;
proxy.ClientCredentials.Windows.ClientCredential = creds;
string s = proxy.HelloIndigo("some string");
Setting AllowNtlm to false prevents workgroup authentication from being supported, but you will want this enabled for testing outside of a domain environment.

Internet Applications
When remote clients are not part of the Windows domain, they use Internet protocols to access services (HTTP or HTTPS). The configuration settings in this case will vary based on many factors, including the type of protocols client applications can support.

To expose an endpoint that supports earlier Web service standards, WS-I Basic Profile is the typical baseline. Usually the same endpoint will support WS-I Basic Security Profile for security-related settings. So, the requirements of the service might be:

Figure 3 illustrates this scenario. The BasicHttpBinding service configuration that implements these requirements is shown in Listing 1.

 
Figure 3: A service exposing two endpoints to support BasicHttpBinding and WSHttpBinding. Both endpoints require UserName credentials and authenticate using ASP.NET providers.
This endpoint can only be accessed over HTTPS since transport transfer security is specified. Service authorization and authentication settings are specified in the <serviceBehaviors> section, but for this binding, the <serviceCertificate> is unused since HTTPS is used.

Using svcutil.exe a proxy is created for the service, and configuration settings for both bindings in Listing 1. Here is the code to consume the Basic Profile binding and specify the UserName credential in code.

 localhost.HelloIndigoServiceClient soap11proxy =
new BasicClient.localhost.HelloIndigoServiceClient(
"BasicHttpBinding_IHelloIndigoService");
soap11proxy.ClientCredentials.UserName.UserName = "Admin";
soap11proxy.ClientCredentials.UserName.Password = "p@ssw0rd";
string s = soap11proxy.HelloIndigo(
"Soap 1.1 endpoint using BasicHttpBinding.");
For clients that can support advanced Web services standards (WS*) a whole range of possible options exist. Still, a typical interoperable scenario might have these requirements:

Figure 3 illustrates the same service exposing a WSHttpBinding alongside a BasicHttpBinding endpoint. Listing 1 illustrates the binding configuration for WSHttpBinding. This endpoint shares <serviceBehavior> settings with the BasicHttpBinding endpoint, however in this case, since message transfer security is used, the <serviceCertificate> element is required.

Since the client configuration generated by svcutil.exe includes an encoded service certificate (discussed earlier) no changes are required to successfully invoke the service. The following code instantiates the proxy for the WSHttpBinding endpoint, and invokes the service with WS* protocols:

 localhost.HelloIndigoServiceClient soap12proxy =
new BasicClient.localhost.HelloIndigoServiceClient(
"WSHttpBinding_IHelloIndigoService");
soap12proxy.ClientCredentials.UserName.UserName = "Admin";
soap12proxy.ClientCredentials.UserName.Password = "p@ssw0rd";
string s = soap12proxy.HelloIndigo(
"Soap 1.2 endpoint using WSHttpBinding.");
Business Partner Applications
A business partner accessing your services over the Internet may require a different approach to authentication and authorization. Consider these requirements:

 
Figure 4: A service requiring Certificate credentials over WSHttpBinding. Authorized public key certificates should be installed in the LocalMachine certificate store under TrustedPeople.
Figure 4 illustrates this scenario and Listing 2 shows the required configuration settings for WSHttpBinding. Certificates can also be used with other bindings as a form of authentication.

The client configuration generated by svcutil.exe doesn't include information about the location of the client certificate. You must make a modification to the configuration on the client to add the following behavior and associate it to the client endpoint:

 <behaviors>
<endpointBehaviors>
<behavior name="clientBehavior">
<clientCredentials>
<clientCertificate findValue="SubjectKey"
storeLocation="CurrentUser" storeName="My"
x509FindType="FindBySubjectName"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Certificate credentials can also be useful for services authenticating across tiers behind the firewall.




Federated Security
It is impossible to include an in-depth discussion on federated security scenarios in this article, but it at least warrants an introduction to whet your appetite. In a federated scenario the service can require that client applications send a security token generated and signed by a specific, trusted identity provider (Figure 5).

 
Figure 5: Communication between client application, target service (relying party) and identity provider (token issuer) when the target service relies on SAML tokens issued by the trusted identity provider.
In some cases the identity provider is the same company as the target service—but they have decoupled token issuance from business services. The client application authenticates to the identity provider and requests a token for a particular subject (usually a user). The identity provider returns a signed and encrypted token that can be used for subsequent communications with the target service. It carries the claims requested if the subject is authorized, and the service can use this for a rich, claims-based authorization model.

For this situation, the target service may have the following requirements:

The service configuration for this scenario will use WSFederationHttpBinding—which allows you to specify which identity provider you require claims from, and which claims you expect the issued token to contain. An abbreviated version of this binding configuration is illustrated here:

 <wsFederationHttpBinding>
<binding name="wsFedBinding">
<security mode="Message">
<message issuedTokenType=
"http://docs.oasis-open.org/wss/oasis-wss-saml-
token-profile-1.1#SAMLV1.1" >
<claimTypeRequirements>
<add claimType=
"http://schemas.microsoft.com/ws/2005/05/identity/
claims/privatepersonalidentifier" isOptional="false"/>
...more claims...
</claimTypeRequirements>
<issuer address=
"http://localhost:2489/TokenIssuer/Service.svc"
binding ="wsHttpBinding" ... >
...
</issuer>
</message>
</security>
</binding>
</wsFederationHttpBinding>
There are many details that warrant discussion in a federated security scenario including the detailed implementation of the identity provider, authentication requirements to the provider, SAML token generation, authorization of claims and the use of custom IIdentity and IPrincipal objects to streamline authorization. You can gain insight into these details from the federated security code sample provided with this article.

Next Steps
You've probably gathered from the details in this article that there are many intricacies in WCF security. I have covered most of the security-related binding properties, and many behavioral settings for specific scenarios—and this will definitely get you on the right track. Beyond these topics, you will still want to explore security scenarios for some of the bindings that I have left out of this discussion for simplicity. These have overlapping uses for the concepts I've discussed here but also introduce more possibilities. In addition, federated security scenarios and Windows CardSpace each warrant a focused discussion since they are quite advanced and relatively new concepts to most. You can find many resources on these subjects on the .NET 3.0 community portal. Enjoy!

Michèle Leroux Bustamante is Chief Architect of IDesign Inc., Microsoft Regional Director for San Diego, Microsoft MVP for XML Web Services, and a BEA Technical Director. At IDesign, Michele provides training, mentoring, and high-end architecture consulting services focusing on WCF, CardSpace, Web services, interoperability, scalable and secure architecture design for .NET, and globalization architecture. She is a member of the International .NET Speakers Association (INETA), a frequent conference presenter, conference chair of SDs Web Services track, and is frequently published in several major technology journals. Michele is also on the Board of Directors for IASA (International Association of Software Architects), and Program Advisor to UCSD Extension. Her book, Learning Windows Communication Foundation (OReilly) is scheduled to release in late 2006. Read her blog at www.thatindigogirl.com.


© Copyright Component Developer Magazine and EPS Software Corp., 2009
DevX is a division of Internet.com.
© Copyright 2010 Internet.com. All Rights Reserved. Legal Notices