Saturday 22 March 2014

WCF Security

 Security in WCF

Windows Communication Foundation (WCF) security has three common security modes that are found on most predefined bindings: transport, message, and "transport with message credential." Two additional modes are specific to two bindings: the "transport-credential only" mode found on the BasicHttpBinding, and the "Both" mode, found on the NetMsmqBinding. However, this topic concentrates on the three common security modes: TransportMessage, and TransportWithMessageCredential.
Note that not every predefined binding supports all of these modes. This topic sets the mode with the WSHttpBinding and NetTcpBinding classes and demonstrates how to set the mode both programmatically and through configuration.
<security mode="Message/None/Transport/TransportWithMessageCredential">
   <transport
         clientCredentialType="Basic/Certificate/Digest/None/Ntlm/Windows"
      proxyCredentialType="Basic/Digest/None/Ntlm/Windows"
      realm="string" 
      defaultClientCredentialType="Basic/Certificate/Digest/None/Ntlm/Windows"
      defaultProxyCredentialType="Basic/Digest/None/Ntlm/Windows"
      defaultRealm="string" />
   <message
            clientCredentialType="Certificate/IssuedToken/None/UserName/Windows"
      algorithmSuite="Basic128/Basic192/Basic256/Basic128Rsa15/Basic256Rsa15/TripleDes/TripleDesRsa15/Basic128Sha256/Basic192Sha256/TripleDesSha256/Basic128Sha256Rsa15/Basic192Sha256Rsa15/Basic256Sha256Rsa15/TripleDesSha256Rsa15"
       establishSecurityContext="Boolean" 
      negotiateServiceCredential="Boolean"/>
</security>

To set the security mode in code

  1. Create an instance of the binding class that you are using. For a list of predefined bindings, see System-Provided Bindings. This example creates an instance of theWSHttpBinding class.
  2. Set the Mode property of the object returned by the Security property.
    WSHttpBinding b = new WSHttpBinding();
    b.Security.Mode = SecurityMode.Transport;
    
    
    Alternatively, set the mode to message, as shown in the following code.
    WSHttpBinding b = new WSHttpBinding();
    b.Security.Mode = SecurityMode.Message;
    
    
    Or set the mode to transport with message credentials, as shown in the following code.
    WSHttpBinding b = new WSHttpBinding();
    b.Security.Mode = SecurityMode.TransportWithMessageCredential;
    
    
  3. You can also set the mode in the constructor of the binding, as shown in the following code.
    WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
    
    

Setting the ClientCredentialType Property

Setting the mode to one of the three values determines how you set the ClientCredentialType property. For example, using the WSHttpBinding class, setting the mode toTransport means you must set the ClientCredentialType property of the HttpTransportSecurity class to an appropriate value.

To set the ClientCredentialType property for Transport mode

  1. Create an instance of the binding.
  2. Set the Mode property to Transport.
  3. Set the ClientCredential property to an appropriate value. The following code sets the property to Windows.
    WSHttpBinding b = new WSHttpBinding();
    b.Security.Mode = SecurityMode.Transport;
    b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
    
    

To set the ClientCredentialType property for Message mode

  1. Create an instance of the binding.
  2. Set the Mode property to Message.
  3. Set the ClientCredential property to an appropriate value. The following code sets the property to Certificate.
    WSHttpBinding b = new WSHttpBinding();
    b.Security.Mode = SecurityMode.Message;
    b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
    
    

To set the Mode and ClientCredentialType property in configuration

  1. Add an appropriate binding element to the <bindings> element of the configuration file. The following example adds a <wsHttpBinding> element.
  2. Add a <binding> element and set its name attribute to an appropriate value.
  3. Add a <security> element and set the mode attribute to MessageTransport, or TransportWithMessageCredential.
  4. If the mode is set to Transport, add a <transport> element and set the clientCredential attribute to an appropriate value.
    The following example sets the mode to "Transport", and then sets the clientCredentialType attribute of the <transport> element to "Windows".
    <wsHttpBinding>
    <binding name="TransportSecurity">
        <security mode="Transport" />
           <transport clientCredentialType = "Windows" />
        </security>
    </binding>
    </wsHttpBinding >
    
    Alternatively, set the security mode to "Message", followed by a <"message"> element. This example sets the clientCredentialType to "Certificate".
    <wsHttpBinding>
    <binding name="MessageSecurity">
        <security mode="Message" />
           <message clientCredentialType = "Certificate" />
        </security>
    </binding>
    </wsHttpBinding >
    
    Using the TransportWithMessageCredential value is a special case, and is explained below.

Using TransportWithMessageCredential

When setting the security mode to TransportWithMessageCredential, the transport determines the actual mechanism that provides the transport-level security. For example, the HTTP protocol uses Secure Sockets Layer (SSL) over HTTP (HTTPS). Therefore, setting the ClientCredentialType property of any transport security object (such asHttpTransportSecurity) is ignored. In other words, you can only set the ClientCredentialType of the message security object (for the WSHttpBinding binding, theNonDualMessageSecurityOverHttp object).
Value
Description
None
Security is disabled.
Transport
Security is provided using HTTPS. The service needs to be configured with SSL certificates. The message is entirely secured using HTTPS and is authenticated by the client using the service’s SSL certificate. The client authentication is controlled through theClientCredentials attribute. of the <transport> of <wsHttpBinding>.
Message
Security is provided using SOAP message security. By default, the SOAP body is Encrypted and Signed. This mode offers a variety of features, such as whether the service credentials are available at the client out of band, the algorithm suite to use, and what level of protection to apply to the message body through the Security.Message property. Client authentication is performed once per session and the results of authentication are cached for the duration of the session.
TransportWithMessageCredential
In this mode, HTTPS provides integrity, confidentiality, and server authentication, and SOAP message security provides client authentication. By default, client authentication is performed once per session and the results of authentication are cached for the duration of the session.

Using the code

wshttpbinding:  A secure binding for HTTP transport applications
The WSHttpBinding
class is designed for interoperation with services that implement WS-*
specifications. The transport security for this binding is Secure Sockets Layer
(SSL) over HTTP, or HTTPS.
You can go through the web.config file in the project folders which I have uploaded.
<system.serviceModel>
 <services>
   <service behaviorConfiguration="returnFaults" name="TestService.Service">
      <endpoint binding="wsHttpBinding" bindingConfiguration=
            "TransportSecurity" contract="TestService.IService"/>
      <endpoint address="mex" binding="mexHttpsBinding" 
            name="MetadataBinding" contract="IMetadataExchange"/>
  </service>
 </services>
 <behaviors>
   <serviceBehaviors>
    <behavior name="returnFaults">
     <serviceDebug includeExceptionDetailInFaults="true"/>
       <serviceMetadata httpsGetEnabled="true"/>
       <serviceTimeouts/>
   </behavior>
  </serviceBehaviors>
 </behaviors>
 <bindings>
    <wsHttpBinding>
       <binding name="TransportSecurity">
             <security mode="Transport">
              <transport clientCredentialType="None"/>
              </security>
        </binding>
      </wsHttpBinding>
 </bindings>
 <diagnostics>
  <messageLogging logEntireMessage="true" 
    maxMessagesToLog="300" logMessagesAtServiceLevel="true" 
    logMalformedMessages="true" logMessagesAtTransportLevel="true"/>
  </diagnostics>
 </system.serviceModel>

//Contract Description
[ServiceContract]
interface IService
{
  [OperationContract]
   string TestCall();
}

//Implementation
public class Service:IService
{
  public string TestCall()
  {
      return "You just called a WCF webservice On SSL
                    (Transport Layer Security)";
  }
}

//Tracing and message logging
<system.diagnostics>
  <sources>
      <source name="System.ServiceModel" 
    switchValue="Information,ActivityTracing" propagateActivity="true">
         <listeners>
           <add name="xml"/>
        </listeners>
      </source>
        <source name="System.ServiceModel.MessageLogging">
        <listeners>
            <add name="xml"/>
         </listeners>
         </source>
    </sources>
        <sharedListeners>
          <add initializeData="C:\Service.svclog" 
        type="System.Diagnostics.XmlWriterTraceListener" name="xml"/>
         </sharedListeners>
       <trace autoflush="true"/>
</system.diagnostics>
In the above ServiceModel configuration, there are two end points:
  1. One with contract TestService.IService: In this, binding is configured to have transport layer security , see inside the <bindings> tag. So SSL has to be configured on IIS.
  2. One with contract IMetadataExchange: this is also configured to an HTTPS call. If you see the binding it ismexHttpsBinding, and in the service behaviors section, httpsGetEnabled is used, here I tried to even secure the metadata publishing through WSDL.
To configure this Web.config file you can use SvcConfigEditor.exe which is located in C:\program files\microsoft sdks\windows\v6.0\bin\svcconfigeditor.exe
If you try to run the code from Visual Studio then you get an exception as shown below: "Could not find a base address that matches scheme HTTPS for the endpoint with binding WSHttpBinding. Registered base address schemes are [HTTP]."
So first configure the website on SSL. To get an idea on how to configure SSL, you can go through this. Make sure that when you configure the SSL, the certificate CN value should be exactly the same as the URL of the website. For example, if your webservice address is http:\\www.example.com, then issue a certificate on the name : CN = http:\\www.example.com.
Don't forget to host an entry in the hosts file c:\windows\system32\drivers\etc\hosts. If you want to put this on localhost then just enter the following in the host file 127.0.0.1 www.example.com.
Configure www.example.com as the header value in the website properties on port 80. Once you are done with SSL, you will access the webservice through the web browser as https://www.example.com/service.svc. On this page you will have the HTTPS URL for WSDL .
I have even enabled tracing and message logging on the webservice. To view the service log just usesvctraceviewer.exe by loading service.log file in this. See the <system.diagnostics> tag above
Note that I have not put any certificates to run this sample. So if you want to run this sample, then generate a certificate, install it on IIS as per the instructions above and run it though the browser. To get an idea how to generate self certificates for testing purposes just go through this link.
To run this project you need to have IIS 6.0 on your machine. On IIS 5.0 also you can do that, but it needs to be configured to run WCF services.
Hope this article helps you get a good idea about WCF transport layer security and SSL. If you have any question or comments please email me, I would really appreciate it. Thanks.

4 comments: