2012-09-25 32 views
13

Tengo un servicio WCF con wsHttpBindings y SSL habilitado, pero me gustaría habilitar las sesiones de WCF.Cómo habilitar la sesión con SSL wsHttpBinding en WCF

Después de cambiar a SessionMode requerido

SessionMode:=SessionMode.Required 

estoy recibiendo el error se describe a continuación.

El contrato requiere la sesión, pero el enlace 'WSHttpBinding' no es compatible con o no está configurado correctamente para admitirlo.

Aquí está mi aplicación de muestra.

App.config

<?xml version="1.0" encoding="utf-8" ?> 
    <configuration> 

     <system.web> 
     <compilation debug="true" /> 
     </system.web> 
     <!-- When deploying the service library project, the content of the config file must be added to the host's 
     app.config file. System.Configuration does not support config files for libraries. --> 
     <system.serviceModel> 

     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> 
     <client /> 
     <bindings> 
      <wsHttpBinding> 
      <binding name="NewBinding0" useDefaultWebProxy="false" allowCookies="true"> 
       <readerQuotas maxStringContentLength="10240" /> 
       <!--reliableSession enabled="true" /--> 
       <security mode="Transport"> 
       <transport clientCredentialType="None" proxyCredentialType="None" > 
        <extendedProtectionPolicy policyEnforcement="Never" /> 
       </transport > 
       </security> 
      </binding> 
      </wsHttpBinding> 
     </bindings> 
     <services> 
      <service name="WcfServiceLib.TestService"> 
      <endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0" 
       contract="WcfServiceLib.ITestService"> 
       <identity> 
       <servicePrincipalName value="Local Network" /> 
       </identity> 
      </endpoint> 
      <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" /> 
      <host> 
       <baseAddresses> 
       <add baseAddress="https://test/TestService.svc" /> 
       </baseAddresses> 
      </host> 
      </service> 
     </services> 

     <behaviors> 
      <serviceBehaviors> 
      <behavior> 
       <!-- To avoid disclosing metadata information, 
       set the value below to false and remove the metadata endpoint above before deployment --> 
       <serviceMetadata httpsGetEnabled="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> 

    </configuration> 

ITestService.vb

<ServiceContract(SessionMode:=SessionMode.Required)> 
    Public Interface ITestService 

     <OperationContract(IsInitiating:=True, IsTerminating:=False)> _ 
     Function GetData(ByVal value As Integer) As String 

    End Interface 

TestService.vb

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession, _ 
    ReleaseServiceInstanceOnTransactionComplete:=False, _ 
    ConcurrencyMode:=ConcurrencyMode.Single)> 
     Public Class TestService 
      Implements ITestService 

      Private _user As User 

      <OperationBehavior(TransactionScopeRequired:=True)> 
      Public Function GetData(ByVal value As Integer) As String _ 
Implements ITestService.GetData 

       If _user Is Nothing Then 

        _user = New User() 
        _user.userName = "User_" & value 
        _user.userPassword = "Pass_" & value 

        Return String.Format("You've entered: {0} , Username = {1} , Password = {2} ", _ 
             value, _user.userName, _user.userPassword) 
       Else 
        Return String.Format("Username = {1} , Password = {2} ", _ 
            _user.userName, _user.userPassword) 
       End If 

      End Function 

     End Class 

Probé po soluciones posibles, pude encontrar, pero nada ayudó.

Algunos consejos para que sesiones fiables, pero no trabajar con ssl (aunque sólo sea vinculante que tiene su medida), otros consejos para utilizar http en lugar de https , pero me Me gusta habilitar Sesiones con mis configuraciones actuales, si es posible.

¿Hay algún enfoque para lograr esto?

Cualquier tipo de ayuda es muy apreciada.

+0

¿Cuál es el motivo para habilitar el estado de la sesión en el servicio wcf? Esto podría ser un cuello de botella si está buscando un alto rendimiento. Se debe evitar el servicio de wcf del estado de la sesión. –

+0

Me gustaría tener una _variable de usuario para cada sesión. Obtengo una nueva instancia de clase de servicio para cada llamada. _El valor del usuario siempre es Nada. – hgulyan

+0

¿Qué solución debo usar para mi situación si necesito almacenar datos para cada cliente? – hgulyan

Respuesta

18

Si desea "sesiones" con wsHttpBinding, debe utilizar mensajería confiable o las sesiones de seguridad. (fuente: how to enable WCF Session with wsHttpBidning with Transport only Security).

WSHttpBinding admite sesión pero solo si está habilitada la seguridad (SecureConversation) o la mensajería confiable. Si está utilizando la seguridad de transporte, entonces no está utilizando WS-SecureConversation y WS-ReliableMessaging está desactivado de manera predeterminada. Por lo tanto, los dos protocolos que utiliza WSHttpBinding para la sesión no están disponibles. O necesita usar seguridad de mensaje o activar sesión confiable. (fuente: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/57b3453e-e7e8-4875-ba23-3be4fff080ea/).

Hemos deshabilitado RM sobre Https en los enlaces estándar porque la forma de asegurar una sesión de RM es usar una sesión de seguridad y Https no proporciona sesión.

Encontré el msdn blurb al respecto aquí: http://msdn2.microsoft.com/en-us/library/ms733136.aspx El texto publicitario es "La única excepción es cuando se usa HTTPS. La sesión SSL no está ligada a la sesión confiable. Esto impone una amenaza porque las sesiones que comparten un contexto de seguridad (la sesión SSL) no están protegidas entre sí; esto puede o no ser una amenaza real según la aplicación. "

Sin embargo, puede hacerlo si determina que no hay ninguna amenaza. Hay una muestra de RM sobre HTTPS a través del enlace personalizado http://msdn2.microsoft.com/en-us/library/ms735116.aspx (fuente: http://social.msdn.microsoft.com/forums/en-US/wcf/thread/fb4e5e31-e9b0-4c24-856d-1c464bd0039c/).

para resumir su posibilidades, puede:

1 - Mantener wsHttpBinding, eliminar la seguridad del transporte y habilitar la mensajería fiable

<wsHttpBinding> 
    <binding name="bindingConfig"> 
     <reliableSession enabled="true" /> 
     <security mode="None"/> 
    </binding> 
    </wsHttpBinding> 

Pero usted suelta la capa SSL y entonces parte de su seguridad .

2 - Mantener wsHttpBinding, mantener la seguridad del transporte y añadir mensaje de autenticación

<wsHttpBinding> 
    <binding name="bindingConfig"> 
     <security mode="TransportWithMessageCredential"> 
     <message clientCredentialType="UserName"/> 
     </security> 
    </binding> 
    </wsHttpBinding> 

Tienes la oportunidad de mantener su capa de seguridad SSL, pero su cliente tendrá que proporcionar credenciales (de cualquier forma) e incluso si no los valide en el lado del servicio, los falsos aún se deben proporcionar ya que WCF rechazará cualquier mensaje que no especifique las credenciales.

3 - Use una unión con la mensajería fiable y el transporte HTTPS encargo

<customBinding> 
    <binding name="bindingConfig"> 
     <reliableSession/> 
     <httpsTransport/> 
    </binding> 
    </customBinding> 

No puedo ver ninguna desventaja de esto, excepto la amenaza se explica en MSDN, y que depende de su aplicación.

4 - Utilizar otros proveedores de sesión Si su solicitud es hotsed en IIS, puede configurar

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> 

y dependen de la

HttpContext.Current.Session 

de su estado.

O implementando sus propias cookies.

PD: Tenga en cuenta que para todas las configuraciones de WCF, solo probé la activación del servicio, no las llamadas.

EDITAR: Según la solicitud del usuario, wsHttpBinding con TransportWithMessageCredential sesiones de implementación de modo de seguridad (no estoy muy familiarizado con VB.NET por lo perdona mi sintaxis): Código

Servicio fragmento:

<ServiceContract(SessionMode:=SessionMode.Required)> 
Public Interface IService1 

    <OperationContract()> _ 
    Sub SetSessionValue(ByVal value As Integer) 

    <OperationContract()> _ 
    Function GetSessionValue() As Nullable(Of Integer) 

End Interface 

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession, 
    ConcurrencyMode:=ConcurrencyMode.Single)> 
Public Class Service1 
    Implements IService1 

    Private _sessionValue As Nullable(Of Integer) 

    Public Sub SetSessionValue(ByVal value As Integer) Implements IService1.SetSessionValue 
     _sessionValue = value 
    End Sub 

    Public Function GetSessionValue() As Nullable(Of Integer) Implements IService1.GetSessionValue 
     Return _sessionValue 
    End Function 
End Class 

Public Class MyUserNamePasswordValidator 
    Inherits System.IdentityModel.Selectors.UserNamePasswordValidator 

    Public Overrides Sub Validate(userName As String, password As String) 
     ' Credential validation logic 
     Return ' Accept anything 
    End Sub 

End Class 

servicio fragmento de configuración:

<system.serviceModel> 
    <services> 
    <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"> 
     <endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService1" bindingConfiguration="bindingConf"/> 
     <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/> 
    </service> 
    </services> 
    <bindings> 
    <wsHttpBinding> 
     <binding name="bindingConf"> 
     <security mode="TransportWithMessageCredential"> 
      <message clientCredentialType="UserName"/> 
     </security> 
     </binding> 
    </wsHttpBinding> 
    </bindings> 
    <behaviors> 
    <serviceBehaviors> 
     <behavior name="WcfService1.Service1Behavior"> 
     <serviceMetadata httpsGetEnabled="true"/> 
     <serviceDebug includeExceptionDetailInFaults="false"/> 
     <serviceCredentials> 
      <userNameAuthentication 
      userNamePasswordValidationMode="Custom" 
      customUserNamePasswordValidatorType="WcfService1.MyUserNamePasswordValidator, WcfService1"/> 
     </serviceCredentials> 
     </behavior> 
    </serviceBehaviors> 
    </behaviors> 
</system.serviceModel> 

cliente de código de prueba fragmento:

Imports System.Threading.Tasks 

Module Module1 

    Sub Main() 
     Parallel.For(0, 10, Sub(i) Test(i)) 
     Console.ReadLine() 
    End Sub 

    Sub Test(ByVal i As Integer) 
     Dim client As ServiceReference1.Service1Client 
     client = New ServiceReference1.Service1Client() 
     client.ClientCredentials.UserName.UserName = "login" 
     client.ClientCredentials.UserName.Password = "password" 
     Console.WriteLine("Session N° {0} : Value set to {0}", i) 
     client.SetSessionValue(i) 
     Dim response As Nullable(Of Integer) 
     response = client.GetSessionValue() 
     Console.WriteLine("Session N° {0} : Value returned : {0}", response) 
     client.Close() 
    End Sub 

End Module 
+0

No tengo tiempo para probar sus soluciones, la recompensa termina en 10 minutos, pero esta es la respuesta más detallada, así que la aceptaré. Es adecuado para mí usar el enlace personalizado o el modo TransportWithMessageCredential. Los probaré a los dos. Gracias. – hgulyan

+0

TransportWithMessageCredential no funcionará con wsHttpBinding. Funciona solo con NetHttpBinding. Compruebe http://msdn.microsoft.com/en-us/library/ms730879.aspx – hgulyan

+0

Significa que la única forma posible para mí es utilizar un enlace personalizado. – hgulyan

1

De forma predeterminada, WSHttpBinding solo permite sesiones de seguridad. Es un concepto de WCF y no está vinculado al Transporte. Una sesión de seguridad no es una sesión en https, sino una sesión con autenticación mutua. Esto se logra agregando seguridad de mensajes.

Sobre la base de su servicio, se debe aplicar esta configuración

<bindings> 
     <wsHttpBinding> 
     <binding name="wsHttpBindingConfig"> 
      <security mode="TransportWithMessageCredential"> 
      <!-- configure transport & message security here if needed--> 
      </security> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 

En clientside, aquí es una prueba de unidad sencilla

[TestMethod] 
    public void TestSecuritySession() 
    { 
     //remove this is certificate is valid 
     ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) => { return true; }); 

     var binding = new WSHttpBinding(); 
     binding.Security = new WSHttpSecurity() { Mode = SecurityMode.TransportWithMessageCredential}; 
     ChannelFactory<ITestService> Factory = new ChannelFactory<ITestService>(binding, new EndpointAddress("https://localhost/TestService.svc")); 

     Factory.Open(); 
     var channel = Factory.CreateChannel(); 

     //call service here 

     (channel as IClientChannel).Close(); 

     Factory.Close(); 
    } 
+0

¿Funcionará mi sesión en su caso, si realizo InstanceContextMode PerSession? – hgulyan

+0

@hgulyan Sí, por supuesto. Puede probar fácilmente este comportamiento desde su lado devolviendo datos específicos de sesión/instancia en un método de servicio. – Cybermaxs

1

wsHttpBinding requiere reliableSession para soportar sesiones de WCF, y sesiones fiables requiere personalizada vinculante para apoyar ssl. Entonces, por lo que puedo ver, preguntar por las sesiones de WCF sobre ssl y con wsHttpBinding parece fuera de lugar.

+1

Supongo que tienes razón, pero ¿qué debo hacer si necesito tanto el SSL como la sesión funcionando? – hgulyan

Cuestiones relacionadas