Self-Hosted Wcf Service with Certificate client authentication

1.9k Views Asked by At

I have a self-hosted wcf service which uses wsHttpBinding with Transport security. I want the service to authenticate a client using a certificate.

When the client communicates with the service using clientCredentialsType set to 'None' everything works fine. The certificate was created with OpenSSL (self-signed) and registered with netsh on a specific port. The name of the certificate is DomainName (machine name in my case).

Update
I have created certificates for both client and server and placed them in each others Trusted Root stores (server certificate in client's store and vice-versa).

I've gone over a lot of articles and other questions at SOF but even the ones that look relevant couldn't help me resolve the issue.

Current Configuration

Service

<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="true" httpsHelpPageEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="httpsBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" sendTimeout="01:00:00">
          <security mode="Transport" >
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="serviceBehavior" name="Service">
        <endpoint binding="wsHttpBinding" bindingConfiguration="httpsBinding" contract="SomeNamespace.IService"/>
        <host>
          <baseAddresses>
            <add baseAddress="https://domain:port/Something/"/>
          </baseAddresses>
        </host>
      </service>
    </services>    
  </system.serviceModel>

Client

<system.serviceModel>  
    <client>  
      <endpoint address="https://domain:port/Something/"   
                behaviorConfiguration="endpointCredentialBehavior"  
                binding="wsHttpBinding"   
                bindingConfiguration="Binding"   
                contract="SomeNamespace.IService"/>  
    </client>  
    <behaviors>  
      <endpointBehaviors>  
        <behavior name="endpointCredentialBehavior">  
          <clientCredentials>  
            <clientCertificate findValue="DomainName"  
                               storeLocation="LocalMachine"  
                               storeName="My"  
                               x509FindType="FindBySubjectName" />  
          </clientCredentials>  
        </behavior>  
      </endpointBehaviors>  
    </behaviors>  
    <bindings>  
      <wsHttpBinding>         
        <binding name="Binding">  
          <security mode="Transport">  
            <transport clientCredentialType="Certificate"/>  
          </security>  
        </binding>  
      </wsHttpBinding>  
    </bindings>  
  </system.serviceModel>  

I get the following exception:

System.ServiceModel.Security.MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'. ---> System.Net.WebException: The remote server returned an error: (403) Forbidden. at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

2

There are 2 best solutions below

7
Abraham Qian On

There is one more thing we need to do. We should make their certificate trusted by each other. the server’s certificate must be trusted by the client and the client’s certificate must be trusted by the server.
Specifically, the server certificate is installed in the client Trusted Root Certification Authorities, the client certificate is installed in the server Trusted Root Certificate Authorities. It is best to use a local machine certificate store. We could check the certificate by using Certlm.msc command.
enter image description here Please refer to the official document with regards to this issue.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication
For some special certificates created by other special tools, such as PowerShell, we had better make the target framework of the project (server and client) above 4.6.2.
https://github.com/dotnet/docs/issues/12000
Feel free to let me know if there is anything I can help with.

1
Davit Mikuchadze On

your configuration file looks okay. i have same issue with my 3rd party client certificate(public key) no matter where i add that certificate is still doesn't works. However i've managed to make it work with my self-signed client certificate. i just had to add client CA certificate to Trusted Root Certification authorities on server.

i found those two topics helpful in determining some of issues: Mutual authentication with a IIS hosted WCF WCF – 2 Way SSL Security using Certificates

Hope it will be helpfull for you. i'll post updates if i'll manage to solve this problem.