WCF Certificate Authentication with Service Only (No Client Cert) - c#

I am currently using a netTcpBinding with Windows authentication (program written in C#). I will be moving away from the domain authentication (adding new clients that won't be on the domain) and am looking to set up a certificate security with username/pass authentication. From what I've been reading so far, I don't necessarily need a client certificate (which is good; I won't be able to install the service's certificate on every client). My thinking is the along the same lines as navigating to a secure website with a certificate from a trusted CA; it recognizes it's trusted and doesn't ask any questions or give any hassle, it just accepts the certificate!
So far I have the service certificate set up (we have a wildcard cert from GoDaddy), however I can't figure out what changes I have to make to the app.config file(s) to not require the client certificate.
Service app.config:
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</clientCertificate>
<serviceCertificate findValue="*.xxxxxx.com"
storeLocation="LocalMachine"
storeName="TrustedPublisher"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
Client app.config:
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
<message clientCredentialType="UserName" />
</security>
I'm aware I'll have to set up a custom validator for the username portion, but I figure one step at a time. Thanks, and let me know if you need further details.

change clientCredentialType to None. Also do this on the server config.

Related

WCF Certificate Based Authentication Issue. Service is Getting authenticated with an invalid Certificate

I'm a beginner with WCF services. Trying to implement a Certificated based authentication on a WCF service and facing an issue. The service expects a specific Certificate from the calling client. The server throws an authentication error if the client is not passing any certificate. But at the same time, the service call is passing authentication with any certificates provided by the client(The service suppose to authenticate if the client provides a specific certificate).
Following is the code snippet of server config :
Service Config :
<bindings>
<wsHttpBinding>
<binding name="MyWsHttpBinding" maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00">
<readerQuotas maxStringContentLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxArrayLength="2147483647"/>
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"/>
<message clientCredentialType="Certificate" algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" />
</clientCertificate>
<serviceCertificate findValue="e616ebcd940951794736624acc6484802018c8d4" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<CustomBehaviorExtensionElement/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="MyEndpointBehavior">
<MySchemaValidator validateRequest="True" validateReply="False">
<schemas>
<add location="App_Data\model-service.xsd"/>
</schemas>
</MySchemaValidator>
</behavior>
</endpointBehaviors>
<services>
<service name="MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint binding="wsHttpBinding" bindingConfiguration="MyWsHttpBinding" contract="MyExchangeService" behaviorConfiguration="MyEndpointBehavior" bindingNamespace="http://www.mycompany.com/exchange/"/>
<endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" name="mex"/>
</service>
</services>
The cause of the problem is the security mode you use is transport, so only the following code works:
<transport clientCredentialType="None" proxyCredentialType="None"/>
The following message settings have no effect:
<message clientCredentialType="Certificate" algorithmSuite="Default"/>
Change the value in transport to certificate, you can also download the wcf demo on the official website, there are examples of related certificate verification, and there are tutorials corresponding to the demo.
I see that the certificate validation mode used in your code is ChainTrust.
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" />
</clientCertificate>
As mentioned in Microsoft Docs, using ChainTrust means -
The certificate is valid if the chain builds to a certification authority in the trusted root store
Meaning, the client need not send certificate with the exact same thumbprint as mentioned in your service web.config. Infact, any certificate whose Root / Intermediate Certification Authority is present in your VM's Trusted Root Store will pass validation.
To make sure that the client is able to use only a specific certificate to authenticate to your service, change ChainTrust to PeerTrust and add the certificate to the trusted people store on your VM's Certificate Store (certmgr).
<authentication certificateValidationMode="PeerTrust" />
References:
MS Docs - Working with certificates in WCF
Authentication element in web.config
More info on Certificate Chain of Trust

WCF w/ mutual authentication

I'm trying to help troubleshoot a third-party self-hosted web service written in WCF that requires mutual authentication. The issue is that web service is returning a 401 Unauthorized. I've read several articles about how to write the client and server pieces in WCF to use mutual authentication, but I still have the following questions:
Once the client sends the client certificate, how does the WCF service determine whether or not to accept it as being an authenticated endpoint with access to the given resource. Does the certificate only need to be trusted by the service being able to find the certificate's root CA in the certificate store as a trusted root CA, or is there some mechanism that maps the certificate to a list of entities that have been identified as allowed to access the resource?
Normally when I've seen mutual authentication used, in Wireshark I see the server respond to a Client Hello and Certificate Request with a Server Hello, Certificate, and Certificate Request. However, in the case I am troubleshooting, I do not see the server send a Certificate Request. I believe the client is sending its certificate in encrypted data, but I'm not able to decrypt the data to see it. Is there a way to force the WCF service to send a Certificate Request with the Server Hello?
The configuration file has the following:
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</webHttpBinding>
</bindings>
I believe that's enough to indicate the client should authenticate with a certificate, but now how the service decides if that certificate is one that's allowed?
Your binding definition looks correct. The certificate is defined in the endpointBehaviors. It is a little hard to follow, because it is split-up in separate XML groups.
Here is an example of what is working for my projects:
<client>
<endpoint address="(address to our)WebService.svc"
behaviorConfiguration="behaviorConfig"
binding="webHttpTransportSecurity"
bindingConfiguration="bindingConfig"
contract="((your contract name))"
name="mainEndPoint">
<identity>
<certificateReference findValue="CN=((cert name like blah.blah.blah-blah.blah)), OU=((lookup)), O=((lookup))"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectDistinguishedName" />
</identity>
</endpoint>
</client>
<bindings>
<!-- you already have a good looking binding (above) -->
</bindings>
<behaviors>
<serviceBehaviors ...etc />
<endpointBehaviors>
<behavior name="behaviorConfig">
<clientCredentials>
<clientCertificate findValue="CN=((short name)), OU=((lookup)), O=((lookup))"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectDistinguishedName" />
<serviceCertificate>
<defaultCertificate findValue="CN=((same content from certificateReference above)), OU=((lookup)), O=((lookup))"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectDistinguishedName" />
<authentication certificateValidationMode="PeerTrust"
revocationMode="NoCheck"
trustedStoreLocation="LocalMachine" />
</serviceCertificate>
</clientCredentials>
<callbackTimeouts />
</behavior>
</endpointBehaviors>
</behaviors>

WCF showing 403 Forbidden using SSL and client certificates

We are having a problem with WCF - we are getting the error below when trying to connect. There are tons of suggestions for various configurations, having tried them all we could use some help.
We are using HTTPS for transport security, using a real SSL certificate that we got from GoDaddy. It seems to be installed and working properly when we browse to web pages on the site. With no authentication, we can connect properly to our WCF service.
For authentication, we are using client certificates that we created ourselves. These client certificates were working fine before we switched to HTTPS, when we were using message security with a self-signed server certificate (which was a pain because we had to get the clients to install the server certificate).
Error
The HTTP request was forbidden with client authentication scheme 'Anonymous'.
Inner exception: The remote server returned an error: (403) Forbidden
Server configuration file
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WcfService1.Service1">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0" contract="WcfService1.IService1" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
<serviceCertificate findValue="....." x509FindType="FindByThumbprint" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="https" binding="wsHttpBinding" bindingConfiguration="NewBinding0" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Client configuration file
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior0">
<clientCredentials>
<clientCertificate findValue="customuser1"
storeName="TrustedPeople" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://www.insertoursitename.com/WcfService1/Service1.svc"
behaviorConfiguration="NewBehavior0" binding="wsHttpBinding"
bindingConfiguration="NewBinding0" contract="ServiceReference1.IService1"
name="wsHttpBinding_IService1" />
</client>
</system.serviceModel>
My problem was very similar to yours, and i'll describe my scenario before answering the question.
Created a simple WCF service (using custom binding, but that's irrelevant).
Created a self-signed RootCA using makecert, and generated two certs tempCertServer.cer used for SSL encryption, configure IIS to require https, etc.
--> Tested this part, worked ok from the Browser from a different computer.
The second cert tempCertClient.cer was used as a client-cert to be presented to IIS, configure IIS to Require client-cert, etc. --> Tested this part from a browser (best to use IE since you can easily clear SSL state). I get a prompt to choose a client cert, but never connects, the error is exactly the same as per the question:
"The HTTP request was forbidden with client authentication scheme 'Anonymous'. Inner exception: The remote server returned an error: (403) Forbidden."
Replaced tempCertClient with a proper cert (from a known CA), there was no issue, connection was established and WCF page shown; No matter what i tried with the self-signed client cert, always getting above error.
Wasted a whole day++ trying various settings, reading blogs on registry changes, placing the cert server-side under different cert stores, changing config file settings, etc, with no resolution.
The answer was very simple, inspect the LocalComputer\Trusted Root Certification Authorities server-side, and remove any NON-ROOT CA's (i.e. those that should not be there, IssuedTo NOT EQUALS IssuedBy)
The client-cert itself did not need to be installed on the server, only a Root CA that can validate it has to be installed in LocalComputer\Trusted Root Certification Authorities server-side.

Securing WCF using Certificates for Transport Mode

I am using WCF service with Transport mode. I need to make this service secure using Certificates.
I followed the steps given in the below link and got it working in my local
http://www.codeproject.com/Articles/36683/simple-steps-to-enable-X-certificates-on-WCF
The issues i am facing now are:-
In the above mentioned steps, i had the service running locally as well as my client application that calls the service, running locally. Now for my QA deployment i have the service hosted on one server and my Client application on another server.
I dont have visual studio commant prompt in both these servers to create the certificates using makecert.
My service will be in https.
I will be using some third party to get the certificates for my production, but now i am not able to figure out how to get this working for my QA environment.
I have tried creating a Certificate to Act as Root Certificate Authority and installed it in both the servers. In this approach also i am stuck as to how will i create my client and server certificates under this root authority.
Kindly let me know how can i get this working.
Thanks in advance.
Finally got it working. I had to create certificates using makecert in my local and then had to import them in my QA environment (will be using certificates from a trusted third party for my production environment). My requirement was to make my service secure and not allow unauthorised clients to consume it.
My service web-config.
Changes in the binding
<bindings>
<basicHttpBinding>
<binding name="basicHttpEndpointBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings
Changes in behavior.
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
</clientCertificate>
</serviceCredentials>
My Client web-config.
Changes in binding
<binding name="">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" />
</security>
</binding>
Add behavior
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="RootCATest"
x509FindType="FindByIssuerName"
storeLocation="LocalMachine"
storeName="My"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Attach this behavior to the endpoint
behaviorConfiguration="CustomBehavior"

Add additional SSL behavior for WCF endpoint within Azure Web Role

Our azure web application already uses https port 443 with our site certificate, we have a WCF service within this webrole that has an https endpoint using our cert to authenticate (1-way ssl), this same service needs an additional https endpoint supporting 2-way auth using our cert and the third party's cert. We have uploaded the cert, updated the service definition file, and added an endpoint that we are hoping will work, but in testing we are getting the error: The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'None'.
so the endpoint that does work is: https://environemnt.application.com/Services/Service.svc
the endpoint that generates the error: https://environment.application.com/Services/Service.svc/twa
The key requirement is that it is https, port 443, at the above new endpoint, without altering the SSL behavior of the rest of the role, I have seen entries to change the IIS configuration or use the role editor to add an Https Input endpoint, but as we already have an Https Input endpoint on port 443 using our site cert I don't want to alter/affect the whole role.
If it is helpful the service is a WCF Service which consumes an Mtom encoded soap 1.2 message
here are the new values that we have entered, what else do I need?
<behaviors>
<serviceBehaviors>
<behavior name="SSLServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="OneWayAuthEndpointBehavior">
</behavior>
<behavior name="TwoWayAuthEndpointBehavior">
<endpointDiscovery enabled="true"></endpointDiscovery>
<clientCredentials>
<clientCertificate findValue="thumprint..." storeLocation="LocalMachine" storeName="CertificateAuthority" x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="SSLServiceBehavior" name="Service">
<endpoint address="" behaviorConfiguration="OneWayAuthEndpointBehavior"binding="wsHttpBinding" bindingConfiguration="HttpsMtomOneWay" contract="ITestService" />
<endpoint address="twa" behaviorConfiguration="TwoWayAuthEndpointBehavior" binding="wsHttpBinding" bindingConfiguration="HttpsMtomTwoWay" contract="ITestService"/>
</services>
<bindings>
<wsHttpBinding>
<binding name="HttpsMtomOneWay" messageEncoding="Mtom">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
<binding name="HttpsMtomTwoWay" messageEncoding="Mtom">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
thank you much
Fixed through these steps:
Added serviceCredentials.serviceCertificate (cert details for our cert) to the service behavior
Eliminated Endpoint behavior definitions
Changed the HttpsMtomTwoWay binding to securityMode=Message
Now the message handlers handle the authentication exchange and external cert validation, then pass on to the transport endpoint, and we did not need to mess with the site wide SSL or endpoint settings. Tested and verified with numerous 3rd parties.

Categories

Resources