Use Windows Authentication on WCF service behind a SSL handler

After my last blog post about using Cert-based Message security for WCF web service, we started to look into using Windows Authentication for a different system that also sits behind a load balancer/SSL handler. Windows Authentication provides a much easier integration option – client side can simply provide a domain user account to be authenticated, where as in Cert-based authentication, each client needs to install a certificate. This increases difficulties for clients to develop against the service and is our motivation to look into utilizing Windows Authentication instead.

With the experience of cert-based authentication, I was pretty sure it wasn’t going to be easy to use Windows Authentication in a load balanced environment. First thing we tried of course is to follow Microsoft’s guide to use wsHttpBinding with Windows Authentication and Message Security, with one different is that our client needs to use Transport security instead of Message because it must use HTTPS.

Like we thought, this setup didn’t work because the service expect to use Message security but the client is using Transport security. We then tried TransportWithMessage credential and some other settings. None of them works. We were stuck on this error message “The HTTP request is unauthorized with client authentication scheme ‘Ntlm’. The authentication header received from the server was ‘Negotiate,NTLM’.“, which unfortunately is one of those error messages that do not make sense.

In the painful process of pursuing truth, we came across some post raising the problem level to the load balancer level, which discouraged us to keep researching. It seemed more reasonable to find an alternative at that point, and we did find out that using BasicHttpBinding with Windows Authentication and TransportCredentialOnly worked in our environment.

Here is our client setup:

<basicHttpBinding>
  <binding name="BasicHttpBinding">
   <security mode="Transport">
    <transport clientCredentialType="Basic" />
   </security>
  </binding>
</basicHttpBinding>

Service setup:

<basicHttpBinding>
  <binding name="BasicHttpEndpointBinding">
    <security mode="TransportCredentialOnly">
      <transport clientCredentialType="Basic"/> 
    </security>
  </binding>
 </basicHttpBinding>

The problem with this is that the credentials of the client is passed in clear text. Although message before the land balancer is protected by HTTPs, still we want a true end-to-end protection on the credentials. So this solution is off the table. We decided to go back to our original plan.

I will just skip to the end of the story because I like magic!… We eventually found a solution that worked in the load balanced environment. Custom binding once again saved the world! I didn’t find any article about this configuration, which makes it more important to share it with everyone.

Client side:

 <customBinding>
  <binding name="customBinding_WindowsAuth">
    <textMessageEncoding>
      <readerQuotas />
    </textMessageEncoding>
    <security authenticationMode="SspiNegotiated"></security>
    <httpsTransport  authenticationScheme="Anonymous"  
      proxyAuthenticationScheme="Anonymous" useDefaultWebProxy="true">
    </httpsTransport>      
  </binding>
</customBinding>

Service side:

<wsHttpBinding>
 <binding name="WsBindingConfigration" >      
   <security mode="Message">
     <message clientCredentialType="Windows" 
     negotiateServiceCredential="true" algorithmSuite="Default" 
     establishSecurityContext="false"/>
   </security>
 </binding>
</wsHttpBinding>

Use Message security on WCF service behind a SSL handler

Configuring WCF web service’s security is just tedious. Microsoft has been trying to make it simple by removing many configuration settings in .NET 4.5 but it could still get messy if you need to touch the security part – There are many bindings and there are Message, Transport, and TransportWithMessageCredentials security modes, each with their own client credential types, not mentions all those authentication modes for Custom Bindings such as AnoymousForCertificate, IssuedTokenForCertificate, IssuedTokenOVerTransport, etc.

Developers are developing WCF web service on the platform from Microsoft. They are the users of the platform in this sense. It’s supposed to be user friendly and intuitive. But I found it is quite difficult to select the right security configuration in different scenarios. Even after you read the documentation from Microsoft carefully, you sill have a very limited idea on how these security modes differentiate from each other.

This post is aimed to cover one small scenario of using WCF security – using a WCF web service with cert-based Message security behind a front-end SSL handler. Often times, your web servers are behind a load balancer that handles all SSL requests and pass in HTTP requests to your IIS. Below is diagram showing the infrastructure.

8-8-2014 4-17-55 PM

At first glance, it seems pretty straightforward – Transport security mode covers SSL security, Message security mode handles message encryption. Hey there is a security mode just for the two modes combined: TransportWithMessageCredentials . We should be able to just use that on both client and service side to achieve what we want, right? However, you just can’t be so optimistic in the world of software development.

This configuration won’t working. First of all, since the service is not really receiving HTTPS requests, Transport mode should not be used. We just need Message security. So below is the correct configuration on service side.

<wsHttpBinding>
     <binding name="WsBindingConfigration">
     <security mode="Message">
      <message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="false"/>
     </security>
    </binding>
  </wsHttpBinding>

The client side is where it gets tricky. I can’t really explain why TransportWihtMessageCredential doesn’t work. Something goes wrong under the hood. But here is the configuration worked for me. Use MutualSSLNegotiated mode and CustomBinding!

<customBinding>
        <binding name="customBinding_CertAuth_ClientService">
           <security authenticationMode="MutualSslNegotiated">
           </security>
           <httpsTransport authenticationScheme="Anonymous"
proxyAuthenticationScheme="Anonymous" useDefaultWebProxy="true">
           </httpsTransport>
        </binding>
</customBinding>

It took me a long while to research and trial and error to finally figure this out. Many development teams don’t have the time to mirror the environments of their clients, which makes finding and troubleshooting issues like this difficult. But hopefully this post can help you out.

 

Assign permission on a certificate for an ApplicationPoolIdentity account

If your web application is running under ApplicationPoolIdentity account, you must have had the headache of configuring permission to this account. The trick of using IIS APPPOOL\Name has never worked for me. In order to find this user in the permission configuration window, I have been running ICACLS commend every time. This post has more detail on both approaches.

Now if your ApplicationPoolIdentity-using-web-application utilizes some certificate to encrypt/decrypt messages, such as a WCF web service with message level security based on certificate, you would have to figure out how to assign permission on this certificate to your ApplicationPoolIdentity user.

It is actually similar with assigning permission to some other file in that way that you can either use the IIS APPPOOL\Name method or using ICACLS command as described in the post mentioned above. However, if the IIS APPPOOL\Name approach does not work for you, ICACLS approach requires a file path in order to add this user account. The cert is usually stored somewhere deep and is under a different name than your original cert, which makes it difficult to be found.

HOW TO FIND THE PATH TO THE CERT? 

First you need a tool called FindPrivateKey.exe from Microsoft. It is funny because you can’t find a download link directly for this executable. It is actually a part of a sample code solution for WCF services. Here is the link to the source codes. Unzip it and compile the project from the folder C:\WF_WCF_Samples\WCF\Setup\FindPrivateKey\. After the compilation, you will have the executable!

This tool can help you find the actual file location of you cert with the cert’s Thumbprint. To find the thumbprint, open Microsoft Management Console.

Image

Add the Certificates snap-in

Image

Image

You should be able to find your cert somewhere

Image

Right click it, select Open. Click on the Details tab in the Certificate dialog. You should be able to find the Thumbprint of your cert.

Image

Now with the thumbprint, run the following command in command line prompt. Note that in the example, I tried to retrieve the cert’s for the local machine. See this page for more details on this tool. 

>FindPrivateKey my localmachine -t ” THUMBPRINT

It will return the folder and name of your cert!

Image

Now a simple ICACLS command can grant the permission needed to our cert.

Image

Fix WCF AddressFilter mismatch error when hosted behind load balancer

Weeks ago we had an issue with WCF web service hosted behind a load balancer that does address redirection and SSL handling. The error message is

“The message with To ‘https://Your/WCF/Service.svc ‘ cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher.  Check that the sender and receiver’s EndpointAddresses agree.”

Basically this means that your WCF service hosted behind the load balancer does not recognize the request, because the request’s “TO” address, which is a public facing address pointing to the load balancer, does not match the EndpointAddress of your WCF service, which comes from the IIS base address/host headers on the actual web server (where the load balancer will eventually redirect the request)

This checking mechanism of WCF is called AddressFilter, which is default to be turned on. So to fix the issue, add this line of code above each service to turn it off:


[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]

This is a quick and easy fix, but if you have a big number of services, creating a custom behavior to change the default AddressFilter is more feasible. Check the first link in the reference for detail of how to do that.

References:

Fix WCF AddressFilter mismatch error, customized IServiceBehavior , WCF service behind Load balancer or Firewall

Address Filter mismatch – WCF addressing

OperationContext.Current is Null

Today I tried to run a past WCF project and it refused to work. The error message was OperationContext.Current is null. The project uses a third-party written WCF custom encoder that enables SOAP with Attachment, so it made that harder to debug the issue. After struggled with it the whole day, I was surprised to find that the issue was because of a WS-Addressing Action mismatch between my client and service. It turned out that in a certain version of codes I modified the action name of both client and service and today my codes were not at the latest version thus the client and service were having different action values.

What was misleading was that the error message didn’t mention anything about the action. It only said about OperationContext.Current being null. And I have explicitly used OperationContext at my client side:

PayloadsSoapClient Client = new PayloadsSoapClient("CustomBinding_PayloadsSoap_Swa");
using (OperationContextScope scope = new OperationContextScope(Client.InnerChannel))

And the code below shows the contract and binding used by this client:

 <client>
      <PayloadsSoap name="CustomBinding_PayloadsSoap_Swa"/>
</client>

The client is using a contract “PayloadsSoap” and that is where the issue comes from. On client side we have set the WS-Addressing as http://tempuri.org/service1. (OperationContractAtrribute.Action) which should match the same property from service side. Below is the client side contract.

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://tempuri.org", 
ConfigurationName="PayloadsSoap")]
public interface PayloadsSoap
{
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/service1", 
ReplyAction="http://tempuri.org/service1Response")]
service1Response service1(service1Request request);
}

Note: The OperationContractAttribute.ReplyAction above defines the value of SOAP action and a mismatch in that does not cause the issue I have.

I have also run a few tests after having identified the issue to be sure. In my tests, whenever there is a mismatch on WS-Addressing Action, an exception is thrown by the custom encoder that needs to edit the OperationContext.Current object. My guess is that because of the mismatch, the OperationContext used by client becomes different from the OperationContext used by the service.

Next time I will make sure that my local copy of codes is up to date first.