WCF Dynamic proxy configuration for COM+ and client certificates

I use the dynamic proxy to create proxies for com+ exposed web services. I want to use wsHttpBinding with transport security mode with SSL using client certificate for authentication.

To address this scenario you have to modify the proxy adding a Credential property on DynamicProxy type.

public ClientCredentials Credentials
{
     get
     {
       return (ClientCredentials)base.GetProperty("ClientCredentials");
     }

}

From your code you can use this to set the certificate. In my case the client is an asp.net app so the certificate in the local machine store.

To download the metadata via SSL you have to change DownloadMetadata method in DynamicProxyFactory type adding the certificate to

yourProxy.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "certificateName");

DiscoveryClientProtocol instance.

private void DownloadMetadata()
{
    EndpointAddress epr = new EndpointAddress(this.wsdlUri);

    DiscoveryClientProtocol disco = new DiscoveryClientProtocol();
    disco.AllowAutoRedirect = true;

    disco.ClientCertificates.Add(SetCertificate("certificateName"));
    
    disco.DiscoverAny(this.wsdlUri);
    disco.ResolveAll();
.....
}

public static X509Certificate SetCertificate(string CertificateName)
{
    X509Certificate cert = null;
    if (CertificateName.Length == 0)
    {
        certificatoClient = null;
        return null;
    }
    X509Store store = new X509Store("My", StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateName, true);
    if (certs.Count == 0)
        throw new Exception("Certificate not found: " + CertificateName);
    else if (certs.Count > 1)
        throw new Exception("More certificates found: " + CertificateName);
    else
        cert = certs[0];
    return cert;
}

Now you have to configure WCF for this (using svcconfigeditor.exe or modifying the config file directly). The behavior configuration is

<wsHttpBinding>
  <binding name="comNonTransactionalBinding">
    <reliableSession enabled="false" />
    <security mode="Transport">
      <transport clientCredentialType="Certificate" />
    </security>
  </binding>
</wsHttpBinding>

The service behavior is

<serviceBehaviors>
  <behavior name="NewBehavior">
    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
    <serviceCredentials>
      <windowsAuthentication includeWindowsGroups="false" allowAnonymousLogons="false" />
    </serviceCredentials>
    <serviceDebug includeExceptionDetailInFaults="true" />
  </behavior>
</serviceBehaviors>

I set httpGetEnable='false' to use only HTTPS for metadata retrieval.

Attach the behavior and binding to your service

<service name="{9962A512-0105-48AE-B168-1FEED589B147},{45302176-5C77-49F7-B181-46689EEAE374}" behaviorConfiguration="NewBehavior">
  <endpoint address="_myApp" binding="wsHttpBinding" bindingConfiguration="comNonTransactionalBinding" contract="{ADA119DF-09D7-4EC6-98F5-6EA335FA495D}" />
</service>

note: to set up a configuration for com+ WCF you would use ComSvcConfig.exe. The name of the service that the tool inserts in the config file is constructed using the guid of the com+ package and the guid of the component something like {2C6B87B5-3C7B-4AFF-AE35-F0851F4543C2},{B1396717-2E01-473B-B550-73B1D223A2E5}. In the .svc file the guid are inverted and in lower case!!! {b1396717-2e01-473b-b550-73b1d223a2e5},{2c6b87b5-3c7b-4aff-ae35-f0851f4543c2} :'(

In IIS manager you have to set the directory security->Secure communication to require SSL and client certificates(iisreset required). If not you'll get the error "The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'SslNegotiateCert, SslMapCert'. "

In my case I had also to map the certificate to a valid user account to let the com+ package take the right identity.

Also in IIS manager you have to go directory security->Authentication and access control to disable Integrated windows authentication and anonymous access....wait you can't ;-)

 

If you disable anonymous access you'll get an error "Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service". It seems a bug of WCF (ehm ... a feature) To workaround this you could set the anonymous user to an invalid user (say user "winnie" with pwd "pooh") and leave the anonymous access turned on. If someone try to access you services she will get a 401.

Beware that toggling anonymous access on and off requires an iisreset to take place (I lost some time for this, being insecure about WCF behavior).

This should work...take a look at the iis logfile to see if the metadata are downloaded correctly via SSL with the correct user and also the POST of the payload.

Hope this helps someone sort out this topic.

Technorati tags: , , ,
«agosto»
domlunmarmergiovensab
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678