I've been struggling with the configuration for this blasted WCF service for the past week, and I'm slowing beginning to suspect that what I'm trying to do is just not possible, despite the documentation.
Quite simply, I want to have a WCF service require a client certificate (which the server will have in its cert store), and then access that identity with System.ServiceModel.ServiceSecurityContext. Additionally, this needs to use transport security.
Here's my server config:
<system.serviceModel>
<services>
<service behaviorConfiguration="requireCertificate" name="Server.CXPClient">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="PartnerComm.ContentXpert.Server.ICXPClient" />
<endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="mexEndpoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="requireCertificate">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" maxBufferPoolSize="5242880" maxReceivedMessageSize="5242880">
<readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="1073741824" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
Here's my client config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/"
binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" behaviorConfiguration="ClientCertificateBehavior"
contract="ContentXPertServer.ICXPClient" name="wsHttpEndpoint" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
The code all works perfectly when security mode='None' over http, but of course, there's no authentication, and nothing in System.ServiceModel.ServiceSecurityContext. I've tried dozens of variations on all of these elements, and it all ends up inevitably with the request throwing an exception "An existing connection was forcibly closed by the remote host".
I'm using a self-signed cert "CyberdyneIndustries", whose CA cert I've added to the trusted CA store. The cert checks out when I view it. I've gone through the hell of http namespace management, and solved those problems as well. It simply looks like WCF doesn't really support this...please tell me I'm wrong.
TIA.
Ultimately, I decided to try message security, to see if that would shed some light on the situation - it did, and I'm going to cut my losses and go with that. So, there's no definitive answer to this.
Implementing message security did, however, expose a BIG problem, and this may have been the root of the transport security problem. There is a piece of poison documentation from MSDN:
http://msdn.microsoft.com/en-us/library/ff650751.aspx
On this page, the command to create the self-signed cert is as follows:
makecert -sk MyKeyName -iv
RootCaClientTest.pvk -n
"CN=tempClientcert" -ic
RootCaClientTest.cer -sr currentuser
-ss my -sky signature -pe
The argument "signature" should instead be "exchange". Once I regenerated all my certs, message security started working. One big takeaway from all of this is that if you're wanting to implement transport security, get message security working first, because the error messages you get from the system are much more descriptive.
Does the SSL handshake succeed? Enable SChannel logging to troubleshoot the SSL layer. See this old KB article: How to enable Schannel event logging in IIS. Although is an KB for W2K and XP, the steps to enable SChannel logging are the same and still valid on newer systems. With the logging enabled you'll be able to determine why is SSL rejecting the certificate.
I know this is 3 years old, but for those who might still be interested...
I'm in the process of learning WCF (security among other things) and was able to get things working properly with netTcpBinding (presumably, this will work for WsHttpBindings as well) using Transport security mode with a clientCredentialType="Certificate" (and, protectionLevel="EncryptAndSign", though that wasn't germane to the issue).
I did encounter the force connection close error from the server-side too, but discovered I was missing one piece of configuration. It's all working now.
Here's my server-side config:
<configuration>
<system.serviceModel>
<services>
<service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<serviceCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="TcpCertSecurity">
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
And my client-side configuration:
<configuration>
<system.serviceModel>
<client>
<endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding"
bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService"
behaviorConfiguration="MyServiceBehavior">
<identity>
<dns value="MyServiceCert" />
</identity>
</endpoint>
</client>
<bindings>
<netTcpBinding>
<binding name="TcpCertSecurity">
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="MyServiceBehavior">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" />
</serviceCertificate>
<clientCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I created a certificate chain for the server (self-signed Trusted Root certificate + a certificate built using that root) using the technique described here and stored both the Root cert and child cert in the certificate store of my server host machine. And, finally, I imported that server certificate + public key into the cert store on my client host machine (in LocalMachine/TrustedPeople).
WsHttpBinding DOES support certificate authentication for transport security.
There can be a few things wrong:
Did you add both certificates to your store? CyberdyneIndustries as well a CA that you used to sign it? CA should be in "Trusted Root Certification Authorities"
Also, i've done this self-hosted, never in Visual Studio Dev server. Try to host your service in IIS at least. I am not sure if VS Dev server supports certificates.
Try to turn off service authentication. So the client doesn't have to authenticate the service. I don't know if you want this in your app or not but just for testing so we can rule that out
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" />
<serviceCertificate>
<authentication certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>
Related
I’m trying to setup a security transport using certificates over a SSL service.
The service is installed over IIS, I have configured it using a “MyLaptop” certificate (stored on local machine/Personal) validated by a self-signed certificate (“My Root CA” certificate – stored on local machine Trusted Root Certification Authorities). Everything seems to be OK with the service; I can access it using the Internet Explorer.
On the server side the web.config looks like
<behaviors>
<serviceBehaviors>
<behavior name="EchoServiceBehavior">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" revocationMode="NoCheck" />
</clientCertificate>
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MutualSslBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="EchoServiceBehavior" name="HttpsBindingDemo.EchoService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MutualSslBinding"
contract="HttpsBindingDemo.IEchoService">
<identity>
<dns value="MyLaptop" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="https://MyLaptop:12643/EchoService/" />
</baseAddresses>
</host>
</service>
On the client side I have installed a new certificate “MyClient” (stored on CurrentUser/Personal) validated by the same “My Root CA” certificate.
On the client side the app.config looks like
<behaviors>
<endpointBehaviors>
<behavior name="EchoClientBehavior">
<clientCredentials>
<clientCertificate findValue="MyClient" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEchoService">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://MyLaptop:12643/EchoService/EchoService.svc" behaviorConfiguration="EchoClientBehavior"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IEchoService"
contract="SecuredServices.IEchoService" name="WSHttpBinding_IEchoService">
<identity>
<dns value="MyLaptop" />
</identity>
</endpoint>
</client>
Every time when trying to execute the operations of the EchoService.svc I’m receiving the error below:
“The HTTP request was forbidden with client authentication scheme 'Anonymous'.”
Enabling the service’s log I found that first exception message is in fact “Client certificate is required. No certificate was found in the request. This might be because the client certificate could not be successfully validated by the operating system or IIS. For information on how to bypass those validations and use a custom X509CertificateValidator in WCF please see http://go.microsoft.com/fwlink/?LinkId=208540.”.
Could you please help me to understand how to correctly configure the service to avoid the described errors?
Thank you!
It looks like you are most likely missing the serviceCertificate tag inside of your serviceCredentials tag in your service behavior. Try adding this and it should resolve the issue. Each time I use certificates with a WCF service I always have to specify in the config what certificate the service should be using.
http://msdn.microsoft.com/en-us/library/ms731340%28v=vs.110%29.aspx
When you import client cert to your personal store, try to import using pfx file and specifying the password
So I'm completely lost with certificates. I've searched all over the web for solutions and tutorials for this and found nothing that can really help me.
What I'm trying to do is to have both server and client certificate validation for my WCF client-server application. The application is hosted on IIS.
I want it on my dev computer (the server is localhost) and in test (where im the client and the server is a windows server).
the configuration I have now is:
Client:
<behaviors>
<endpointBehaviors>
<behavior name="myBehaviorConfig">
<clientCredentials>
<clientCertificate findValue="CN=MyTestClientCertificate"
storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MyBindingConfig">
<security mode="TransportWithMessageCredential">
<transport realm=""/>
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://localhost/Service.Calculator.svc"
binding="wsHttpBinding"
bindingConfiguration="MyBindingConfig"
behaviorConfiguration="MyBehaviorConfig"
contract="Service.ICalculator"
name="ICalculatorServiceEndpoint">
<identity>
<servicePrincipalName value="host"/>
</identity>
</endpoint>
</client>
Server:
<behaviors>
<serviceBehaviors>
<behavior name="myBehavior">
<serviceCredentials>
<serviceCertificate findValue="CN=MyTestRootCA"
storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName"/>
<userNameAuthentication userNamePasswordValidationMode="Windows"/>
<clientCertificate>
<authentication certificateValidationMode="PeerOrChainTrust"/>
</clientCertificate>
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<unity operationContextEnabled="true"
instanceContextEnabled="true"
contextChannelEnabled="true"
serviceHostBaseEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MyBinding">
<security mode="TransportWithMessageCredential">
<transport realm=""/>
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Service.Calculator"
behaviorConfiguration="myBehavior">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="MyBinding"
contract="Service.ICalculator" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange"
name="CalculatorServiceMex" />
</service>
</services>
"CN=MyTestRootCA" is the "Authority" the "Creating" certificate and I put him in the trusted root certificates on the localComputer as well as in the personal directory in the local computer.
And it is the issuer of the client certificate "CN=MyTestClientCertificate".
Few things..
I know that the client certificate should be in the CurretUser directory in the "MMC" but when its there i have an exception that the app can't find the certificate.
I tried locating it by "FindBySubjectDistinguishedName" and with "FindByThumbprint", both time was the same exception "Cant find certificate with the given criteria ..." so i put it in the LocalMachine and its fine.
Any one has an idea why it didn't work?
I had lots of problems and exceptions with this =\ the current one is:
"The private key is not presented in the X.509 certificate"
Anybody familiar with this exception and know how to fix it?
thanks a lot for your answers, i'm sitting on this for few days now
Your configuration file does not specify the clientCertificate storeLocation value, therefore the client certificate needs to be in the LocalMachine store, which is the default value for storeLocation.
Consider the following example from msdn which sets the client certificate store location:
<clientCertificate>
<certificate
findValue="www.cohowinery.com"
storeLocation="CurrentUser"
storeName="TrustedPeople"
x509FindType="FindByIssuerName" />
<authentication …
Note: the other error, “The private key is not presented in the X.509 certificate”, is mostly likely thrown because your certificate does not have an associated private key or your process’ user context does not have permission to access the private key.
Is it possible to have an WCF Rest Webservice which excepts SSL Client Certificates and have the IIS SSL Setting to not set to "require SSL" and to anly "accept" client certificates and not "require" them?
I have the following config:
<system.serviceModel>
<services>
<service behaviorConfiguration="RestServiceBehaviour" name="PM.WCF.Service.PmRestService">
<endpoint address="" behaviorConfiguration="web" binding="webHttpBinding"
bindingConfiguration="StreamedRequestWebBinding" contract="PM.WCF.Service.IPmRestService" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="StreamedRequestWebBinding"
bypassProxyOnLocal="true"
useDefaultWebProxy="false"
hostNameComparisonMode="WeakWildcard"
sendTimeout="10:15:00"
openTimeout="10:15:00"
receiveTimeout="10:15:00"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
transferMode="StreamedRequest">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="RestServiceBehaviour">
<serviceMetadata httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
My problem is the following line:
<transport clientCredentialType="Certificate"/>
If i use this setting and IIS configured to accept, but not require client certificates, I get the following error:
The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'SslNegotiateCert'.
Sadly setting
<transport clientCredentialType="None"/>
Does not work either. I'm pretty sure the browser/client does send it's certificate, but OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsAuthenticated is False.
Is there any other way then to have two IIS Websites, one configured to require SSL and client certificates and one which does not?
Even if there is no way around it. How do I debug this in Visual Studio? Because the moment I require SSL client certificates, I can't just start the webservice. Visual Studio tries to access http://localhost/Foo.WCF.Service/debugattach.aspx and fails because of the missing client certificate.
I have created basichttpendpoint with security mode="TransportWithMessageCredential" for my self hosted WCF service.
My server config has:
enter code here
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IViewerManager" maxBufferSize="655360000" maxReceivedMessageSize="655360000" messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="SecureBehavior" name="Lumedx.ApolloLXPACS.ViewerServiceLibrary.ViewerManager">
<endpoint name="basicHTTP" address="https://localhost:5100/ViewerService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IViewerManager" contract="Lumedx.ApolloLXPACS.ServiceContracts.IViewerManager"/>
<host>
<baseAddresses>
<add baseAddress="https://localhost:5100/ViewerService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="HttpsBehavior">
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceCredentials>
<serviceCertificate findValue="RootCATest"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByIssuerName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
my windows client config has:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="priorityEndpoint1" value="basicHttpEndpoint"/>
<add key="maxCommunicationRetries" value="0"/>
</appSettings>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IViewerManager" maxBufferSize="655360000" maxReceivedMessageSize="655360000" messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="basicHttpEndpoint" address="https://10.10.10.100:5100/ViewerService/" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IViewerManager" contract="Lumedx.ApolloLXPACS.ServiceContracts.IViewerManager" behaviorConfiguration="HttpsBehavior"/>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="HttpsBehavior">
<clientCredentials>
<clientCertificate findValue="RootCATest"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByIssuerName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<
I have installed and configured certificate.
I am connecting my windows client with the self hosted WCF service with https end points. I captured network traffic using wireshark. All I see in the network traffic is TCP packets between the server and client. When I follow the TCP stream the message does not seem to be encrypted.
What am I doing wrong here?
Security mode TransportWithMessageCredential encrypts transport (SSL) and leaves message body not encrypted.
Encryption is made using your certificate.
If you see not encrypted data one of the following scenarios happend:
Traffic for some reason is not encrypted with ssl
Wireshark has access to your certificate and encrypted traffic using it.
Is this looks similar to what you did? http://trycatch.be/blogs/decaluwet/archive/2009/04/08/decrypting-ssl-traffic-using-wireshark.aspx
In any case you should be safe if transport level encryption is enable and your certificate is not compromised.
I'm looking for a definitive answer as to whether what I'm trying to do is supported or not.
Basically, I'm using WCF to stream large MTOM attachments (200 Mb), this works perfectly fine. The security requirements for the service is to use HTTPS and certificate-based authentication. I can run the service over HTTPS without any problems, but once I set IIS to “Accept client certificates” or “Require client certificates” (no change in the code), the following error is thrown (but only once the attachments get over about 80 Mb or so):
The socket connection was aborted.
This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue.
Local socket timeout was '00:30:00'.
I found some resources, sorry can't find them now, that indicated that the failure is probably related to the fact that the incoming messages either cannot be digitally signed, or verified due to the streaming nature of the message contents. I believe the service would have to hash the whole message contents to verify the cert, but this can't be achieved because portions of the message are in transit while validation is trying to occur.
I've setup the message contract so that the body is a single Stream element, and the other elements are contained within the header:
<MessageContract()>
Public Class StreamAttachmentRequest
<MessageHeader(MustUnderstand:=True)>
Public Property AttachmentName As String
<MessageBodyMember(Order:=1)>
Public Property Attachment As Stream
End Class
The service configuration looks as follows:
<system.serviceModel>
<!-- BINDING -->
<bindings>
<basicHttpBinding>
<binding name="TestCaseBasicBinding"
messageEncoding="Mtom"
transferMode="StreamedRequest"
maxReceivedMessageSize="2147483647"
closeTimeout="00:30:00"
openTimeout="00:30:00"
receiveTimeout="00:30:00"
sendTimeout="00:30:00">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
<readerQuotas maxDepth="32"
maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<!-- BEHAVIORS -->
<behaviors>
<serviceBehaviors>
<!-- TEST CASE SECURE BEHAVIOR -->
<behavior name="TestCaseSecureBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<serviceCertificate
storeLocation="LocalMachine"
storeName="My"
findValue="DistinguishedNameOfCert"
x509FindType="FindBySubjectDistinguishedName" />
<clientCertificate>
<authentication certificateValidationMode="ChainTrust"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<!-- SERVICES -->
<services>
<service name="StreamingMutualAuthTestCase.Web.Service.TestCaseServiceImplementation"
behaviorConfiguration="TestCaseSecureBehavior">
<!-- SERVICE -->
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="TestCaseBasicBinding"
contract="StreamingMutualAuthTestCase.Web.Service.ITestCaseService" />
<endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
The client configuration looks like this:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITestCaseService" closeTimeout="00:30:00"
openTimeout="00:30:00" receiveTimeout="00:30:00" sendTimeout="00:30:00"
maxReceivedMessageSize="2147483647" messageEncoding="Mtom"
transferMode="Streamed">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate" realm="" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<!-- BEHAVIORS -->
<behaviors>
<endpointBehaviors>
<behavior name="SecureClientBehavior">
<clientCredentials>
<clientCertificate
storeLocation="LocalMachine"
storeName="My"
findValue="DistinguishedNameOfCert"
x509FindType="FindBySubjectDistinguishedName"/>
<serviceCertificate>
<authentication certificateValidationMode="ChainTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="https://test7/TestCaseService/TestCaseService.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ITestCaseService"
contract="TestCaseService.ITestCaseService"
name="BasicHttpBinding_ITestCaseService"
behaviorConfiguration="SecureClientBehavior"/>
</client>
</system.serviceModel>
Once again, this will work just fine until I set IIS Client Certs to either Accept or Require.
Also, there is a 413 error in the IIS log...
2011-08-18 15:00:06 W3SVC1 10.39.8.111 POST /TestCaseService/TestCaseService.svc - 443 - 10.75.13.81 - - - test7 413 0 0
I've already designed an authentication service on top of my file upload service to work around the issues; but I'd really like to know if what I'm trying to do is 'do-able' or not.
Thanks a ton - Patrick
If you want to turn on client certificates in IIS you must do the same for your service (and client):
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
Your client must provide certificate to the proxy:
yourProxy.ClientCredentials.ClientCertificate.SetCertificate(...);
Also your server must trust these certificates so client certificates must be either issued by certification authority trusted by the server or they must be installed to LocalMachine\Trusted people store directly on the server.
WCF endpoints don't support "Accept client certificates" - you must either use client certificates or not.