How to set WCF security to require client certificate?
Solution 1
Instead of
<serviceCredentials>
<clientCertificate>
<authentication trustedStoreLocation="LocalMachine"
certificateValidationMode="PeerTrust" />
</clientCertificate>
</serviceCredentials>
I think you are supposed to have
<serviceCredentials>
<serviceCertificate findValue="SubjectKey" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
</serviceCredentials>
You are not authenticating the service by this, instead you are telling the service how the client is to be authenticated.
Solution 2
I found the following guide extremely helpful and very detailed. https://notgartner.wordpress.com/2007/09/06/using-certificate-based-authentication-and-protection-with-windows-communication-foundation-wcf/
It covers creating the service, the client, the certificates and adjusting the 2 configs.
Server:
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<!--only accept certificates in "Trusted People"-->
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Client:
<bindings>
<basicHttpBinding>
<binding name="customBinding1">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="customBehavior1">
<clientCredentials>
<!--fabrkam-->
<clientCertificate storeName="My" storeLocation="CurrentUser" x509FindType="FindByThumbprint" findValue="d2 31 6a 73 1b 59 68 3e 74 41 09 27 8c 80 e2 61 45 03 b1 7e"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
We auto-redirect any HTTP requests to HTTPS so we have to use TransportWithMessageCredential type security. For normal Http using just Message as security type should also work.
Solution 3
I was able to accomplish the same thing by using a customBinding, like this:
<customBinding>
<binding name="bindingName">
<security authenticationMode="UserNameOverTransport" />
<httpsTransport requireClientCertificate="true"/>
</binding>
</customBinding>
(I omitted the attributes not relevant to your case.)
As far as authenticationMode
, I think you can probably use any of them--the httpsTransport
with requireClientCertificate
are the important parts here.
jlp
Updated on November 07, 2020Comments
-
jlp over 3 years
I have WCF service. I demand clients to authenticate with certificate. This is service configuration:
<system.serviceModel> <services> <service name="FilmLibrary.FilmManager" behaviorConfiguration="FilmService.Service1Behavior"> <endpoint address="manager" name="certBinding" binding="basicHttpBinding" contract="FilmContract.IFilmManager" /> </service> </services> <bindings> <basicHttpBinding> <binding name="certBinding"> <security mode="Message"> <message clientCredentialType="Certificate" /> </security> </binding> </basicHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="FilmService.Service1Behavior"> <serviceCredentials> <clientCertificate> <authentication trustedStoreLocation="LocalMachine" certificateValidationMode="PeerTrust" /> </clientCertificate> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
Public key is installed in LocalMachine, Trusted People
Client configuration is as follows:
<system.serviceModel> <bindings> <basicHttpBinding> <binding name="certBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <security mode="Message"> <message clientCredentialType="Certificate"/> </security> </binding> </basicHttpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="certBehaviour"> <clientCredentials> <clientCertificate findValue="SubjectKey" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName"/> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint address="[...]/Service1.svc/manager" binding="basicHttpBinding" bindingConfiguration="certBinding" behaviorConfiguration="certBehaviour" contract="FilmsService.IFilmManager" name="certBinding" /> </client> </system.serviceModel>
Private key is installed in Personal, current user.
Without security, service works. With security enabled - it does not. I tried several configurations and I got errors like authentication failed or that I have to set service certificate in clientCredentials element. Which I don't understand because I do not want to authenticate service at all.