tags:

views:

3168

answers:

4

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?

+8  A: 

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.

Enrico Campidoglio
Thanks for detailed answer. One question: under (7) you say sessions are enabled by setting the SessionMode property. I didn't find this to be true: without also enabling reliable sessions I got "binding not configured to support sessions" or something like that. Perhaps it will be different now.
Ian Horwill
I updated the post with some more information about WCF Sessions. Were you perhaps using another binding, or maybe you explicitly disabled security?
Enrico Campidoglio
Here is a useful article: http://www.lybecker.com/blog/2007/04/30/wcf-sessions-and-reliable-messaging/
Enrico Campidoglio
A: 

Can anybody please put some code base as an example?

+1  A: 

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.

Ian Horwill
What's the problem?
Enrico Campidoglio
A: 

The answers are very informative. I am trying to implement Transport Security with Windows as clientCredentialtype (answer 5 a) and facing some issues.








If I change the clientCredentialType to None, everything works fine. But when clientCredentialtype is "Windows" then I get communication error. The error message seems to be like opening up a login.aspx for UserId and Password. How are these Windows credentials passed. Any help is highly appreciated.

Are you trying to access your service from a web browser and which one? BTW, could you please post this as a new question?
Enrico Campidoglio