2011-04-28 6 views
3

J'ai un service wcf sécurisé à l'aide de WIF. Je mise en œuvre de la mise en cache jeton sur le client (un site), comme décrit dans le blog de Travis Spencer ici:Service WIF sécurisé Wif, jetons de mise en cache - méthode async wcf perd son identité

http://travisspencer.com/blog/2009/03/caching-tokens-to-avoid-calls.html

Le site utilise l'usurpation d'identité (me faisant passer), et le STS WCF point final est configuré pour utiliser Authentification Windows Lorsque vous appelez le service WCF à l'aide d'appels directs (appels non asynchrones), la mise en cache des jetons fonctionne correctement: le comportement ClientCredentials est supprimé et mon comportement personnalisé CacheClientCredentials est ajouté. Le jeton est mis en cache lors du premier appel et réutilisé. appel ultérieur.

Cependant, j'ai un scénario dans lequel une méthode async est appelée sur le service wcf, avec un rappel fourni. Dans des circonstances normales (non asynchrones), la méthode CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider est appelée plusieurs fois et, à chaque appel, l'identité que le thread exécute est correcte. L'appel suivant au STS utilise les informations d'identification correctes, l'utilisateur est authentifié et le jeton renvoyé. Lorsque la méthode async est appelée, les appels multiples à CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider se produisent, mais seul le premier appel a l'identité correcte. Les appels suivants ont "NT AUTHORITY \ NETWORK SERVICE" comme identité. Par conséquent, l'appel à la STS a les informations d'identification incorrectes et l'authentification échoue. (Le journal STS affiche un message indiquant "impossible à authentifier"

J'ai essayé d'ajouter l'emprunt d'identité explicite autour des méthodes async Begin/End, mais cela n'a pas fonctionné tout le temps. à la web.config:

<legacyImpersonationPolicy enabled="false" /> 
    <alwaysFlowImpersonationPolicy enabled="true" /> 

Cela n'est pas toujours (bien que le fait parfois) la chose inhabituelle ici aussi que la logique métier implique 3 tentatives d'appeler la méthode async (si les appels échouent) I.. Je constate que généralement le premier 2 échoue, et le troisième réussit - c.-à-d. CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider fonctionne normalement comme la mauvaise identité les deux premières fois, et l'identité correcte la troisième fois - mais cela semble être un peu aléatoire aussi. Lorsque CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider réussit avec la bonne identité, l'appel WCF réussit. Cependant, le jeton n'est pas ajouté au cache (aucun code de cache de jeton n'est exécuté). Les appels suivants à une méthode non asynchrone construisent ensuite un nouveau cache, puis récupèrent le jeton en l'ajoutant au cache.

Quelle est la méthode correcte pour appeler une méthode WCF asynchrone sécurisée à l'aide de WIF, pour garantir que le jeton WIF est mis en cache à travers les appels?

Existe-t-il une configuration d'identité spéciale requise pour garantir que la même identité est utilisée dans tous ces processus?(Tous les secteurs utilisent l'usurpation d'identité)

Mise à jour:

Je ne suis pas sûr si elle ajoute beaucoup, mais j'ai trouvé que lorsque le code ne fonctionne pas, ce qui suit est le stacktrace alors que dans le CacheClientCredentialsSecurityTokenManager :

Unflagged > 5732 18 Worker Thread <No Name> CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider Normal 
         MySecurity.dll!CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider(System.IdentityModel.Selectors.SecurityTokenRequirement tokenRequirement) Line 18 
         System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.AddSupportingTokenProviders(System.ServiceModel.Security.Tokens.SupportingTokenParameters supportingTokenParameters, bool isOptional, System.Collections.Generic.IList<System.ServiceModel.Security.SupportingTokenProviderSpecification> providerSpecList) + 0xca bytes 
         System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.OnOpen(System.TimeSpan timeout) + 0xa7 bytes 
         System.ServiceModel.dll!System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(System.TimeSpan timeout) + 0x45 bytes 
         System.ServiceModel.dll!System.ServiceModel.Security.OperationWithTimeoutAsyncResult.OnScheduled(object state) + 0x82 bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2() + 0x46 bytes  
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback(object o) + 0x28 bytes 
         mscorlib.dll!System.Security.SecurityContext.Run(System.Security.SecurityContext securityContext, System.Threading.ContextCallback callback, object state) + 0x55 bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke() + 0x4d bytes  
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks() + 0x180 bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback(object state) + 0x7a bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0xf bytes  
         SMDiagnostics.dll!System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame(uint error, uint bytesRead, System.Threading.NativeOverlapped* nativeOverlapped) + 0x3d bytes  
         mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x54 bytes  
         [Appdomain Transition] 

Quand il fonctionne, il est un peu différent (notez les entrées de mscorlib supplémentaires et des transitions au milieu):

Unflagged > 5408 12 Worker Thread <No Name> CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider Normal 
         MySecurity.dll!CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider(System.IdentityModel.Selectors.SecurityTokenRequirement tokenRequirement) Line 18 
         System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.AddSupportingTokenProviders(System.ServiceModel.Security.Tokens.SupportingTokenParameters supportingTokenParameters, bool isOptional, System.Collections.Generic.IList<System.ServiceModel.Security.SupportingTokenProviderSpecification> providerSpecList) + 0xca bytes 
         System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.OnOpen(System.TimeSpan timeout) + 0xa7 bytes 
         System.ServiceModel.dll!System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(System.TimeSpan timeout) + 0x45 bytes 
         System.ServiceModel.dll!System.ServiceModel.Security.OperationWithTimeoutAsyncResult.OnScheduled(object state) + 0x82 bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2() + 0x46 bytes  
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback(object o) + 0x28 bytes 
         ***mscorlib.dll!System.Security.SecurityContext.runTryCode(object userData) + 0x6e bytes  
         [Native to Managed Transition] 
         [Managed to Native Transition] 
         ***mscorlib.dll!System.Security.SecurityContext.RunInternal(System.Security.SecurityContext securityContext, System.Threading.ContextCallback callBack, object state) + 0xc2 bytes 
         ***mscorlib.dll!System.Security.SecurityContext.Run(System.Security.SecurityContext securityContext, System.Threading.ContextCallback callback, object state) + 0xca bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke() + 0x4d bytes  
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks() + 0x180 bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback(object state) + 0x7a bytes 
         System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0xf bytes  
         SMDiagnostics.dll!System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame(uint error, uint bytesRead, System.Threading.NativeOverlapped* nativeOverlapped) + 0x3d bytes  
         mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x54 bytes  
         [Appdomain Transition] 

Répondre

3

je n'ai pas abeille n appelant explicitement .Open() sur le proxy avant d'essayer d'appeler la méthode async, et par conséquent le .Open() semble se produire en interne dans le proxy client, sur un autre thread - d'où les problèmes d'identité. Je trouve que si j'ai appelé:

If _proxy.State <> CommunicationState.Opened Then 
    _proxy.Open() 
End If 

_proxy.Begin[asyncMethod]() 

la configuration de mise en cache des informations d'identification et la vérification de cache jeton arrive de façon synchrone, et donc d'utiliser l'identité correcte, et fonctionne comme prévu.

Questions connexes