Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set WCF security to require client certificate?

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.

like image 255
jlp Avatar asked Dec 05 '09 19:12

jlp


2 Answers

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.

like image 113
Tikall Avatar answered Oct 13 '22 11:10

Tikall


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.

like image 33
K2so Avatar answered Oct 13 '22 12:10

K2so