EngineerSpock
EngineerSpock

Reputation: 2675

Using client certificates for authentication

The client machine has the "TicketSalesClient" certificate in "My" storage of current user and the "TicketSalesServer" certificate in "TrustedPeople" storage of current user. The server machine has "TicketSalesClient" certificate in "TrustedPeople" storage of local machine and the "TicketSalesServer" certificate in "My" storage of local machine.

The service runs under IIS 7. Below is the web.config file:

<system.serviceModel> 
<services>
  <service behaviorConfiguration="secureBehavior" name="InternetRailwayTicketSales.TicketSalesImplementations.TicketSalesService">
    <endpoint address="TicketSalesService" 
              binding="basicHttpBinding" 
              bindingConfiguration="secureHttpBinding" contract="InternetRailwayTicketSales.TicketSalesInterface.ITicketSales" />

    <endpoint address="TicketSalesServiceSecureMex" 
              binding="basicHttpBinding" 
              bindingConfiguration="secureHttpBinding" 
              contract="IMetadataExchange" />

    <host>
      <baseAddresses>
        <add baseAddress="https://localhost:443/TicketSales/" />            
      </baseAddresses>
    </host>

  </service>
</services>
<bindings>
  <basicHttpBinding>
    <binding name="secureHttpBinding">
      <security mode="Transport">
        <transport clientCredentialType="Certificate"/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

<behaviors>
  <serviceBehaviors>
    <behavior name="secureBehavior">
      <serviceThrottling maxConcurrentInstances="5000" maxConcurrentSessions="5000" />
      <serviceMetadata httpsGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="True" />
      <serviceCredentials>
        <serviceCertificate findValue="TicketSalesServer" 
                            storeLocation="LocalMachine"
                            storeName="My"
                            x509FindType="FindBySubjectName"/>
        <clientCertificate>
          <authentication certificateValidationMode="PeerTrust"/>
        </clientCertificate>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

The service in IIS is configured for SSL and certificate requiring.

1)Now when I try to add service reference in the client I receieve: "The HTTP request was forbidden with client authentication scheme 'Anonymous'. The remote server returned an error: (403) Forbidden."

2)If I try to request the metadata endpoint using browser I firstly apply the SSL certificate and then receieve an error that "The credentials do not give the right to view this directory or page." As I understand this is because I can't give the client credentials through the browser.

3)I tried to use svcutil with configuration file which contains client credentials:

    <configuration>
  <system.serviceModel>
    <client>
      <endpoint 
        behaviorConfiguration="ClientCertificateBehavior"
        binding="basicHttpBinding"
        bindingConfiguration="Binding1" 
        contract="IMetadataExchange"
        name="https" />
    </client>
    <bindings>
      <basicHttpBinding>
        <binding name="Binding1">
          <security mode="Transport">
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCertificateBehavior">
          <clientCredentials>
            <clientCertificate findValue="TicketSalesClient"
                               storeLocation="CurrentUser"
                               storeName="My"
                               x509FindType="FindBySubjectName" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
    </configuration>

And then:

svcutil https://veryLongAddress.svc?wsdl /config:svcutilConf.config

And the response is that the "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. The remote certificate is invalid according to the validation procedure"

So what am I doing wrong?

Upvotes: 2

Views: 13257

Answers (3)

Shubham Sharma
Shubham Sharma

Reputation: 91

When we host WCF service in IIS with security type transport and client credential type certificate, Then put your client certificate on Root store and enable anonymous authentication in IIS. Enable anonymous authentication in IIS But most important, add your certificate to root store.

Upvotes: 0

Rajesh
Rajesh

Reputation: 7886

Seems like your certificates installation is fine. Can you try as shown below and see the output. Try to browse to the service from IE and you should be able to see the service and its wsdl.

Go to IE and then

Tools --> Internet Options --> Security --> Internet --> Custom Level

Tools --> Internet Options --> Security --> Intranet --> Custom Level

Now scroll down to Misc section to find the option "Dont Prompt for client certificate selection when no certificate is present or only one certificate is present" to Diable.

Now restart IE and browse to the service and IE should ask you to select a client certificate from the personal store and you need to select mvc.localhost.

If TicketSalesClient cert is not visible then your client certificate is not in the appropriate store.

The reason for this is that the file you are using to install the certificates do matter as well as the purpose for which the certificate has been created. You can find the purpose of each certificate when you double click them in the certificate store you have a column that is called Intended Purpose. Make sure its for your client certificate.

Upvotes: 1

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364399

When hosting the service in IIS all endpoints must have the same transport security configuration. I played with this before and I ended with redefining binding for WSDL GET (yes it has also internal binding defined). So modify your bindings on service to:

  <basicHttpBinding>
    <binding name="secureHttpBinding">
      <security mode="Transport">
        <transport clientCredentialType="Certificate" />
      </security>
    </binding>
  </basicHttpBinding>
  <customBinding>
    <binding name="wsdlBinding">
      <textMessageEncoding messageVersion="None" />
      <httpsTransport requireClientCertificate="true" />
    </binding>
  </customBinding> 

And in service behaviors use:

  <serviceMetadata httpsGetEnabled="true" 
                   httpsGetBinding="customBinding" 
                   httpsGetBindingConfiguration="wsdlBinding" />

This should force WSDL get to require client certificate and it "should" work from browser (unless there is some other problem).

Upvotes: 0

Related Questions