How can I get serviceCredentials > windowsAuthentication > allowAnonymousLogons to work in WCF? - wcf

I have a WCF service exposed as a netTcpBinding.
On the service side:
<netTcpBinding>
<binding>
<security mode="Message">
<message clientCredentialType="Windows"/>
</security>
</binding>
</netTcpBinding> ...
// Service behavior
<behavior>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true" />
</serviceCredentials>
</behavior>
I am unable to access this service from a anonymous user on another machine. (Error: Negotiation failed redentials could not be verified.)
What does
<windowsAuthentication allowAnonymousLogons="true" />
do?
I want my service to be accessible to both windows and anonymous users over net tcp binding. I can do this using UserName validation, but how do I do this using Windows authentication?
Thanks

Have you set the AllowedImpersonationLevel on the client?
<behaviors>
<endpointBehaviors>
<behavior>
<clientCredentials>
<windows allowedImpersonationLevel="Anonymous"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
or
client.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Anonymous;

The MSDN article Debugging Windows Authentication Errors points out the need to combine your service configuration with the client configuration mentioned by #user1467261. It points to another article on impersonation in WCF for more detail - but glossing over it, the need to combine these settings is not entirely obvious.

Related

WCF with SSL doesn't use any certifacte and fails

I have created a WCF with several calls and I want to protect it with Transport security so it'll go over SSL.
So I configured SSL in webmatrix since I'm using VS2012 + IIS Express like you can see below.
HTTPs configured in Webmatrix on port 44330.
I updated my Web.config to support one endpoint with metadata on HTTPS and transportsecurity.
<system.serviceModel>
<services>
<service name="Counter" behaviorConfiguration="Behavior">
<endpoint address="https://localhost:44330/Counter.svc"
binding="wsHttpBinding"
bindingConfiguration="HTTPsBinding"
contract="ICounter">
</endpoint>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="HTTPsBinding">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Behavior">
<serviceMetadata
httpGetEnabled="false"
httpsGetEnabled="true"
httpsGetUrl="" />
</behavior>
</serviceBehaviors>
</behaviors>
Now when I run this in the browser it points me to the metadata at the HTTPS address like you can see below.
HTTP works but HTTPs fails.
And here is the problem, it doesn't use any certificate and I don't see anything.
"This page can't be displayed" without any certificate being used.
How do I fix this or what am I doing wrong?
I found it that my issue wasn't located in my WCF configuration since it worked the day before. After a lot of coffee, surfing and command lining I noticed that the issue was IIS Express and it's SSL bindings with netsh http ssl.
I was using the default IIS Express certificate (CN=localhost) because I didn't include any serviceCertificate like Sam Vanhoutte suggests.
Even when specify a certificate IIS Express only uses CN=localhost that needs to be in LocalMachine > Personal when starting IIS Express.
If that doesn't fix your problem, try to reinstall IIS Express.
(It will reinstall the CN=localhost certificate on the correct place - Don't forget to reenable SSL in Webmatrix)
I believe you need to specify your server certificate in your web.config
<behaviors>
<behavior name="wsHttpCertificateBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceCredentials>
<clientCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"
revocationMode="NoCheck"/>
</clientCertificate>
<serverCertificate findValue="CN=SSLCert"/>
</serviceCredentials>
</behavior>
</behaviors>

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.

"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.

Configure WCF to ignore authentication requirements inside IIS

Scenario:
Two websites (example.com, admin.example.com) that share the same wwwroot folder.
example.com allows only anonymous access
admin.example.com allows only windows authentication.
/Service/Awesome.svc returns a json object
Accessing the Awesome service using example.com works, while admin.example.com throws a NotSupportedException; "Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service."
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="WcfServices.AwesomeService"
behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="webHttpBinding"
contract="WcfServices.IAwesomeService"
behaviorConfiguration="jsonBehavior" />
</service>
</services>
</system.serviceModel>
How do I configure WCF to ignore the authentication requirement? I want the same behavior as if this were a web service or handler, just execute and return the awesome json object.
I think you're out of luck here. Give AWesome.svc anonymous access, and give anon access a user account that has no access to sensitive resources.
It sounds like you have two copies of the service, one under the website example.com and the other under admin.example.com. If admin.example.com needs IIS integrated (challenge/response) authentication then you're WCF service binding needs to be in Transport mode because IIS requires all admin.example.com resources to be Windows authentication. Try this configuration:
<bindings>
<basicHttpBinding>
<binding name="Binding1">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
If this doesn't work for you, you may want to try hosting the services in their own virtual directy so they are not at the mercy of what the website needs for security.
Good Luck.

netTcpBinding without Windows credentials?

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>