Step by Step Guide for Authenticating WCF Service with Username and Password over SSL

Here is a short step by step guide on how to get your WCF service to perform Message and Transport level security over SSL with user name and password. I ran into this recently and thought should document it along with source code to provide reference for the rest of us.

1. If your development machine is XP (or 2K3 server) and you need dev SSL cert installed on it, follow the instructions mentioned in the articles here. The SelfSSL makes it real easy to do self signed certificates, literally one statement.

Setting up SSL with a SelfSSL certificate on Windows Server 2003 (and XP)

Create a self-signed SSL certificate with IIS 6.0 Resource Kit SelfSSL

2. Create a WCF Service Project. Name the service and contracts appropriately. In my sample it is a simple contract like follows.

   [ServiceContract]
    public interface IWcfService
    {
        [OperationContract]
        string GetData(int value);
    }

Make sure you make the appropriate config changes matching with your service contract.

2. Add a custom validator class in your service. You can create a separate file for it. In this example I have added it to the main service file WcfService.svc.cs. You are going to need to add the reference (not just adding these lines at the top, go to add-reference and add the corresponding dll's to the project)

using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;

and the custom validator code.

public class CustomValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == "test" && password == "test")
                return;
            throw new SecurityTokenException(
                "Unknown Username or Password");
        }
    }

You probably want to make this user name and password moved to a more secure location or point to your database/authentication store for security and maintainability perspective.

3. Now the code part is done. Move to config file. Enable custom errors so you know details about the errors happening.

<customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">

4. Add a new bindings attribute in the config called SafeServiceConf which will specify the TransportWithMessageCredential type of security. You can add this right before </system.serviceModel>

<bindings>
<wsHttpBinding>
<binding name="SafeServiceConf" maxReceivedMessageSize="65536">
<readerQuotas maxStringContentLength="65536" maxArrayLength="65536"
maxBytesPerRead="65536" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<bindings>       <wsHttpBinding>          <binding name="SafeServiceConf" maxReceivedMessageSize="65536">             <readerQuotas maxStringContentLength="65536" maxArrayLength="65536"                maxBytesPerRead="65536" />             <security mode="TransportWithMessageCredential">                <message clientCredentialType="UserName" />             </security>          </binding>       </wsHttpBinding>    </bindings>

5. Modify your end point address to refer to this binding configuration

			<endpoint address="" binding="wsHttpBinding" contract="MySamples.IWcfService" bindingConfiguration="SafeServiceConf">

also modify your metadata exchange endpoint to use mexHttpsBinding

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

6. Modify your service behavior to look like this

				<behavior name="WcfService.Service1Behavior">
					<serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <userNameAuthentication
                 userNamePasswordValidationMode="Custom"
                 customUserNamePasswordValidatorType="MySamples.CustomValidator,WcfService"
                                                                          />

          </serviceCredentials>
        </behavior>

It's recommended that "Include exception in faults" should be disabled when moved to production.

7. Now you are almost ready to run the service however before you do this, make sure that you are running it in the IIS AND you have the SSL enabled on the server as specified in step 1 otherwise you'll run into WCF error stating that there is no HTTPS endpoint available.

Setup Virtual Directory in IIS from Visual Studio
Setup Virtual Directory in IIS from Visual Studio

You should be able to run and see the service end point as follows.

Running WCF Service over SSL
Running WCF Service over SSL
Running WCF Service over SSL 2
Running WCF Service over SSL 2

8. Now that the service is done, let's move towards building the client. Add the service reference to the service end point. You can do it either via entering the entire URL or using the discover feature.

Add WCF Reference
Add WCF Reference

9. Name your reference "Client" or modify your code appropriately. Following is the code for client implementation.

       private static void Main(string[] args)
        {
           ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(
                delegate { return true; });

            var client = new WcfServiceClient();
            GetCredentials();
            client.ClientCredentials.UserName.UserName = username;
            client.ClientCredentials.UserName.Password = password;
            Console.Write(client.GetData(1));
            client.Close();
            Console.Read();
        }

The RemoteCertificateValidationCallback part is used to programatically avoid the following warning which would popup due to self signed cert usage.

Certificate Warning
Self signed Certificate Warning

10. Now run the program.

Running WCF client
Running WCF client

You can see that for the right credentials, service will run just fine. Otherwise a security exception will be thrown.

Source code can be downloaded from here.WCFAuthSample

Feel free to drop me an email or comment here if you have any questions.

References and Further Readings:

How to: Authenticate with a User Name and Password

WCF Service over HTTPS with custom username and password validator in IIS

Chapter 5 – Authentication, Authorization and Identities in WCF

How to: Use Transport Security and Message Credentials

SecurityMode Enumeration

WCF: Could not establish trust relationship for the SSL/TLS secure channel with authority

Deploying an Internet Information Services-Hosted WCF Service

How messages are encrypted when security mode is "Message"?

Simple WCF - X509 Certificate

Windows HTTP Services Certificate Configuration Tool (WinHttpCertCfg.exe)

Setting up SSL with a SelfSSL certificate on Windows Server 2003 (and XP)

Create a self-signed SSL certificate with IIS 6.0 Resource Kit SelfSSL

Share