Question

I am trying to host a wcf service on IIS Express (.NET 3.5) over ssl and with client certificates which are mapped to a windows user.

When I use a console application as testclient I receive the following error:

The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM,Negotiate'.

I don't understand how this is possible because when I check the IIS Express tracelogging I see the clientcertificate being mapped in the iisclientcertificatemapping httpmodule to my window user.

Extract from IIS tracelogging

As seen in the screenshot it is the httpmodule with name "ServiceModel" which sets the response to 401.

I enabled svc tracing on both client and server side but the only thing that is logged on server side is the "Receive bytes on connection 'https://myurl/orderservice.svc/ClientCert'"

My IIS express (applicationhost.config) is overridden in the web.config:

<system.webServer>
    <security>
      <authentication>
        <windowsAuthentication enabled="true" />
        <anonymousAuthentication  enabled="false" />
        <iisClientCertificateMappingAuthentication enabled="true" oneToOneCertificateMappingsEnabled="true" >
          <oneToOneMappings>
            <add enabled="true" certificate="MIICGjCCAYegAwIBAgIQfi996nkvEYdO6WBFfokO/jAJBgUrDgMCHQUAMCUxIzAhBgNVBAMTGkdsb2JhbFZpc2lvblNlcnZpY2VzUm9vdENBMB4XDTEyMDkwNzEyMjg1OVoXDTM5MTIzMTIzNTk1OVowHjEcMBoGA1UEAxMTR2xvYmFsVmlzaW9uQ2xpZW50MTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5qBoLtQjkN2LtWdCQVbWqMA5N4jMmDM3yscUi3c7mwO9iFZaOcf41+SUFMivEXOOVI/5qVdaMII/ombGPopKoZhtXYUkv90psWwQHXNfqE1L+Vkur/u2KiQSImXLhSPF8qTR5RbRj3inpTWTg74p1a1HjbndU/lwu1cznl5vW/sCAwEAAaNaMFgwVgYDVR0BBE8wTYAQjpcP+m/6Y3T5yi7PJKxrGqEnMCUxIzAhBgNVBAMTGkdsb2JhbFZpc2lvblNlcnZpY2VzUm9vdENBghB+Uxyrj6x2rEV3HQ6vVX48MAkGBSsOAwIdBQADgYEAT5CiQCj4y9dW+zBSq96dRye3FJswAYiZgMLLoiyRV5h2QT7H0nxcdQ0mtdcN3OPunuvrYYlS58QVlBx6aozznmKeBuRl6GwWwQLYGxBRsKbQTuEiI85v1n/jK0LTT6FSGBMUlcJSn2NgnUAWgXvlf8f0SqLqApwWPeYybQxfz4U="
                 userName="CORP\mywindowsuser" password="mypassword" />
          </oneToOneMappings>
        </iisClientCertificateMappingAuthentication>
      </authentication>
      <authorization>
        <add users="*" accessType="Allow"/>
      </authorization>
      <!--Require SSL *AND* require a client certificate -->
      <access sslFlags="Ssl, SslNegotiateCert"/>
    </security>
  </system.webServer>

With this configuration the browser asks for a clientcertificate when I navigate to the svc file (https://myurl/orderservice.svc?wsdl) and when I select the self signed certificate I am able to see the wsdl of the service. For me this means the certificates(rootca, server and client certificate) are correct and ssl is working.

For completion this is my service configuration server side:

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false">
  <baseAddressPrefixFilters>
    <add prefix="https://myurl:443"/>
  </baseAddressPrefixFilters>
</serviceHostingEnvironment>
<diagnostics wmiProviderEnabled="true">
  <messageLogging
       logEntireMessage="true"
       logMalformedMessages="true"
       logMessagesAtServiceLevel="true"
       logMessagesAtTransportLevel="true"
       maxMessagesToLog="3000"
   />
</diagnostics>
<bindings>
  <wsHttpBinding>
    <binding name="ClientCert">
      <security mode="Transport">
        <message clientCredentialType="Certificate"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior name="wsHttpCertificateBehavior">
      <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
      <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
      <serviceAuthorization serviceAuthorizationManagerType="CompanyName.Model.Security.AuthorizationBehaviors.AdamAuthorizationManager,ServiceSecurity">
        <authorizationPolicies>
          <add policyType="CompanyName.Model.Security.AuthorizationPolicies.AdamAuthorizationPolicy, ServiceSecurity" />
        </authorizationPolicies>
      </serviceAuthorization>
      <serviceCredentials>
        <serviceCertificate findValue="certificatesubject" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
        <clientCertificate>
          <authentication revocationMode="NoCheck" mapClientCertificateToWindowsAccount="true" />
        </clientCertificate>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
<services>
  <service name="CompanyName.Model.Services.OrderService" behaviorConfiguration="wsHttpCertificateBehavior">
    <endpoint address="https://myurl/OrderService.svc/ClientCert" contract="CompanyName.Model.Services.ServiceContracts.IOrderService" binding="wsHttpBinding" bindingConfiguration="ClientCert">
    </endpoint>
  </service>
</services>

Service configuration client side

<system.serviceModel>
    <diagnostics>
      <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxSizeOfMessageToLog="26214400" />
    </diagnostics>
    <bindings>
      <wsHttpBinding>
        <binding name="ClientCertificate">
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="wsHttpCertificateBehavior">
          <clientCredentials>
            <clientCertificate findValue="39820c4f767c809bb8f64b0f52ccfd686093896c" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint"/>
            <serviceCertificate>
              <authentication revocationMode="NoCheck"/>
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <endpoint name="ClientCertificate" address="https://myurl/OrderService.svc/ClientCert" contract="CompanyName.Model.Services.ServiceContracts.OrderService" binding="wsHttpBinding" bindingConfiguration="ClientCertificate" behaviorConfiguration="wsHttpCertificateBehavior"/>
    </client>
  </system.serviceModel>

If I browse to the service i get the following:

Choose certificate

If i choose the correct certificate i get this:

Browser response

When i try to access the endpoint in a browser it says 400 Bad request (which is normal)

I am already spending several hours on this if someone finds a wrong configuration or has experience with ssl and clientcertificatemapping with wcf hosted on iis express let me know.

Was it helpful?

Solution

There is an inconsistency between the 2 configs:

The wshttpbinding is set to transport security on client and server but on the server side config the ClientCredentialType is configured for message security instead of transport.

The service requires to use a certificate, this means the SslFlags attribute in the System.WebServer section can be set to the following:

 <access sslFlags="Ssl, SslNegotiateCert, SslRequireCert"/>

I hope this helps ;)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top