RequestSecurityToken使用Windows凭据和.ne​​t 4.5 WIF

时间:2013-01-09 23:01:11

标签: asp.net security .net-4.5 wif

任何人都可以指向使用Thread.CurrentPrincipal as ClaimsPrincipal的NT凭据主动发布RequestSecurityToken的示例代码吗?

该场景是一个启用了Windows身份验证的asp.net Web应用程序(因此有一个经过身份验证的WindowsIdentity)。我的愿望是主动调用STS而不是启用passiveRedirect,并使用.Net 4.5身份库执行此操作。

大多数代码示例(例如Claims Helper for Windows PhoneUsing an Active STS都使用用户名/密码输入和UserNameWSTrustBinding设置凭据。

我认为该解决方案可能涉及模拟或使用从Windows标识创建的令牌调用channelFactory.CreateChannelWithActAsToken()

- 当访问/ adfs / services / trust / 13 / windowsmixed端点时,以下.Net4.5代码确实获得了GenericXmlSecurityToken。 但是,声明适用于运行站点的域帐户,而不是经过身份验证的用户的域帐户。当我将端点切换到/ adfs / services / trust / 13 / kerberossmixed时,我得到了“无法协商”的错误,如几个问题和论坛中所述,但我不能在.Net 4.5中应用任何提供的解决方案。其中一个未从Microsoft.IdentityModel移植过的类是KerberosWSTrustBinding ......

public static void CallSts()
{
    try
    {
        var wsMod = FederatedAuthentication.WSFederationAuthenticationModule;
        var appliesToEp = new EndpointReference(wsMod.Realm);
        var stsEp = new EndpointAddress(new Uri(wsMod.Issuer), EndpointIdentity.CreateSpnIdentity("stsSpn"));

        var msgBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
        msgBinding.Security.Message.EstablishSecurityContext = false;
        msgBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

        using(var factory = new WSTrustChannelFactory(msgBinding, stsEp))
        {
            factory.Credentials.SupportInteractive = false;
            factory.TrustVersion = TrustVersion.WSTrust13;

            var myRst = new RequestSecurityToken
            {
                RequestType = RequestTypes.Issue,
                AppliesTo = appliesToEp,
                KeyType = KeyTypes.Bearer,
            };
                var channel = factory.CreateChannel();
                var stsToken = channel.Issue(myRst) as GenericXmlSecurityToken;

                if(stsToken != null)
                {
                    Log.DebugFormat("Reply Token is {0}", stsToken.GetType().Name);

                    var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
                    var token = handlers.ReadToken(new XmlTextReader(new StringReader(stsToken.TokenXml.OuterXml)));
                    var identity = handlers.ValidateToken(token).First();
                    //TODO write to session
                }
                else
                {
                    Log.Debug("Reply Token is null.");
                }
        }
    }
    catch(Exception ex)
    {
        Log.Error("Rst.Call has failed", ex);
    }
}

对于@leastprivilege建议,我添加以下代码:

    var user = Thread.CurrentPrincipal as ClaimsPrincipal;
var winId = user.Identity as WindowsIdentity;
if(winId != null)
{
    // shows my domain account after I was prompted for credentials;
    // my domain account does not exist on the client machine, so it is a true domain credential
    Log.DebugFormat("WindowsIdentity Name is {0}", winId.Name);
}
using(winId.Impersonate())
{
    // again, shows my domain account
    Log.DebugFormat("Impersonation Context {0}", WindowsIdentity.GetCurrent(true).Name);
    var channel = factory.CreateChannel();
    var stsToken = channel.Issue(myRst) as GenericXmlSecurityToken;
    // request is issued, but results in SecurityNegotiationException: The caller was not authenticated by the service.
}

失败的“调用者未通过服务进行身份验证”。相同的STS将在被动重定向方案中对我的域帐户进行身份验证...所以虽然我知道我做错了,但帐户本身应该被识别。


更新

我收到通知,此问题收到了大量意见,因此我将提供以下一个解决方法: 虽然我们将服务器配置为委托(如下面Dominick所建议的那样),但我们仍然没有超越双跳问题。如果我记得的话,我们在本地IT之上的简单网络管理政策遇到了障碍,任何企业都可能会遇到这种情况。 因此,虽然不允许使用Windows身份验证对服务器进行双跳模拟,但可以使用基本身份验证通过双跃点模拟凭据。这可能是也可能不是可接受的情况(我们案例的内联网)。如果你这样做,你会添加

msgBinding.Security.Message.NegotiateServiceCredential = true;

到上面的ChannelBinding配置。

1 个答案:

答案 0 :(得分:2)

嗯 - 这实际上并非无足轻重。您需要为此进行Kerberos模拟和委派。

首先假扮。你需要在从Thread.CurrentPrincipal获得的WindowsIdentity上调用Impersonate()。

您可以通过调用WindowsIdentity.GetCurrent来确保您正在冒充。此标识必须指向客户端(而不是服务器标识)。

然后在冒充时你需要发出WS-Trust请求。默认情况下,这很可能是不允许的。因此,网络管理员需要为STS配置服务器标识的委派。