2013-03-25 12 views
12

Ho un servizio WCF ospitato da un servizio Windows. L'app client ha esito positivo se accedo al computer client utilizzando le stesse credenziali del servizio in esecuzione, ma non riesce con un'eccezione se sono connesso con un altro account di dominio valido.WCF Net.tcp con sspi ha esito negativo a meno che client e server non utilizzino la stessa finestra Identità

Ho due account con cui sto verificando, uno è un account utente ordinario e l'altro account è un account amministratore. Ho provato tutte le quattro combinazioni di seguito elencati:

    Server account 
    CLient  RegUser AdminAcct 
    RegUser  Succeeds  Fails 
AdminAcct  Fails  Succeeds  

Come si può vedere, non può essere un problema admin come il sistema funziona quando sia client che server sono in esecuzione con l'account non-admin. In entrambi i casi in cui viene a mancare ho la stessa eccezione, sul client, senza alcuna indicazione di qualsiasi cosa accada nei log dei server: "Una chiamata a SSPI fallito vedere l'eccezione interna"

L'eccezione interna è "Il nome del principio di destinazione non è corretto."

Ho registrato i conti come SPN.

Il problema si verifica solo dall'app client, ma non quando utilizzo lo WCVFTestClient.exe fornito con Visual Studio.

L'eccezione, nel registro di traccia WCF, è

"System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089"

con un messaggio:

"autenticazione non riuscita sul lato remoto (il flusso potrebbe essere ancora disponibile per ulteriori tentativi di autenticazione). "

La traccia di stack si trova nella parte inferiore: Cosa c'è che non va?

dello stack trace


System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.OnAcceptUpgrade (Stream flusso, SecurityMessageProperty & remoteSecurity) System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorBase.AcceptUpgrade (Stream stream) System.ServiceModel.Channels.InitialServerConnectionReader.UpgradeConnection (Connessione IC IC , aggiornamento StreamUpgradeAcceptorAccetto o, IDefaultCommunicationTimeouts defaultTimeouts) System.ServiceModel.Channels.ServerSessionPreambleConnectionReader.ServerFramingDuplexSessionChannel.OnOpen (TimeSpan timeout) System.ServiceModel.Channels.CommunicationObject.Open (TimeSpan timeout) System.ServiceModel.Dispatcher.ChannelHandler.OpenAndEnsurePump() System.Runtime.ActionItem.DefaultActionItem.TraceAndInvoke() System.Runtime.ActionItem.CallbackHelper.InvokeWithoutContext (Object stato) System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback (UInt32 errorCode, UInt32 numBytes, NativeOverlapped * nativeOverlapped) System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame (UInt32 errore, UInt32 bytesRead, nativeOverlapped * nativeOverlapped) System.Threading._IOCompletionCallback.PerformIOCompletionCallback (UInt32 errorCode, UInt32 numBytes, nativeOverlapped * pOVERLAP)

risposta

12

Trovato la risposta. Il mio problema era una combinazione di due fattori.

  1. Quando si utilizza il protocollo net.tcp WCF binario, la modalità di Client Security determina se NTLM o Kerberos viene utilizzato per l'autenticazione. Se si imposta Modalità di sicurezza client su "Trasporto", l'autenticazione utilizza NTLM e solo un salto è possibile. Se si prova ad avere il server WCF in comunicazione con un terzo server, (come un database), fallirà. Utilizzando SecurityMode = "Messaggio", otoh, il server WCF utilizza Kerberos, che consente più hop ...

  2. Il secondo problema era relativo a ciò che stavo facendo sul client nel binding. Il protocollo WCF net.tcp richiede che durante l'istanziazione dell'endpoint sul client, sia necessario specificare una "identità dell'endpoint" (vedere il codice di seguito). Ingiustamente pensavo che questo fosse in qualche modo correlato all'autenticazione, ed era, quindi, l'identità dell'utente attualmente connesso (Windows Principal) sul client.

    var epId = EndpointIdentity.CreateUpnIdentity(userPrincipalName); 
        var ep = new EndpointAddress(new Uri(url), epId): 
    

    No ... L'identità, da precisare nella creazione dell'endpoint sul client deve essere l'identità del server è in esecuzione sotto. Questo è il motivo per cui il codice ha funzionato ogni volta che ho effettuato l'accesso al client con lo stesso utente in cui il servizio era in esecuzione e non è riuscito quando il client era un utente diverso.

    Non riesco ancora a capire perché questa identità utente (dell'account di servizio) debba essere specificata nell'endpoint sul client. Per quale funzione sul server sono necessari questi dati?

+0

Grazie mille per questa risposta. Dopo ore e ore di tentativi, ho provato questa soluzione e funziona come un incantesimo! Se mai ci incontreremo, ti darò una birra ;-) –

+0

Sei il benvenuto! Dove vado a prendere la mia birra?

+0

Secondo il tuo profilo, penso che non ci incontreremo nel prossimo futuro ... ma i ringraziamenti senza fine ti seguiranno ;-) –

1

Per quanto riguarda il secondo punto, il cliente non è richiesta per l'esecuzione con lo stesso account di Windows del server al fine di essere autenticato, e non è necessario specificare manualmente il nome dell'account nella richiesta. Da quello che ho capito, l'autenticazione WCF è reciproca, il che significa che il client sta verificando anche il server.

L'errore che hai ricevuto è probabilmente dovuto a un errore sul lato client. Se si configura l'endpoint del servizio del client per fornire un ServicePrincipalName, il problema potrebbe essere risolto. Ho trovato this article piuttosto utile per risolvere lo stesso problema che ho riscontrato.

Problemi correlati