Thursday, May 20, 2010

6 steps to implement DUAL security on WCF using User name + SSL


Introduction and Goal
Basics Transport and Message level security
Step 1:- Customize ‘WsHttp’ Bindings with security mode and credential type
Step 2:- Create your custom validator class
Step 3:- Define runtime behavior
Step 4:- Define SSL for your WCF service
Step 5 :- Consume WCF Service
Step 6: Run your WCF service

Introduction and Goal

In the article we will try to apply DUAL security using transport plus message on WCF services. So we will first try to understand the basic concepts of WCF security i.e. transport and message. Once we understand the concept we will move step by step in to how to implement SSL and user name security on WCF services.
Watch my 500 videos on various topics like design patterns,WCF, WWF , WPF, LINQ ,Silverlight,UML, Sharepoint ,Azure,VSTS and lot more @ click here , you can
also view my WCF videos Part :-1 and Part:- 2
Enjoy my free ebook which covers major .NET related topics like WCF,WPF,WWF,Ajax,Core .NET,SQL Server, Architecture and lot more Download from here



Basics Transport and Message level security

On a broader basis WCF supports two kinds of security, transport level and message level security. Transport means the medium on which WCF data travels while message means the actual data packets sent by WCF. Transport medium can be protocols like TCP, HTTP, MSMQ etc. These transport mediums by themself provide security features like HTTP can have SSL security
(HTTPS). WCF has the capability of leveraging underlying transport security features on WCF service calls.

Message level security is provided in the data itself using WS-Security. In other words it’s independent of the transport protocol. Some examples of message level security are messages encrypted using encryption algorithm, messages encrypted using X509 certificate etc, messages protected using username etc.

WCF gives you an option to either just use message level security in stand alone, transport level in stand alone or combination of both. If you are interested in how to do message level security and transport security in a standalone manner you can read more from here.



The best security is the combination of transport and message. In this article we will see step by step how to implement dual security using ‘SSL’ plus message security using ‘Username’ using ‘WsHttpBinding’.

Step 1:- Customize ‘WsHttp’ Bindings with security mode and credential type

The first step is to customize your ‘Wshttp’ binding with proper security mode and credential type. There are three options in security mode ‘Transport’, ‘Message’ and ‘TransportWithMessageCredential’.

As we are implementing dual security we need to use the last one i.e. ‘TransportWithMessageCredential’ where the transport security is provided by SSL and message security is provided using ‘UserName and password’.


The second thing we need to provide is the credential type. There are five different credential type none, windows, username, certificate and issued token. Credential type defines how the credentials will be passed over the transport layer. For the current instance we will select ‘UserName’.


So summing up we will provide security mode as ‘TransportWithMessageCredential’ and message security will be provided by ‘UserName’.

So create a WCF service using the WCF service template and in ‘web.config’ provide the security mode and credential type as shown in the below code snippet.
<bindings>

<wsHttpBinding>

<binding name="Binding1">
<!-- UsernameToken over Transport Security -->

<security mode="TransportWithMessageCredential" >
<message clientCredentialType="UserName"/>

</security>

</binding>

</wsHttpBinding>

</bindings>



Step 2:- Create your custom validator class

Once we have customized the ‘WsHttp’ binding with security mode and credential type it’s time to create the custom class which will do authentication of the user name provided.

In order to create your custom class you need inherit the ‘UserNamePasswordValidator’ class which belongs to ‘System.IdentityModels.Selector’.


Below goes the code snippet of ‘MyValidator’ class. We need to override the ‘Validate’ method with the authentication logic as shown below.
class MyValidator : UserNamePasswordValidator
{

public override void Validate(string userName, string password)
{

if ((userName == "shiv123") && (password == "pass123"))
{

}
else
{
throw new FaultException("Invalid credentials");
}
}
}
If the credentials are not proper we have raised the ‘FaultException’ error which can be caught by the WCF client to display error messages.

Step 3:- Define runtime behavior


So we are almost 50% through now. We have customized the ‘WsHttp’ binding and created our custom class ‘MyValidator’ which will do the necessary authentication. The next step is to define behavior.

‘Behaviors’ define customized run time logic over the binding agreement. Currently we need to execute ‘MyValidator’ class logic for the ‘UserName’ provided in the WCF service by WCF client.


To specify the behavior go to your ‘Web.config’ file and in the ‘servicecredentials’ tag specify the ‘userNameAuthentication’ tag which points to the custom class ‘MyValidator’.
<behaviors>
<serviceBehaviors>

<serviceCredentials>

<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyValidator, app_code"/>

</serviceCredentials>
</behavior>

Step 4:- Define SSL for your WCF service


We have already mentioned transport security will be provided by SSL while message security will be provided by ‘username’. We have already configured ‘UserName’ message security using ‘MyValidator’ class which is specified in the behavior section of ‘web.config’ file. The next step is to configure SSL i.e. transport security for our WCF service.

We will be using ‘makecert.exe’ which is a free tool given by Microsoft to enable HTTPS for testing purpose. MakeCert (Makecert.exe) is a command-line tool that creates an X.509 certificate that is signed by a system test root key or by another specified key. The certificate binds a certificate name to the public part of the key pair. The certificate is saved to a file, a system certificate
store, or both.

You can get the same from “C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin” or you can also get it from windows SDK.

You can type the below thing through your dos prompt on “C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin”. Please note “compaq-jzp37md0” is the server name so you need to replace with your PC name.

makecert -r -pe -n "CN= compaq-jzp37md0 " -b 01/01/2000 -e 01/01/2050 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr
localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
If you run the same through your command prompt you should get a succeeded message as shown below.

Now it’s time to assign this certificate to your IIS website. So go to IIS properties, click on directory security tab and you should see server certificate tab.


So click on the server certificate tab and you will then be walked through an IIS certificate wizard. Click ‘Assign an existing certificate’ from the wizard.

You can see a list of certificates. The “compaq-jzp37md0” certificate is the one which we just created using ‘makecert.exe’.

Now try to test the site without ‘https’ and you will get an error as shown below….That means your certificate is working.

Do not forget to enable IIS anonymous access.

We also need to make couple of changes in the WCF service ‘Web.config’ ‘endpoint’ section as shown below. You can see how the address points to HTTPS and binding uses ‘mexHttpsBinding’.
<service name="Service" behaviorConfiguration="ServiceBehavior">

<endpoint address="https://localhost/Service.svc" binding="wsHttpBinding" contract="IService" bindingConfiguration="Binding1">

<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>

</service>

Step 5 :- Consume WCF Service

It’s time to consume WCF the service application. So click on add service reference and specify your service URL. You will be shown a warning box as shown in the below figure as the certificate is a test certificate. So just let it go.


The next step is to create WCF proxy client object and pass the credentials as shown in the below snippet.
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(IgnoreCertificateErrorHandler);
ServiceReference1.ServiceClient obj = new ServiceReference1.ServiceClient();
obj.ClientCredentials.UserName.UserName = "shiv123";
obj.ClientCredentials.UserName.Password = "pass123";
Response.Write(obj.GetData(12));
‘makecert.exe’ creates test certificates. In other words it’s not signed by CA. So we need to suppress those errors in our ASP.NET client consumer. So we have created a function called as ‘IgnoreCertificateErrorHandler’ which return true even if there are errors. This function is attached as a callback to ‘ServicePointManager.ServerCertificateValidationCallback’ as shown in the above
code snippet.
public static bool IgnoreCertificateErrorHandler(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}


Step 6: Run your WCF service

If everything goes appropriate you should be able to run the WCF service. Try changing the use rid and password to something else you should get the fault exception message provided in the ‘MyValidtor’ class.