使用无效网络凭据的Kerberos身份验证会在第二次调用后导致无法解释的超时

时间:2014-07-23 15:15:33

标签: wcf .net-3.5 wif kerberos adfs2.0

我遇到的问题是使用KerberosWSTrustBinding两次使用相同的参数调用WSTrustChannel.Issue不会产生相同的结果。第一次调用导致异常“安全包中没有可用的凭据”,但第二次调用导致超时。看起来第一次调用没有清理一些资源并使应用程序处于一种奇怪的状态。

知道什么是错的?

以下是代码:

    using System;
    using System.IdentityModel.Tokens;
    using System.ServiceModel;
    using System.ServiceModel.Security;
    using Microsoft.IdentityModel.Protocols.WSTrust;
    using Microsoft.IdentityModel.Protocols.WSTrust.Bindings;
    using Microsoft.IdentityModel.SecurityTokenService;
    using System.Security.Principal;
    using System.Net;
    using System.ServiceModel.Channels;

    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                GetToken();
                GetToken();
            }

            private static void GetToken()
            {
                try
                {
                    var credentials = CredentialCache.DefaultNetworkCredentials;

                    var binding = new KerberosWSTrustBinding(SecurityMode.TransportWithMessageCredential);
                    binding.CloseTimeout = TimeSpan.FromSeconds(10);
                    binding.OpenTimeout = TimeSpan.FromSeconds(10);
                    binding.ReceiveTimeout = TimeSpan.FromSeconds(10);
                    binding.SendTimeout = TimeSpan.FromSeconds(10);

                    var trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress("https://www.google.com/adfs/services/trust/13/kerberosmixed")); //Changing for a valid ADFS server address does not affect the behavior
                    trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
                    trustChannelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
                    trustChannelFactory.Credentials.Windows.ClientCredential = credentials;
                    trustChannelFactory.ConfigureChannelFactory();

                    var wsTrustChannel = (WSTrustChannel)trustChannelFactory.CreateChannel();
                    var requestSecurityToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue, KeyTypes.Bearer);
                    requestSecurityToken.AppliesTo = new EndpointAddress(new Uri("https://DontCare"));

                    var requestSecurityTokenResponse = new RequestSecurityTokenResponse();
                    var token = wsTrustChannel.Issue(requestSecurityToken, out requestSecurityTokenResponse);

                    Console.WriteLine("[SUCCESS] Kerberos");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("[FAIL] Kerberos");
                    Console.WriteLine(GetExceptionMessages(ex));
                }
            }
            public static string GetExceptionMessages(Exception exception, string separator = ". ")
            {
                StringBuilder sb = new StringBuilder();

                string previousExceptionMessage = null;

                Exception currentException = exception;

                while (currentException != null)
                {
                    string currentExceptionMessage = currentException.Message;

                    if (currentExceptionMessage != previousExceptionMessage)
                    {
                        if (sb.Length > 0)
                        {
                            sb.Append(separator);
                        }

                        sb.Append(currentExceptionMessage);
                    }

                    previousExceptionMessage = currentExceptionMessage;

                    currentException = currentException.InnerException;
                }

                return sb.ToString();
            }

        }
    }

1 个答案:

答案 0 :(得分:0)

有趣的是,六年后我不记得我最初的问题时再次遇到了同样的问题...

更新:事件6年后,使用更新版本的wif未能自行解决此问题。

由于此问题仍未解决,因此知道第二个呼叫将失败,因此我将超时设置为1毫秒,并立即重新发出了呼叫(令人惊讶的是重新发出呼叫将起作用)

            binding.CloseTimeout = TimeSpan.FromMilliseconds(1);
            binding.OpenTimeout = TimeSpan.FromMilliseconds(1);
            binding.ReceiveTimeout = TimeSpan.FromMilliseconds(1);
            binding.SendTimeout = TimeSpan.FromMilliseconds(1);

然后是第三个调用(或使用默认值)

            binding.CloseTimeout = TimeSpan.FromMilliseconds(60000);
            binding.OpenTimeout = TimeSpan.FromMilliseconds(60000);
            binding.ReceiveTimeout = TimeSpan.FromMilliseconds(60000);
            binding.SendTimeout = TimeSpan.FromMilliseconds(60000);