A solution to limit specified client certificates to consume WCF service

Background:

 

Suppose there is a WCF service which will be consumed by other parties. The client credential type of this WCF service is configured as certificate. In other word, the WCF consumer must present its client certificate to WCF service for authentication & authorization. This is a typical kind of business –to-business architecture.

By default, WCF provides below options to validate if the incoming client certificate is valid:

 

· None

· PeerTrust

· ChainTrust

· PeerOrChainTrust

· Custom

More details about this topic, you can refer to below MSDN:

X509CertificateValidationMode Enumeration

https://msdn.microsoft.com/en-us/library/system.servicemodel.security.x509certificatevalidationmode(v=vs.90)

 

Suppose there are multiple incoming client certificates, let’s say: WCFClient#1, WCFClient#2. Both client certificates can be validated successfully according to above X509 certificate validation policy. Then the problem comes up:

How can we limit only WCFClient#1 can consume the WCF service, and disallow WCFClient#2 to consume the WCF service although WCFClient#2 can be validated successfully?

 

Or we have multiple WCF services deployed in the same box and will be consumed by multiple other parties who will present their corresponding client certificates, just as below diagram shows:

 

Then how can we control WCF#1 WCF service can only be consumed by WCFClient#1, and WCF#2 WCF service can be only consumed by WCFClient#2 as well?

 

Recently I handled several cases that customer were just trying to find a solution to implement above design.

 

Here I’d like to share a solution to implement this kind of design.

 

NOTE: One thing I need to mention is: this is one possible solution, but not the only one. So I just share the steps for my specific solution.

Solution:

The rough idea of this solution is to map the incoming client certificate as a windows account. Then we authorize the access to WCF service based on windows account.

To implement above design, we need to configure IIS and WCF perspective at the same time, and a little coding as well.

NOTE: Here I’d like to use IIS7.5 of Windows Server 2008 R2 as the web server. So all configuration about IIS listed below is about IIS7.5.

1) IIS perspective:

      a) For SSL Setting, we need to configure it as below:

                          “Require SSL + Client Certificates Require”

 

 b) For Authentication setting, we need to enable “Anonymous” authentication and disable all other options.

c) We need to enable iisClientCertificateMappingAuthentication just as below screenshot shows:

 

So we need to map the incoming client certificate as a windows account. Let’s say the mapped windows account is “mydomain\wcfclientaccount”.

 

For more details about how to configure client certificate mappings, you can refer to below article:

Configuring Many-to-One Client Certificate Mappings for Internet Information Services (IIS) 7.0 and 7.5

https://support.microsoft.com/kb/2026113

 

2. WCF Service Perspective:

  a) Configure your binding to use Transport Security mode with Certificate client credential type . So the configuration will be just like below:

         “
   <basicHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>

   “

 

 b) Apply the same binding configuration to the metadata endpoint. The configuration will just be like below:

”…

     <service behaviorConfiguration="securebehaviour" name="HelloWorldDemo.Service1">
……
<endpoint address="mex" binding="basicHttpBinding" bindingConfiguration="NewBinding0" name="mexEndpoint" contract="IMetadataExchange" />
</service>

 

For more information about this topic, you can refer to below MSDN:

How to: Use Certificate Authentication and Transport Security in WCF Calling from Windows Forms
https://msdn.microsoft.com/en-us/library/ff650785.aspx

  c) Configure the service behavior as below:

i) Enable service authorization.

ii) Enable “mapClientCertificateToWindowsAccount”

So the configuration will just look as below highlighted.


  <serviceBehaviors>
<behavior name="securebehaviour">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" mapClientCertificateToWindowsAccount="true" />
</clientCertificate>
</serviceCredentials>
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>

More details about mapClientCertificateToWindowsAccount property, you can refer to below MSDN article:

X509ClientCertificateAuthentication.MapClientCertificateToWindowsAccount Property

https://msdn.microsoft.com/en-us/library/system.servicemodel.security.x509clientcertificateauthentication.mapclientcertificatetowindowsaccount.aspx

d) Apply PrincipalPermission attribute to that specific method that you want to limit access to, for example:


       [PrincipalPermission(SecurityAction.Demand, Name = @"mydomain\wcfclientaccount")]
public string HelloWorld()
{
return "Hello World. You have authenticated with account: " + System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity.Name.ToString();
}

If you have concern about this kind of hardcoded way, you can also implement it programmatically. The sample code will be like below:

    static class PermissionHelper
{

        public static void CheckPermission()
{
string allowedAccount = System.Configuration.ConfigurationManager.AppSettings["AllowedWindowsAccount"].ToString();
// We get the allowed windows account who is authorized to call this WCF method from configuration file

            PrincipalPermission ppAdmin = new PrincipalPermission(null, allowedAccount);
ppAdmin.Demand();

       }
}

 

    public class Service1 : IService1
{
public string helloworld()
{
PermissionHelper.CheckPermission();
//Execute your real logic then
return "Hello World. You have authenticated with account: " + System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity.Name.ToString();
}
}

For more details, you can refer to below article:

PrincipalPermissionMode Enumeration

https://msdn.microsoft.com/en-us/library/system.servicemodel.description.principalpermissionmode.aspx

 

3. WCF Client Perspective.

  WCF client must present its client certificate by specifying the client certificate using Endpoint behavior just like below:


<endpointBehaviors>
<behavior name="NewBehavior0">
<clientCredentials>
<clientCertificate findValue=" AllowedClientCertificate " storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>

Best regards

Winston He from AGPC DSI Team