WCF Application Implementing the Anonymous Client over Certificate WS-Security scenario

1. Introduction

 
This article explains the techniques, architecture and design strategies in order to address one of the most common scenarios of secure communication in Internet, the
Anonymous client over Certificate WS-Security scenario using the message level security mechanisms.
 
In this example, we have a service which provides its authentication and the underlying security services (signature, encryption) using X509 digital certificates. The client in that case trusts in the service.
 

2. WS-Security specifications

 
Web Services Security (WS-Security) is a family of specifications which addresses the main security services such as message integrity, message confidentiality and authentication. In figure 1, you can see the WS-Security architecture.
 
WCF1.jpg 
Figure 1. WS-Security architecture.
 
The WS-Security 1.1 was recently approved as an OASIS standard. You can read the whole specification in OASIS site.
 
WS-Security is not meant to replace any existing security technologies such as SSL, instead WS-Security leverages and federates existing security infrastructures and provides a unified model for security services. SSL was designed for point-to-point communications, but in one scenario where end-to-end security for the entire message path is required, we need to use WS-Security. SSL was designed for protecting the messages on the wire but it doesn't provide protection on the endpoints. And finally, because Web services integrate multiple systems within different security domains and platforms, thus we need for a mechanism to translate or exchange security information from one domain to another. WS-Security is flexible and fits in different security models. SSL doesn't meet these requirements.
 

3. Anonymous client over Certificate scenario

 
In this scenario, the service and the client trust each other, the service authenticates to the client, and the interaction between them is encrypted and signed. In addition, all security must be implemented using a message-based security approach. In figure 2, it is illustrated this scenario.
 
WCF2.gif 
Figure 2. Anonymous client over Certificates.
 

4. Requirements elements

 
For this example, we need to generate the private/public key pairs for the service, then create a Certificate Signing Request with the information associated to the service, and then send the Certificate Signing Request to a Certificate Authority and receive an X509 digital certificate of the service signed by a Certificate Authority. We also need the Certificate Authority's certificate and to store the service's private key along with the digital certificate in the Windows Certificate Store.
 
In other article, I can tell you how you can do all these steps using the command openssl. For now, you can use the CA service shipped in Windows 2003.
 
4.1 Importing the CA's digital certificate into the server and client machine into the Trusted Root Certification Authorities Certificate store.
 
Browse to the CA's digital certificate file (Figure 3.)
 
WCF3.gif 
Figure 3.
 
And then, place the certificate in the Trusted Root Certification Authorities Certificate store. (Figure 4.)
 
WCF4.gif 
Figure 4.
 
A Security Warning message tells if you trust in this CA certificate (Figure 5.) Push the Yes button.
 
WCF5.gif 
Figure 5.
 
4.2 Importing the service's private/public key pairs into the Windows Certificate Store in the server machine.
 
In Figure 6, we browse to the directory where the service.pfx file is located. This file contains the private keys protected with a password, and the public digital certificate signed by the CA.
 
WCF6.gif 
Figure 6.
 
Next, type the passphrase which protects the private key (Figure 7)
 
WCF7.gif 
Figure 7.
 
And then, place the certificate in the Personal Certificate Store (Figure 8)
 
WCF8.gif 
Figure 8.
 

5. Implementing the Service

 
Our example comprises two components, the service which exposes simple functionality such as adding two numbers, and a client which consumes the service.
 
First of all, we must define the contract of the service. This is the interface of the service with the outside. The contract is defined using the annotations ServiceContractAttribute and the OperationContractAttribute attributes. See listing 1.
  1. namespace WCFServiceLibrary  
  2. {  
  3.     [ServiceContract()]  
  4.     public interface ICalculate  
  5.     {  
  6.         [OperationContract]  
  7.         int Add(int nParam1, int nParam2);  
  8.     }  
  9. }  
Listing 1. The service contract.
 
The realization of this interface is done by the class Calculator. See listing 2.
  1. namespace WCFServiceLibrary  
  2. {  
  3.     public class Calculator : ICalculate  
  4.     {  
  5.         #region ICalculate Members  
  6.         public int Add(int nParam1, int nParam2)  
  7.         {  
  8.             return nParam1 + nParam2;  
  9.         }  
  10.         #endregion  
  11.     }  
  12. }  
Listing 2. The service class realizing the ICalculator interface.
 
And finally, we have the following configuration. See listing 3. The service element which is subelement of services element defines the service behavior that in our case we are providing metadata information by HttpGet method (?wsdl way to access to the service description) and the service is providing a proof of identity through a digital certificate found in the LocalMachine's Personal Certificate Store.
 
The wsHttpBinding element which is subelement of bindings elements defines the message level security requirements and that the client is anonymous.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.             <services>  
  5.                      <service behaviorConfiguration="ServiceCredentialsBehavior"  
  6.                                          name="WCFServiceLibrary.Calculator">  
  7.                                <endpoint address=" http://johndeveloper.mydomain.com:8080/myservices/Calculator.svc"  
  8.                                                           binding="wsHttpBinding"  
  9.                                                          bindingConfiguration="WSHttpBinding_ICalculator"  
  10.                                                           name="Calculator"                                                          contract="WCFServiceLibrary.ICalculate" />  
  11.                      </service>  
  12.             </services>     
  13.       <behaviors>  
  14.         <serviceBehaviors>  
  15.           <behavior name="ServiceCredentialsBehavior">  
  16.                               <serviceMetadata httpGetEnabled="true" />  
  17.              <serviceCredentials>  
  18.                <serviceCertificate x509FindType="FindBySubjectName"   
  19.                                                       findValue="johndeveloper.mydomain.com"  
  20.                                 storeLocation="LocalMachine"  
  21.                                 storeName="My" />  
  22.                </serviceCredentials>  
  23.           </behavior>  
  24.         </serviceBehaviors>  
  25.       </behaviors>  
  26.             <bindings>  
  27.               <wsHttpBinding>  
  28.                      <binding name="WSHttpBinding_ICalculator" >  
  29.                        <security mode="Message">  
  30.                                <message clientCredentialType="None" />  
  31.                        </security>  
  32.                      </binding>  
  33.               </wsHttpBinding>  
  34.             </bindings>  
  35.     <client />  
  36.   </system.serviceModel>  
  37. </configuration>  
Listing 3. The service configuration.
 

6. Implementing the Client

 
The first step to consume the Web Service explained in the previous section is generating the service proxy. In our case, we are going to use the svcutil.exe utility. Type the following command
 
svcutil.exe http://johndeveloper.mydomain.com:8080/myservices/Calculator.svc?wsdl
 
Now we create the program that creates one instance of the proxy, and calls for the service. See listing 4.
  1. namespace WCFClient  
  2. {  
  3.     class Program  
  4.     {  
  5.         static voidMain(string[] args)  
  6.         {  
  7.             CalculateClient objProxy = new CalculateClient();  
  8.             int nResult = objProxy.Add(1, 2);  
  9.             System.Console.WriteLine("The result is {0}",nResult);  
  10.         }  
  11.     }  
  12. }  
Listing 4.
 
And finally, we have the following configuration. See listing 5. The endpoint element which is subelement of client element defines the address to access the service, the identity of the service by dns. The behavior element defines that the clients expects to receive a proof of identity from the service through a digital certificate, that the validation is done by the chain of trust of the receiving certificate, in our case the certificate is validated by the CA's digital certificate that resides in the client's Trusted Root Certification Authorities Certificate store, as well as we say that the clients don't check any revocation list.
 
And finally, the wsHttpBinding element which is subelement of bindings elements defines the message level security requirements and that the client is anonymous.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <configuration>  
  3.           <system.serviceModel>  
  4.                    <bindings>  
  5.                              <wsHttpBinding>  
  6.                                       <binding name="Calculator">  
  7.                                                 <security mode="Message">  
  8.                                                           <message clientCredentialType="None" />  
  9.                                                 </security>  
  10.                                       </binding>  
  11.                              </wsHttpBinding>  
  12.                    </bindings>  
  13.                    <behaviors>  
  14.                              <endpointBehaviors>  
  15.                                       <behavior name="CalculatorBehConf">  
  16.                                                 <clientCredentials>  
  17.                                                           <serviceCertificate>  
  18.                                                                    <authentication revocationMode="NoCheck"   
  19.                                        certificateValidationMode="ChainTrust"/>  
  20.                                                           </serviceCertificate>  
  21.                                                 </clientCredentials>  
  22.                                       </behavior>  
  23.                              </endpointBehaviors>  
  24.                    </behaviors>            
  25.                    <client>  
  26.                              <endpoint address=" http://johndeveloper.mydomain.com:8080/myservices/Calculator.svc"  
  27.                              binding="wsHttpBinding" bindingConfiguration="Calculator"  
  28.                              behaviorConfiguration="CalculatorBehConf"  
  29.                              contract="ICalculate" name="Calculator">  
  30.                                       <identity>  
  31.                                                 <dns value="johndeveloper.mydomain.com "/>  
  32.                                       </identity>  
  33.                              </endpoint>  
  34.                    </client>  
  35.           </system.serviceModel>  
  36. </configuration>  
Listing 5. The configuration file for the client.
 

7. Conclusion

 
This article explains how it is possible to implement the Anonymous client over Certificate WS-Security scenario using Windows Communication Foundation, as well as straightforward description of the use of digital certificates.


Similar Articles