WCF sessions with HTTPS - c#

I cannot figure out how to enable per-session instances for my WCF service while using HTTPS. (I'm not an ASP.NET expert but don't want to use ASP.NET session state if possible.) I am using .NET Framework 3.0.
I have arrived at the following contradiction and am hoping that someone can tell me where there is a flaw in the logic.
1) The service must be hosted on IIS 6 due to client mandate.
2) The service needs to maintain state between calls, including SqlConnection and SqlTransaction instances (ugly but necessary due to project constraints).
3) Therefore I need to use the wsHttpBinding.
4) The service needs to be able to access user authentication info from HttpContext.Current.User.Identity (e.g. using Windows security in IIS).
5) HTTPS is therefore required.
6) Transport-level security must therefore be configured on the binding.
7) Configuring the service to require sessions means I have to configure the wsHttpBinding to use Reliable Sessions.
8) This requires that message-level security is configured on the binding.
I.e. (6) and (8) are mutually exclusive.
It seems that using WCF sessions requires that I use message-level security, which prevents me from using HTTPS.
What am I missing?

3) True, wsHttpBinding and wsDualHttpBinding are the only HTTP bindings that support sessions
5) False, in order to authenticate the service callers you don't necessarily need to have any transport-level security (such as SSL/HTTPS). The only requirement is to configure IIS to enable Integrated Windows Authentication for a virtual directory. Then in WCF you have three possibilities to enable this scenario:
a) Use transport-level security on the wsHttpBinding with Windows credentials (HTTPS)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="SecurityEnabledWsHttp">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
b) Use message-level security on the wsHttpBinding with Windows credentials (HTTP)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="SecurityEnabledWsHttp">
<security mode="Message">
<message clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
c) Run your service under the ASP.NET Compatibility Mode and enable Windows Authentication in ASP.NET (HTTP)
<system.web>
<authentication mode="Windows" />
</system.web>
Note that in a and b you will access the identity of the caller from within a service this way:
OperationContext.Current.ServiceSecurityContext.WindowsIdentity
6) True, transport-level security must be enabled on the wsHttpBinding in order to use HTTPS
7) False, Reliable Sessions is a particular implementation of Reliable Messaging for WCF sessions. Reliable Messaging is a WS-* standard specification designed to guarantee message delivery on an unreliable network. You can use WCF sessions without Reliable Messaging, and viceversa. Sessions are enabled on the service contract with this attribute:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IMyService {
// ...
}
Also remember that in order to maintain state between service calls you will explicitly have to enable the appropriate instance mode on the service contract implementation:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class MyService : IMyService {
// ...
}
There are two kinds of sessions in WCF: Secure Sessions and Reliable Sessions. The default setting for both wsHttpBinding and netTcpBinding is to use Secure Sessions.For wsHttpBinding this is accomplished with message-level security by using the client's credentials, which is the default setting for the binding.For netTcpBinding instead, the session is established at the tranport level by using the facilities of the TCP protocol.
This means that simply switching to wsHttpBinding or netTcpBinding will enable support for WCF sessions.
The alternative is to use Reliable Sessions. This has to explicitly be enabled in the binding configuration, and removes the requirement of using message security for the wsHttpBinding. So this will work:
<bindings>
<wshttpbinding>
<binding name="ReliableSessionEnabled">
<reliablesession enabled="True" ordered="False" />
<security mode="None" />
</binding>
</wshttpbinding>
</bindings>
8) False, Reliable Sessions are used independently of the security settings of the communication channel.
For a more detailed explanation, have a look at this article.

Following through on Enrico's excellent answer, these are the configs I am using:
Service:
<services>
<service name="Foo.Bar.Service">
<endpoint name="EndpointHttps"
address=""
binding="customBinding" bindingConfiguration="EndpointHttps"
contract="Foo.Bar.IService" />
</service>
</services>
<bindings>
<customBinding>
<binding name="EndpointHttps">
<reliableSession />
<mtomMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
Client:
<client>
<endpoint name="EndpointHttps"
address="https://server/FooBar/service.svc"
binding="customBinding" bindingConfiguration="EndpointHttps"
contract="Foo.Bar.IService" />
</client>
<bindings>
<customBinding>
<binding name="EndpointHttps">
<reliableSession />
<mtomMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
Note: still haven't gotten this to work with Windows authentication though.

Related

Not able to communicate with WCF service running on separate computer using net.tcp

I am not able to communicate with another computer that is in my local area network over a net.tcp connection unless I turn the security mode off. If I set the security mode to "None", communication works fine. With the service model configuration set up as below on both ends of the wire, I get the error message "The server has rejected the client credentials".
The WCF service is being hosted in a Windows service on the remote computer. From what I have seen in various documentation, my configuration is set up correctly. Any ideas on what I might be doing wrong? Wild suggestions welcomed.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ITcpService">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
<!--Communication works if I do this
<security mode="None" />
-->
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://199.198.3.5:8520/TcpService"
binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_ITcpService"
contract="TcpServiceReference.ITcpService"
name="NetTcpBinding_ITcpService">
</endpoint>
</client>
</system.serviceModel>

How to configure WCF service deployed on IIS and remote client to authenticate from remote client PC?

I'm a noob; please help me understand this authentication config / bindings stuff that confuses me so much.
I have a C# WCF service deployed on IIS 7 on Win 2008. My client is a Windows Forms C# app. My client works just fine when it's running from the same server where the WCF service is running, but when I try to run my client from a remote PC, I get the following exception...
System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service.
I've read a few posts about these issues, and know that my problem is because my service and client are configured to use Windows authentication, which I guess is the default when using Visual Studio to create the service, and to add the service reference to the client. Below is my config before I made any changes, when it was still set to Windows (with irrelevant bits removed)...
Web.Config
<system.web>
...
<authentication mode="Windows"/>
...
<system.serviceModel>
<services>
<service name="MCLaborServer.LaborService" behaviorConfiguration="MCLaborServer.LaborServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="wsHttpBinding" contract="MCLaborServer.ILaborService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MCLaborServer.LaborServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
And from the App.Config on the client...
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ILaborService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://<myDnsNameGoesHere>/MCLaborServer/LaborService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ILaborService"
contract="LaborService.ILaborService" name="WSHttpBinding_ILaborService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
So, first I changed "authentication mode="None"" in the web.config, and set "security mode="None"" in the client's app.config, and set both the clientCredentialType="None" for message and transport. I also commented out the "identity" sections in both the web.config and client's app.config. That broke it completely though and now the client running locally won't even work; it gives a "The remote server returned an unexpected response: (405) Method Not Allowed" error.
So what can I do to turn security off so that I can connect using a remote client? I do have anonymous access enabled by the way in IIS for my application.
I'd also like to ask, what's the best practice way to configure this so I can make webservice calls on a remote client over the internet in a semi-secure fashion without using SSL or doing anything that would cost money. I'm not really that concerned about security of the data because it's not really sensitive data, but still I'd like to make sure the server isn't open to attacks.
Also, I read that I can use Windows authentication, and then explicitly specify credentials in code, like below. If I do that, will it still work remotely? And if so, does that end up making my Windows credentials for the server be sent over the wire in an insecure fashion, so then I'd be open to getting my credentials hijacked?
SomeService.ServiceClient someService = new SomeService.ServiceClient();
someService.ClientCredentials.Windows.ClientCredential.UserName="windowsuseraccountname"
someService.ClientCredentials.Windows.ClientCredential.Password="windowsuseraccountpassword"
I've read through the following posts / links, but still am confused. Thanks for any help!
WCF error: The caller was not authenticated by the service
How to fix "The caller was not authenticated by the service"?
http://msdn.microsoft.com/en-us/library/aa291347(v=vs.71).aspx
http://www.devx.com/codemag/Article/33342/1763/page/2
We ran into similar issues when setting up low security WCF services that ran across domains. One of the biggest problems (if you can call it that) is that WCF is configured to be very secure by default. Because our application was entirely within a secure network, we did not want to have to bother with a lot of complicated certificates. Our workaround was to create a custom binding that allowed us to use username/password authentication for our services without any encryption. We based our implementation off of Yaron Naveh's Clear Username Binding. I would recommend that you have a look at that (and at his blog post introducing it).
Some good resources for learning about WCF Bindings and Security:
MSDN - Windows Communication Foundation Bindings Overview
MSDN - System-Provided Bindings
MSDN - Security Overview
MSDN - Programming WCF Security
MSDN - WCF Security Fundamentals
MSDN - Choosing a Transport
I fixed this by changing binding to basicHttpBinding, changing authentication to Forms and turning security off.

WCF Service ask login and password

Good day all
I have the following question: how to change web.config to ask for the credentials before user uses the service?
Thanks in advance
You have to do basic authentication for your purpose and disable all authentication from your IIS (Where your wcf will be hosted) except Basic Authentication
By default anonymous authentication is enabled that's why it will not ask when you access your service.
You need to do web.config setting also as per below
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="myHttpGetBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="yourserviceaddress"
binding="basicHttpBinding"
bindingConfiguration="myHttpGetBinding"
contract="BasicAuthTest.MyServiceContract"
name="myBasicEndpoint"/>
</client>
</system.serviceModel>
Please refer following links
http://www.codeproject.com/KB/WCF/WCFBasicHttpBinding.aspx
http://www.codeproject.com/KB/WCF/BasicAuthWCFRest.aspx
http://msdn.microsoft.com/en-us/library/ee817643.aspx
Since your service is hosted in IIS, you should check out the guidance provided in this link, specifically the section on Authentication.
I believe that unless you have Windows Authentication turned on in IIS, which will automatically prompt the user, your application will be responsible for gathering the user's credentials.

WCF - Disabling security in nettcpbinding (c#)

I'm trying to make a self hosted WCF app that uses nettcpbinding but works in an environment without a domain.
It's just two regular windows pc's, one is the server and the other one will be the client. The problem with this is that when I try to get the client to connect it's rejected because of the security settings.
Can you please point me in the right direction as to how I can get this scenario to work?
Should I (if possible) disable security?
Is there another (hopefully simple) way to accomplish this?
Regards,
Daniel
If you'd like to disable security for testing purposes, in the App.config of the WCF project, change the security element to <security mode="None" />, e.g.:
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfig" transferMode="Buffered" maxReceivedMessageSize="5242880">
<readerQuotas maxArrayLength="5242880" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
If you have a client, update the service reference to sync the security settings. Keep in mind that you should use some level of security in production environments.

Keep MEX binding insecure while securing HTTP binding w/ UsernamePasswordValidator?

We're using UsernamePasswordValidator along with a certificate to secure access to our WCF services.
However, the custom authorization policies we're using are SERVICE behaviors, not endpoint behaviors, so they apply to all endpoints, including the MEX endpoint. We'd like to be able to go and grab the service references using visual studio without having to comment out the service behaviors every time, but since both the mex and the wshttp endpoint are secured, we get an error when doing "Add Service Reference.."
Is there any way around this?
Are you using the same binding on both? If so, try 2 seperate bindings - one for the mex endpoint and one for the wshttp:
So for the service - something like:
<wsHttpBinding><binding name="wsHttpBindingMessageUname">
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="true"
establishSecurityContext="false" />
</security></binding></wsHttpBinding>
and for the mex endpoint (no security):
<customBinding><binding name="customMex">
<textMessageEncoding>
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</textMessageEncoding>
<httpTransport transferMode="Buffered"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647"/></binding></customBinding>
Service endpoints will be something like:
<endpoint address="" behaviorConfiguration="Server.Services.DefaultEndpointBehavior" binding="wsHttpBinding" bindingConfiguration="wsHttpBindingMessageUname" name="DefaultHttp" contract="Server.Services.IMyService" listenUriMode="Explicit" />
<endpoint address="mex" binding="customBinding" contract="IMetadataExchange" name="" bindingConfiguration="customMex" listenUriMode="Explicit" />
With this setup, it's not applying the security for mex so you shouldn't get that message when trying to update service reference. Either that, or create another secure binding that uses different credentials, i.e. a client certificate on your machine.
The following MSDN post has a sample of this and more info can be found on this blog regarding secure mex endpoints.
I think from the question he also noted that he was using Service Behaviours, so the binding configuration wont make a difference, since the entire service uses the UserNamePassword Validator.
Two things come to mind here.
Remove the explicit mex binding and add under service behaviors
<serviceMetadata httpsGetEnabled="true" />
Or Keep the mex binding, and enable
<serviceMetadata httpGetEnabled="true" />
CustomUserNameValidator doesnt get executed when requesting Metadata,
so if httpsgetenabled isnt on, and you have a mex binding on http, you need
httpGetenabled on at least

Categories