2012-09-25 17 views
13

Ho un servizio WCF con wsHttpBindings e SSL abilitato, ma mi piacerebbe abilitare le sessioni WCF.Come abilitare la sessione con SSL wsHttpBinding in WCF

Dopo aver cambiato SessionMode a richiesta

SessionMode:=SessionMode.Required 

sto ottenendo l'errore descritto di seguito.

Il contratto richiede Session, ma Binding 'WSHttpBinding' non supporta o non è configurato correttamente per supportarlo.

Ecco la mia applicazione di esempio.

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 

Ho provato tutte Po soluzioni ssible, ho potuto trovare, ma nulla ha aiutato.

Alcuni consigli per consentire sessioni affidabili, ma non funziona con SSL (se solo si dispone vincolante vostra abitudine), gli altri consigli per utilizzare http invece di https, ma mi piacerebbe come abilitare Sessioni con le mie attuali configurazioni, se è possibile.

C'è qualche approccio per raggiungere questo obiettivo?

Qualsiasi tipo di aiuto è molto apprezzato.

+0

Qual è la ragione per abilitare lo stato di sessione sul servizio wcf? Questo potrebbe essere un collo di bottiglia se stai cercando prestazioni elevate. Dovrebbe essere evitato il servizio wcf di sessione. –

+0

Mi piacerebbe avere una variabile _user per ogni sessione. Ricevo una nuova istanza di classe di servizio per ogni chiamata. il valore di _user è sempre Nothing. – hgulyan

+0

Quale soluzione dovrei usare per la mia situazione, se devo memorizzare i dati per ogni cliente? – hgulyan

risposta

18

Se si desidera "sessioni" con wsHttpBinding, è necessario utilizzare una messaggistica affidabile o le sessioni di sicurezza. (fonte: how to enable WCF Session with wsHttpBidning with Transport only Security).

WSHttpBinding supporta la sessione ma solo se è abilitata la sicurezza (SecureConversation) o la messaggistica affidabile. Se si utilizza la sicurezza del trasporto, non utilizza WS-SecureConversation e WS-ReliableMessaging è disattivato per impostazione predefinita. Pertanto i due protocolli utilizzati da WSHttpBinding per la sessione non sono disponibili. È necessario utilizzare la sicurezza dei messaggi o attivare una sessione affidabile. (fonte: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/57b3453e-e7e8-4875-ba23-3be4fff080ea/).

Abbiamo disabilitato RM su Https nei binding standard perché il modo per proteggere una sessione RM consiste nell'utilizzare una sessione di sicurezza e Https non fornisce la sessione.

Ho trovato il messaggio msdn su di esso qui: http://msdn2.microsoft.com/en-us/library/ms733136.aspx Il blurb è "L'unica eccezione è quando si utilizza HTTPS. La sessione SSL non è legata alla sessione affidabile. Ciò impone una minaccia perché le sessioni che condividono un contesto di sicurezza (la sessione SSL) non sono protette l'una dall'altra; questo potrebbe o potrebbe non essere una vera minaccia a seconda dell'applicazione. "

Tuttavia è possibile farlo se si determina che non vi è alcuna minaccia. Esiste un campione RM su HTTPS tramite associazione personalizzata http://msdn2.microsoft.com/en-us/library/ms735116.aspx (fonte: http://social.msdn.microsoft.com/forums/en-US/wcf/thread/fb4e5e31-e9b0-4c24-856d-1c464bd0039c/).

Per riassumere le vostre possibilità è possibile:

1 - Tenere wsHttpBinding, rimuovere la protezione dei trasporti e consentire messaggistica affidabile

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

Ma si perde lo strato di SSL e quindi parte della vostra sicurezza .

2 - Tenere wsHttpBinding, mantenere la sicurezza dei trasporti e aggiungere l'autenticazione dei messaggi

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

Si arriva a mantenere il livello di sicurezza SSL, ma il vostro cliente dovrà fornire le credenziali (di qualsiasi forma), e anche se si non convalidarli sul lato del servizio, devono essere forniti quelli falsi in quanto WCF rifiuterà qualsiasi messaggio che non specifica le credenziali.

3 - Utilizzare una consuetudine vincolante con messaggistica affidabile e trasporto HTTPS

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

non riesco a vedere alcun aspetto negativo di questo, tranne la minaccia spiegato in MSDN, e dipende dalla vostra applicazione.

4 - Utilizza altre provider di sessione Se l'applicazione è hotsed in IIS, è possibile impostare

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> 

e dipendono dalla

HttpContext.Current.Session 

per il tuo stato.

Oppure implementare i propri cookie.

PS: Si noti che per tutte quelle configurazioni di WCF, ho solo verificato l'attivazione del servizio, non le chiamate.

MODIFICA: come da richiesta dell'utente, wsHttpBinding con sessioni di implementazione della modalità di sicurezza TransportWithMessageCredential (non ho molta familiarità con VB.NET così perdonare la mia sintassi): Codice

Servizio frammento:

<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 

servizio Configurazione frammento:

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

client codice di prova frammento:

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

Non ho tempo per testare le tue soluzioni, la taglia finisce in 10 minuti, ma questa risposta è la più dettagliata, quindi accetterò. È adatto per me utilizzare l'associazione personalizzata o la modalità TransportWithMessageCredential. Li proverò entrambi. Grazie. – hgulyan

+0

TransportWithMessageCredential non funziona con wsHttpBinding. Funziona solo con NetHttpBinding. Controllare http://msdn.microsoft.com/en-us/library/ms730879.aspx – hgulyan

+0

Significa che l'unico modo possibile per me è utilizzare un'associazione personalizzata. – hgulyan

1

Per impostazione predefinita, WSHttpBinding consente solo sessioni di sicurezza. È un concetto di WCF e non è collegato al trasporto. Una sessione di sicurezza non è una sessione su https, ma una sessione con autenticazione reciproca. Ciò si ottiene aggiungendo la sicurezza dei messaggi.

In base al vostro servizio, si dovrebbe applicare questa configurazione

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

Sul lato client, ecco un semplice test di unità

[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

La mia sessione funzionerà nel tuo caso, se creo InstanceContextMode PerSession? – hgulyan

+0

@hgulyan Sì, certo. È possibile testare facilmente questo comportamento da parte dell'utente restituendo dati specifici di sessione/istanza in un metodo di servizio. – Cybermaxs

1

wsHttpBinding richiede ReliableSession per supportare sessioni di WCF, e le sessioni affidabili richiedono personalizzato vincolante per supportare ssl. Quindi chiedere le sessioni di WCF su ssl e con wsHttpBinding sembra fuori questione per quanto posso dire.

+1

Suppongo, hai ragione, ma cosa dovrei fare, se ho bisogno sia di ssl che di sessione di lavoro? – hgulyan

Problemi correlati