Disabling X.509 certificate validation in .NET with WCF service - c#

I am trying to set up message security in a WCF service and disable the X.509 certificate validation in the process. I'd like to validate the client with a username and password only and not validate the server at all. At least for now.
Referring to the first answer here:
How do I tell WCF to skip verification of the certificate?
How do I achieve the following programmatically on the client?
<behavior name="DisableServiceCertificateValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="Custom"
customCertificateValidatorType="MyCertificateValidator, Client"
revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
I have got this:
With myServiceClient.ClientCredentials
.UserName.UserName = "username"
.UserName.Password = "password"
.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom
.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck
End With
I can't work out how to set the "customCertificateValidatorType" and how to wire it to the MyCertificateValidator class.
Does this bypass the requirement of a client certificate, a server certificate or both?
Here is my server web.config file.
<?xml version="1.0"?>
<configuration>
<system.web>
<customErrors mode="Off"/>
<trust level="Full"/>
<compilation debug="true"/>
</system.web>
<system.serviceModel>
<services>
<service name="HelloWorldService.HelloWorldService" behaviorConfiguration="BehaviourMessageSecurity">
<endpoint address ="" binding="wsHttpBinding" contract="HelloWorld.IHelloWorldService" bindingConfiguration="BindingMessageSecurity"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://www.example.com/HelloWorldService.svc"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BehaviourMessageSecurity">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="HelloWorldService.ServiceAuthenticator, HelloWorldService" />
<serviceCertificate findValue="localhost" x509FindType="FindBySubjectName"
storeLocation="LocalMachine" storeName="My" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="BindingMessageSecurity">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>

Czustom means you write your own validation method. If you don't want to check the certificate at all, use None:
.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None

Related

WCF custombinding mutualcertificate keep getting 'The request message must be protected' error

i have a server with wcf soap services. With simple httpbinding configuration everything worked perfectly.
After I changed the web.config to custombinding I keep getting the same error :
The request message must be protected. This is required by an operation of the contract ('IMyServices','http://tempuri.org/'). The protection must be provided by the binding ('BasicHttpBinding','http://tempuri.org/').
This is my web.config :
<system.serviceModel>
<bindings>
<customBinding>
<binding name="MyBinding">
<textMessageEncoding messageVersion="Soap11WSAddressingAugust2004" />
<security authenticationMode="MutualCertificate" requireDerivedKeys="false"
messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
<httpTransport keepAliveEnabled="false" />
</binding>
</customBinding>
</bindings>
<services>
<service behaviorConfiguration="MyBehavior" name="NewWCF.MyServices">
<endpoint address="" binding="customBinding" bindingConfiguration="MyBinding"
name="wsHttpMembershipEndpoint" contract="NewWCF.IMyServices" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://10.130.111.111/NewWCF" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceCredentials>
<clientCertificate>
<certificate findValue="CN=Central-Gateway" x509FindType="FindBySubjectDistinguishedName" storeName="TrustedPeople" />
<authentication revocationMode="NoCheck"
certificateValidationMode = "None"/>
</clientCertificate>
<serviceCertificate findValue="CN=MySrvTst" x509FindType="FindBySubjectDistinguishedName" storeName="My" storeLocation="LocalMachine" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceSecurityAudit serviceAuthorizationAuditLevel="SuccessOrFailure"
messageAuthenticationAuditLevel="SuccessOrFailure" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
lang-xml -->
Both certificates appear correctly in mmc.exe
I try to test it through a browser calling .svc path , should it work that way or does it fail because of the certificates ?
Is there a way to see a more detailed error?
What can be the problem?
Thanks in advance,
Brian.

WCF wsHttpBinding Certificate Security Negotiation Exception

So after having combed through MSDN, countless articles and even SO - I still have nothing to show for days of struggle.
So I have this: WCF service needs to be consumed by a client and I just keep hitting a SecurityNegotiationException
Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.
I've seen this error all over the net and noone seems to have my exact scenario (with a feasible answer atleast).
My setup is local and not hosted by IIS (for time being) but hosted via Visual Studios 2010. My GenericIntegration (WCF service) makes use of wsHttpBinding (Message Mode) authenticated by certificates (I have a very custom username/password authentication + authorization class passed as a parameter by design) and there is no backing out of the security measures.
Host's Config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpintBinding">
<security mode ="Message">
<message clientCredentialType="Certificate" establishSecurityContext="false" negotiateServiceCredential="false"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="wsHttpBehaviour" name="GenericIntegration.GenericService">
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpintBinding"
name="wsHttpEndpoint" contract="GenericIntegration.GenInterface" />
<host>
<baseAddresses>
<!--<add baseAddress="http://localhost:59082/GenericService.svc" />-->
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttpBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<certificate findValue="GenIntegrationClient" storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
<serviceCertificate findValue="GenIntegrationClient" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
And the Client's config
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="endpointBehaviour">
<clientCredentials>
<clientCertificate findValue="GenIntegrationClient" storeLocation="LocalMachine" storeName="My"
x509FindType="FindBySubjectName" />
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" revocationMode="NoCheck"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpoint" maxBufferPoolSize="20000000" maxReceivedMessageSize="20000000">
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:59082/GenericService.svc"
binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" behaviorConfiguration="endpointBehaviour"
contract="GenService.GenInterface" name="wsHttpEndpoint">
<identity>
<certificate encodedValue="AwAAAAEAAAAUAAAAKdyUELIKMtdh2MFsYQ09ja+vyeEgAAAAAQAAACICAAAwggIeMIIBi6ADAgECAhCFBfF1EXQZhkPKaBpQCl84MAkGBSsOAwIdBQAwJDEiMCAGA1UEAxMZNE1PU1RHZW5JbnRlZ3JhdGlvblNlcnZlcjAeFw0xNjA3MjgxNDQ5MjVaFw0zOTEyMzEyMzU5NTlaMCQxIjAgBgNVBAMTGTRNT1NUR2VuSW50ZWdyYXRpb25DbGllbnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIwsIlz5nZ3HxeYofTpYKr6RcfQMe/jZxPuHcljT+8pBOZ6KmYcyxeRTO074yP6yF8b1IqFskII+qqmCT8nDsb8xdo5Ee0oqL1LKR+xeTgg2ZXXoocxqR1AdxWFVdlMxMSjKIEGE+MnSDdB6vgXahhpUbAS7cdrNoAFKNIz+vrt1AgMBAAGjWTBXMFUGA1UdAQROMEyAEB4cu6OjBqQHct6przmowGyhJjAkMSIwIAYDVQQDExk0TU9TVEdlbkludGVncmF0aW9uU2VydmVyghD75YH5y52zsU5wcmZLJzPiMAkGBSsOAwIdBQADgYEA2BinUmEfgZKcb1qFD1T5ajc2OWHGLjDLpDi8Y7amM4P3rFGvelx7NmCNUH88iGS9LcbDsmY59HcZwUavtPOr4LMRDhl+5YuGht1fIYEk8QSDIhjevijgDOIVBBAeNIA8tva1faMNtYnFXsj0VxMvlrZ4exeKFVFjv2sib5YNFxY=" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Now about the certificates (and yes this is for testing only): GenIntegrationServer.cer has been created as a selfsigned CA root certificate with a private key to sign client certificates with. Both GenIntegrationServer and GenIntegrationClient certificates were generated with makecert. The client certificate is linked to the private key and is correctly installed in the personal store.
I am still quite new to certificates, private keys and secure comms - I simply cannot reason where I make my mistake. I didn't find too many posts about specifically using certificates in this manner.
Can anyone assist before I lose more hair or sleep over this?
UPDATE
As per request, I added the logging. But the most they reveal is:
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
<s:Subcode>
<s:Value>a:InvalidSecurity</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-ZA">An error occurred when verifying security for the message.</s:Text>
</s:Reason>
</s:Fault>
</s:Body>
Sadly, I still do not understand why security validation is failing. Any Ideas?
Turns out I needed to add the certificates to different stores.
In addition to already having the certificates set in the personal stores (as indicated by the config), I had to install the the server's certificate on the client and vice versa. I also had to make sure that the client contained the client certificate's personal key and the same with the server.
This does not sound too complete but I'll post a full article on how I did this.

WCF Over HTTPS (Message & Transport) 404 Error (Page Not Found)

I've WCF service that is working great with authentication and Message Security Type.
But I need to communicate with the WCF over https (its have to be in the url), so I need to add Transport Security Type.
(I'm using self sign certificate)
This is my binding config:
<bindings>
<wsHttpBinding>
<binding name="Binding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
This is my Services config :
<services>
<service name="WcfService1.Service1" behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="https://localhost/Service1.svc"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding" contract="WcfService1.IService1" />
</service>
</services>
This is my Behavior config:
<behavior name="MyServiceTypeBehaviors" >
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.UserValidate,WcfService1"/>
<serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
But like a true WCF Service nothing goes smooth:
When I execute the WCF its automatically open the page : "http://localhost:22535/" in the browser instead of https like I specified in the base address.
When I open the page (no https) "http://localhost:22535/Service1.svc" I get the error :
Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http].
When I try to reach the page "https://localhost/Service1.svc" which I specified in the base address i get:
This webpage is not available
This is my entire Web.Config :
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="https://localhost/Service1.svc"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding" contract="WcfService1.IService1" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="Binding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<!--My Custom Behavior-->
<behavior name="MyServiceTypeBehaviors" >
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.UserValidate,WcfService1"/>
<serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Thanks in advance.
Update
I've set the IIS application to bind on Https (Thanks Daniel Holmkviste).
Now I get 404 (not found) for the base address. ("https://localhost/Service1.svc")
But the good news I have a green lock and when I press it i see "LocalHost" with identity verified.
But why now it cant find the page ?
The Http (the automatically URL address when execute the wcf from the VS) "http://localhost:22535/Service1.svc" still give this error :
Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http].
Finally! the answer is to turn the HTTP Activation On.
Search "Turn Windows Features on or off" in windows.
Open .NET Framework 4.5 Advanced Services
Open WCF Services
Check HTTP Activation
Specify the metadata.
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetaDataExchange"/>
To enable https in VS you have to configure the properties of your project to use IIS.

WCF REST Service with Windows Authentication and SSL

I have WCF Rest Service that is being consumed by android, iOS and asp.net web application. all endpoint methods return json format so I use webHttpBinding. Problems started when I secured the service by activating Windows authentication(disabled Anonymous before that). When I try to add Service reference from the asp.net web application I receive the following error:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'.
The remote server returned an error: (401) Unauthorized.
When I call endpoints in browser windows dialog is being showed with username and pass and everything works fine, but When I try to add the reference I receive the error. I'm also using SSL and the service has only https address.
web.config wcf rest service:
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" executionTimeout="90" maxRequestLength="20000" useFullyQualifiedRedirectUrl="false" requestLengthDiskThreshold="8192" />
<authentication mode="Windows" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<bindings>
<webHttpBinding>
<binding name="WebHttpEndpointBinding" maxReceivedMessageSize="200000000" maxBufferPoolSize="200000000">
<readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="restSrvService.restSrvRestService" behaviorConfiguration="serviceBehavior">
<endpoint address="" name="webHttpEndpoint" binding="webHttpBinding" bindingConfiguration="WebHttpEndpointBinding" behaviorConfiguration="web" contract="restSrvService.IrestSrvRestService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceAuthenticationManager authenticationSchemes="IntegratedWindowsAuthentication" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<endpointDiscovery enabled="true">
</endpointDiscovery>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
web.config web application:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules>
</system.webServer>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="WebHttpEndpointBinding" bypassProxyOnLocal="true" useDefaultWebProxy="true" maxReceivedMessageSize="200000000" maxBufferPoolSize="200000000">
<readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
<security mode="Transport">
<transport clientCredentialType="Windows"></transport>
</security>
</binding>
</webHttpBinding>
</bindings>
<client>
<endpoint address="https://serviceAddress/restSrvRestService.svc/"
binding="webHttpBinding" bindingConfiguration="WebHttpEndpointBinding"
contract="restSrvService.IrestSrvRestService" behaviorConfiguration="webEndpoint" name="WebHttpEndpoint">
<identity>
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="webEndpoint">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>

WCF with windows authentication problems

I am building wcf aplication that will work only with users that have User+Password to the windows where this wcf is located.That mean is my wcf located on server X and i call function GetData(5) i will see the logon form (the same users that in windows) and entered User+Password and then get data back, my main goal is to pass User+Password to avoid this logon window,but now i can't forse my wcf to ask for windows authentication,it is returning data to everyone.
What i am doing wrong?
I am using Vs2012(4.5)
P.s if any one have example of wcf that use windows authentication i
will be very happy to see it.
My webConfig
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<authentication mode="Windows" />
<identity impersonate="false" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="WcfService10.Service1">
<endpoint address="WCF10" binding="basicHttpBinding" bindingConfiguration="NewBinding10"
contract="WcfService10.IService1" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="NewBinding10">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Windows" customUserNamePasswordValidatorType="Type, Assembly" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
To pass alternative windows credentials to a service, use the following code:
var proxy = new MyServiceClient();
proxy.ClientCredentials.Windows.ClientCredential.Domain = "MyDomain";
proxy.ClientCredentials.Windows.ClientCredential.UserName = "MyUsername";
proxy.ClientCredentials.Windows.ClientCredential.Password = "MyPassword";
proxy.DoSomething();
proxy.Close();
Here one config with webHttpBinding and Windows Transport security. You have to change the service name, baseAddress, contract="Server.IServicemame"
<system.serviceModel>
<!--Services-->
<services>
<service name="Server.servicemame">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9011/servicemame/service"/>
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding" contract="Server.IServicemame" bindingConfiguration="HttpBindingWithSecurity">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<!--Behaviors-->
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="false" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<!--Bindings-->
<bindings>
<webHttpBinding>
<binding name="HttpBindingWithSecurity">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>

Categories