Saturday, August 11, 2012

How to retrieve service metadata for WCF services that use X509 certificates for client validation


Svcutil is wonderful tool and it comes handy when trying to create WCF client applications. It makes use of the MEX endpoint and retrieves the config and proxy classes.  

Where to look for svcutil.exe tool and its configuration in your machine (WIN 7 64bit):
 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
[select the right version "v7.0A"]

In Visual studio command shell, you can type as follows
Svcutil http://MyTestService/Test.svc

This will generate the service endpoint information as config and proxy as a .cs file.

This approach does not work for the WCF services that demands client authentication certificate while receiving the actual or metadata-exchange request. 

You may have kept the client authentication certificate in your “localmachine” or “currentuser” certificate store (mostly in “personal”) [You can do this either via MMC console or certification manager tool]

In such cases if you try to execute this tool you will be receiving error as below
-------------------------------------------------------------------------
WS-Metadata Exchange Error
URI: https://MyTestService/Test.svc
Metadata contains a reference that cannot be resolved: 'https://MyTestService/Test.svc'.
The HTTP request was forbidden with client authentication scheme 'Anonymous'
The remote server returned an error: (403) Forbidden.
-------------------------------------------------------------------------
This happens as the svcutil does not know where to look for the certificate. There is an easy way to get this working
  1.      Locate the svcutil.exe and svcutil.exe.config
  2.     Copy it to any of your folder let’s say c:\temp\
  3.     Now modify the svcutil.exe.config to have the corresponding certificate store information (mention specific endpoint details and client credentials) 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint behaviorConfiguration="wsHttpBehavior"
         binding="wsHttpBinding" bindingConfiguration="wsHttpMex"
         contract="IMetadataExchange" name="https"/>
    </client>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpMex">
          <security mode="Transport">
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="wsHttpBehavior">
          <clientCredentials>
                  <clientCertificate findValue="<clientcertificatesubject>"
                  storeLocation="LocalMachine"
                  storeName="My"
                  x509FindType="FindBySubjectName" />          
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>
4.  Now the following command will be working as the svcutil is now able to locate the certificate in LocalMachine\Personal certificate store.