Today a colleague asked me how you can prevent anybody but a known client from being able to call your WCF service/service-methods. It goes without saying that we are aiming at controlling the calling machine in this scenario and not so much interested in the calling user. A quite common scenario when doing server-to-server communication in e.g. a B2B situation. Well – it can be accomplished quite securely and robust by using X.509 certificates which identifies the calling machine.
I should mean that it is preferred if the solution to this problem is a completely configured solution instead of a coded solution. No code – just configuration. In this way, the compiled assemblies remain the same and no need for recompilation is needed when you decide to change certificates or other “external” things. This I did not completely succeed with, as the below solution requires a single security-attribute (PrincipalPermission) on the methods that you want protected. As seen in the figure – this service is to be called by 2 different clients; one with a valid certificate and one without a certificate. The last should fail and be thrown away when trying to call the service methods!Running sample:
You can download a running sample (Proof-Of-Concept) here: X509.POC.zip
How do we accomplish this scenario?
First – lets focus on the WCF Service that is to be protected.
Now – to insist that the Client should identity himself via X.509 certificates to the Service, we need to configure this in the service configuration in the <bindings> configuration section. In the below, a custom configuration is seen called “messageAndCertificateClient”. This mandates that the calling Client should present a Certificate (set in the clientCredentialsType attribute) to identity/authenticate himself to the service.
<service name="Server.CalcService" behaviorConfiguration="serviceCredentialsBehavior">
<message clientCredentialType="Certificate" />
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost/Calculator/mex"/>
<!--Service certificate (used for initial handshake and negotiation between C/S)-->
<!--How should Client certificates be authenticated?-->
<!--use AspNetRoles to concatentate CN and thumbPrint -->
The server side has a simple method implementation/signature seen below. As seen, the service method (‘Add’) has been attributed with a PrincipalPermissionAttribute (system.security.permissions). This attribute is set with the Name property to “CN=<subject>; <thumbprint>”. This is quite important as the later tag <serviceAuthorization principalPermissionMode=”UseAspNetRoles”/> makes WCF concatenate the incoming Clients certificate data (subject and certificate unique thumbprint) into a semicolon separated string. This string is used for authorization later on by means of simple string comparison. It is important to mention that this PrincipalPermissionAttribute can be applied to the service method level only and does not apply to the service level. You are however in this way able to control access to a very granular level and do not span the service in it’s entirety.
public interface ICalcService
int Add(int a, int b);
int Subtract(int a, int b);
class CalcService : ICalcService
#region ICalcService Members
//can only be called if cert = <thumb>
[PrincipalPermission(SecurityAction.Demand, Name = "CN=HabaneroClient; 6cc9da1b64592d1f0ce46824674c833a30993bba")]
public int Add(int a, int b)
return a + b;
public int Subtract(int a, int b)
return a - b;
Now – you might be wondering where did this thumbprint stuff come from? The subject and thumbprint that we want to allow to use our service methods are both coming from the Clients certificate. It is retrieved by opening the Clients certificate in the Certificate Manager (MMC-snapin) and copying them into notepad (this is done on the Client machine!).
CLIENT SIDE: We need to setup the client to present certificates to the service. How is this accomplished? The same way anything else is setup when dealing with WCF. It is configured in the Clients configuration file:
The client service is set up like this, mandating that a Certificate is presented to the (server) service. In addition, an expected identity (HabaneroServer) is set in the dns value setting. The Certificate presented by the client is called HabaneroClient and found in the local Certificate Storage.
<?xml version="1.0" encoding="utf-8"?>
<!--Expected identity of server (certificate)-->
<dns value="HabaneroServer" />
<!--Identity to present to service-->
<!--How will the Client validate the Servers certificate?-->
<binding name="certBehave" >
<message clientCredentialType="Certificate" />
As seen above, the Client configuration is more or less a copy of the Server side configuration. It mandates that the Client presents a certificate as authentication to the service.