How to set WCF security to require client certificate?

20,310

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.

Share:
20,310
jlp
Author by

jlp

Updated on November 07, 2020

Comments

  • jlp
    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.