I'm trying to understand WCF and all of it's (complex) security options. I have developed a Wcf webservice with wsHttpBinding on localhost. I'm creating a Console Application that I will distribute to a few clients. Each client has it's own username and password which I will validate against my own database. To do so, I've followed the following tutorial on codebetter.com: http://codebetter.com/petervanooijen/2010/03/22/a-simple-wcf-service-with-username-password-authentication-the-things-they-don-t-tell-you/
- I got the selfsigned certificate, and granted permissions
- I got the server & client all setup and running perfectly on localhost to localhost.
Question 1:
I added the svc service using VS2010 Add Service dialog and it added the folowing tag to my app.config:
<certificate encodedValue="AwA<...>" />
For learning purposes, I changed that value a couple of times, but it did not had any effect. It kept working perfectly. I use Fiddler to see the encrypted communication.
Question 2: Deploy on Test server with SSL
I've deployed the Webapplication, hosting WCF service, on a Test server with IIS7.5 and SSL configured. When I tried the client application to connect to the test-server, it threw a generic error. I discovered that when I changed from https:// to http:// it worked. Fiddler showed nice http communication with encrypted values.
But I also want to use HTTPS, together with my message-level encryption. I think this is not possible. I got it all working, just set the Security Mode to "TransportWithMessageCredential" and it's done. But when I do that, I can remove all certificate info on the client, and it still works. Therefore I can make the conclusion that Transport security (kind of) overrules the Message security.
So am I making the right conclusion:
- Don't got https Transport security? Use certificates (pfx on server, cert on the clients)
- Got https Transport security? Don't use the certificates, SSL is enough.
I hope I make myself clear :). Many thanks in advance.
Below a few (anonymized) configs:
Server
<bindings>
<wsHttpBinding>
<!--The maximum size, in bytes, for a message that is processed by the binding-->
<binding name="Binding1" maxReceivedMessageSize="4194304">
<readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760"
maxBytesPerRead="10485760" maxNameTableCharCount="10485760" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" negotiateServiceCredential="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ApiWcfCustomBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNameValidator, SupplierAPI"/>
<serviceCertificate findValue="xxxxApiv3" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
* Client *
var endPoint = new EndpointAddress(new Uri(apiUrl), EndpointIdentity.CreateDnsIdentity(endpointDnsEntity));
var binding = new WSHttpBinding();
//binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.NegotiateServiceCredential = false;
using (var client = new SupplierServiceClient(binding, endPoint))
{
client.ClientCredentials.UserName.UserName = supplierUID;
client.ClientCredentials.UserName.Password = supplierPassword;
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
endpointDnsEntity);
}