У меня есть служба wcf, которая защищена с помощью WIF. Я реализую кеширование токенов на клиенте (веб-сайте), как описано в блоге Трэвиса Спенсера:
http://travisspencer.com/blog/2009/03/caching-tokens-to-avoid-calls.html
Веб-сайт использует олицетворение (олицетворение меня), и конечная точка STS wcf настроена для использования проверки подлинности Windows.
При вызове службы WCF с использованием прямых вызовов (т. Е. Не асинхронных вызовов) кэширование токенов работает нормально - поведение ClientCredentials удаляется и добавляется мое пользовательское поведение CacheClientCredentials, а токен кэшируется при первом вызове и повторно используется при последующем вызов.
Однако у меня есть сценарий, в котором асинхронный метод вызывается в службе wcf с предоставлением обратного вызова. При нормальных обстоятельствах (не асинхронных) метод CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider вызывается несколько раз, и при каждом вызове идентификатора поток выполняется как правильный. Последующий вызов STS использует правильные учетные данные, пользователь проходит проверку подлинности и токен возвращается. Когда вызывается асинхронный метод, происходят множественные вызовы CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider, но только первый вызов имеет правильную идентификационную информацию. Последующие вызовы имеют «NT AUTHORITY \ NETWORK SERVICE» в качестве идентификатора. В результате вызов к STS имеет неправильные учетные данные, и аутентификация не проходит. (Журнал STS показывает сообщение, указывающее «не удалось аутентифицироваться».
Я пытался добавить явное олицетворение вокруг асинхронных методов Begin / End, но это не всегда работало. Затем я добавил следующие значения в файл web.config:
<legacyImpersonationPolicy enabled="false" />
<alwaysFlowImpersonationPolicy enabled="true" />
Это также не всегда работает (хотя иногда работает). Здесь необычно то, что бизнес-логика включает в себя 3 попытки вызвать асинхронный метод (если вызовы не удаются). Я обнаружил, что, как правило, первые 2 завершаются неудачно, а третий завершается успешно - то есть CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider обычно выполняется как неправильный идентификатор первые два раза, а правильный идентификатор - в третий раз, но это также кажется немного случайным. Когда CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider успешно выполняется с правильным идентификатором, вызов WCF завершается успешно. Однако токен не добавляется в кеш (код кеша не выполняется). Последующие вызовы не асинхронного метода затем создают новый кеш, а затем получают токен, добавляя его в кеш.
Каков правильный метод для вызова асинхронного метода WCF, который защищен с помощью WIF, чтобы обеспечить кэширование токена WIF между вызовами?
Требуется ли специальная конфигурация идентификатора, чтобы гарантировать, что один и тот же идентификатор используется во всех этих процессах? (все области используют олицетворение)
Обновление:
Я не уверен, что он добавляет много, но я обнаружил, что когда код не работает, в 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]
Когда он работает, он немного отличается (обратите внимание на дополнительные записи mscorlib и переходы в середине):
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]