netTcpBinding without Windows credentials? - wcf

I've got a machine-control application where I have a single client computer and five server boxes communicating on the machine subnet. There is no domain controller. I would like to use netTcpBinding to allow for reliability and transaction support.
Is is possible to use username / password authentication with this binding, when a domain controller is not present? I would prefer not to use a certificate as I don't want to manage certificates across 900 computers (150 machines) that will not be connected to the office LAN.

Yes, of course - but only if you use Message security (rather than transport security). Define your binding configuration like so:
<netTcpBinding>
<binding name="UserNameSecurity">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</netTcpBinding>
and then reference that binding configuration in your endpoints (on server and client):
<endpoint address="....."
binding="netTcpBinding"
bindingConfiguration="UserNameSecurity"
contract="IMyService" />
Marc
UPDATE:
Ah, yes, on the server-side, you'll need a certificate to authenicate the service to the client calling it, and it's also used to encrypt+sign the messages. That's on the server only - clients need not install anything.
Configuration:
<behaviors>
<serviceBehavior>
<behavior name="ServerInternet">
<serviceCredentials>
<serviceCertificate
findValue="MyServiceCertificate"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehavior>
</behaviors>
<services>
<service name="MyServiceInternet"
behaviorConfiguration="ServerInternet">
....
</service>
</services>
Make sure to install your server's certificate into the "Local Machine" folder on your server, under the "subject name" that you specify in your config.

There is something you can try first. Set serviceNegotiationCredentials to true:
<message negotiateServiceCredential="true"/>
This will create a secure conversation between your client and your service without a domain controller.
BUT, if there isn't any domain controller, the client doesn't trust your service, so it will fail.
So you should set the expected identity of the service. You can find that in the WSDL of your service. By default, if you are hosted on IIS, it seems to be:
<client>
<endpoint>
<identity>
<servicePrincipalName value="host/NETWORKSERVICE"></servicePrincipalName>
</identity>
</endpoint>
</client>
I don't think you'll need it, but maybe you'll have to allow anonymous logon on the service side:
<serviceBehaviors>
<behavior>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>

Related

Test WCF with Mutual Certificate Authentication using SOAPUI

I´m trying to test a WCF service with mutual certificates authentication using a client on C# and it works; now I want to test the service using SOAP UI.
This is the service configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="WS_XXXXX.WcfXXXX">
<endpoint address=""
binding="customBinding" bindingConfiguration="XXXSoap" bindingNamespace=""
contract="IXXXSoap" >
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:47037/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<customBinding>
<binding name="XXXSoap">
<security authenticationMode="SecureConversation"
requireSignatureConfirmation="false"
canRenewSecurityContextToken="true"
messageProtectionOrder="SignBeforeEncrypt"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11"
requireDerivedKeys="false" >
<secureConversationBootstrap
authenticationMode="MutualCertificate"
requireSignatureConfirmation="true"
canRenewSecurityContextToken="true"
messageProtectionOrder="SignBeforeEncrypt"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11"
requireDerivedKeys="false">
</secureConversationBootstrap>
</security>
<textMessageEncoding messageVersion ="Soap11WSAddressingAugust2004" >
</textMessageEncoding>
<httpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior" >
<serviceCredentials>
<serviceCertificate findValue="WCfClient"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
I read some info on how to test a WCF service with service certificate on SOAPUI; but because of the WCF configuration (mutual certificates), I don´t know how to configure the SOAP UI for test the WCF web service.
Thanks in advance.
When we use mutual certificate mode to authenticate the client and protect the server communication. We need to establish the trust relationship between the client and the server, then we provide the client certificate on the clients-side when calling the service. For some kinds of WCF created with message security, we might need to on the client-side provide the service certificate that the server-side used.
Anyhow, we at least a client certificate on the client-side. In SOAPUI, we are able to configure the client certificate for one request or all request.
Here are steps details.
1. Export your certificate that your client needs to provide by using the export wizard.
2. Please tick “export the private key” option.
3. Input your password.
4. Set up the certificate for all request. the menu locates in the main toolbar File > Preferences.
Result.
For sending https request for one, please refer to the below link. It is similar to these steps.
https://www.soapui.org/docs/functional-testing/sending-https-requests.html
Feel free to let me know if the problem still exists.

WCF Self hosted REST server (https) keeps asking for client authentication

I created a self hosted WCF REST server (w/o IIS). When I enable SSL support, I am keep asked for a Client Certification when I test the site in Chrome.
Below is my app.config of which I believe I disabled the client authentication. Is there anything that I am missing here?
photo :
Chrome asking for client certificate
App.config code :
<system.serviceModel>
<services>
<service behaviorConfiguration="ADConnectorLibrary.Service1Behavior" name="ADConnectorLibrary.ADConnectorLibrary">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpTransportSecurity" behaviorConfiguration="web" contract="ADConnectorLibrary.IADConnectorLibrary" >
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="https://ADDRESS:8888/ADConnectorLibrary/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ADConnectorLibrary.Service1Behavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
**<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" />
</clientCertificate>
</serviceCredentials>**
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity">
<security mode="Transport">
**<transport clientCredentialType="None" />**
</security>
</binding>
</webHttpBinding>
</bindings>
The only thing you need to do is disable the SSL setting when hosting the service in IIS.
On my side, I create a console application to host the service and bind the sslcert to the specified port with the following command. when the client calls it via browser, it does not pop up a dialog box and prompted me to select the client certificate.
netsh http add sslcert ipport=0.0.0.0:8000
certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6
appid={00112233-4455-6677-8899-AABBCCDDEEFF}
Maybe we don't need to open the support client certificate,or disable it.
clientcertnegotiation=disable
Here is the official document, wish it is useful to you.
https://learn.microsoft.com/en-us/windows/desktop/http/add-sslcert
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
Feel free to let me know if there is anything I can help with.
Since you are using TransportSecurity, I believe you need to assign a certificate to your service otherwise it will not be able to encrypt the message via SSL over HTTPS.
Likewise the client would have to trust that certificate, or will get one of these reponses when the client tries to access the service via HTTPS in a brower, and calls from code will fail.
You probably need to use netsh, since you are not using IIS. You might need to reseach netsh a bit to fit your needs.
Something like this to register the cert to the port and map to the application guid: This is a pure made up example: netsh http add sslcert ipport=127.0.0.1:8000 certhash=c20ed305ea705cc4e36b317af6ce35dc03cfb83d appid={c9670020-5288-47ea-70b3-5a13da258012} clientcertnegotiation=enable
you probably don't need this since you are not apply a certificate:
**<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" />
</clientCertificate>
</serviceCredentials>**

Custom UserName/Password authentication in IIS6

I have a WCF service I'm hosting in IIS6. I'm trying to set up custom username/password authentication using Transport level security. I've set up a test certificate and got a client to connect over SSL with no authentication specified, i.e:
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
I've set up a custom validator with Message security and client credential type "UserName", but I'd like to incorporate this now with Transport level security. When I have my web.config set, when I try to view the WSDL, I get an error:
"Security settings for this service require 'Basic' Authentication but it is not enabled for the IIS application that hosts this service."
Here are the important parts of my web.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="UserNameBinding">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceAuthenticationBehavior"
name="Service.WebServices.MyService">
<endpoint address="mex" binding="mexHttpsBinding" bindingConfiguration=""
name="mexBinding" contract="IMetadataExchange" />
<endpoint binding="wsHttpBinding" bindingConfiguration="UserNameBinding"
name="wsHttpBindingWithAuth" contract="Service.WebServices.IMyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceAuthenticationBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="TestCert01" storeLocation="LocalMachine"
storeName="TrustedPeople" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Service.WebServices.ClientCredentialsValidator, Service.WebServices" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Is there something I'm supposed to set in IIS6 to enable this?
In IIS, I started initially with the "Enable anonymous access" option enabled. I also tried enabling "Basic authentication (password is sent in clear text)" checkbox, but no success.
This post seems to suggest that Basic is only available for Windows account, with a 3rd party solution...
Basic Authentication with WCF REST service to something other than windows accounts?
I've been here myself, and ended up going with 1-legged openauth which worked nicely.
edit
this post sent me well on my way to a solution http://www.cleancode.co.nz/blog/523/oauth-dot-net
its worth mentioning the diff between 1 and 2-leg OAuth. 1-leg is where the client and the service both know the client's secret (password) for the client's account name which is used to encrypt and decrypt the authentication request (which all gets added to the querystring). with 2-legged, this is generated by a 3rd party such as google, facebook etc.

Configuring WCF Transport security for IIS6 over SSL

I've been attempting to set up WCF transport security using SSL on IIS6.
The client is on a seperate machine on the same domain.
I understand the premise of certificates, root CA etc and have a working set of certs for message security and can use these no probs in the same enviroment set up. (i've learn't a lot over the last week :)
I'm having an nightmare trying to get my client to authenticate against the IIS 6 service when i switch it to SSL. Always recieving 'annonymous authetication not allowed' when calling.
IN IIS i have
a root signed CA cert set on the site for SSL port 443
(if i browse the https:// svc page i can see the IE padlock and the page says you need a cert to communicate)
under secure communications i have
require SSL channel
require 128 bit encryption
require client certificates
enable client certificate mapping (set up with a many to 1 mapping to a admin account on the IIS box for now matched on the cert subject O field )
under web site security (authentication and access control)
Anonymous access = ON
Intergrated Windows Authentication = OFF
basic Authentication = ON
For the client wsHttpBinding i have a certificate ready to authenticate and a custom endpoint behaviour to supply this info but i don't think its getting this far!
UPDATED SERVER CONFIG
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="CertificateWithTransport">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WCFServiceCertificate.Service1" behaviorConfiguration="credentialConfig">
<endpoint address="https://svnvmig02/Service1.svc"
binding="wsHttpBinding"
bindingConfiguration="CertificateWithTransport"
contract="WCFServiceCertificate.IService1">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="credentialConfig">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
UPDATED CLIENT CONFIG
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://svnvmig02/Service1.svc" binding="wsHttpBinding" behaviorConfiguration="CustomBehavior"
bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
name="WSHttpBinding_IService1">
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="svnvmig02" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
EDIT:
Probably worth mentioning that my VS projects are 3.5 but IIS6 is running .net4
With the amended config (thanks Fabio ;) i can now IE browse the address https://svnvmig01/Service1.svc from the client machine and see the generated svc page which allows me to click on the wsdl URl which is also available.
The majority of the pages i have found on the net refer to selfhosting or IIS7....I'm hoping IIS7 support is better ;)
Any help would be greatly appreciated :)
Your config includes:
https://svnvmig02:8091/Service1.svc
The normal port for ssl is 443.
It may be that the request is not going to the site that you expect it to go to. Therefore, you are getting and unexpected error message.
Check the IIS logs to make sure which site is receiving the request.
I think your issue here may be that you have IIS set to:
Anonymous access = OFF
I use transport security on several of my servers, and all the IIS6 ones have that setting ON, not OFF. This also corresponds to the error message you provided:
'annonymous authetication not allowed'
Without anon access off, IIS will either want the user to enter a username/password, or pass along a windows / active directory / kerberos credentials.

"The caller was not authenticated by the service" when using a customBinding only on machines on a domain

I wrote a WCF service hosted by IIS 6 on a server that is not part of a domain. It uses the following configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Services.DeliveryStatsService">
<endpoint address="" binding="customBinding" bindingConfiguration="BindingWithMaxClockSkewForIncorrectlyConfiguredWindowsServer"
contract="Services.IDeliveryStatsService" />
</service>
</services>
<bindings>
<customBinding>
<binding name="BindingWithMaxClockSkewForIncorrectlyConfiguredWindowsServer">
<binaryMessageEncoding />
<security>
<localClientSettings maxClockSkew="00:20:00" />
<localServiceSettings maxClockSkew="00:20:00" />
<secureConversationBootstrap />
</security>
<httpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
It would've been a simple basicHttpBinding, except that the server's clock is not set to the right time and its administrator will not change that, so a customBinding is required to allow for "clockSkew."
Clients use pretty much the same configuration (binding-wise) and can access the service without any trouble, as long as they are not part of a domain. However, clients that are part of a domain are rejected with the message "The caller was not authenticated by the service."
I turned on tracing and it would seem that the problem comes from a token exchange using SSPI negociation. Unfortunately, I can't seem to find the right configuration that will allow both machines that are not part of a domain and machines that are part of a domain to access the service. I have tried several values for authenticationMode, without avail. What's more, as far as I'm concerned, I don't need any particular security on this service.
WCF configuration is far from being my specialty and I haven't found an answer anywhere else, so I hope someone at Stack Overflow will be able to help. Thanks in advance.
Why do you need to set maxClockSkew when you don't need security? It is for handling time differences in timestamps which are not send without security. Once you add security element you turn on authentication because all attributes in the element have default values. Default value for mode is sspiNegotiated. I would start with removing security element.