【问题标题】:RequestSecurityToken using windows credentials and .net 4.5 WIFRequestSecurityToken 使用 Windows 凭据和 .net 4.5 WIF
【发布时间】:2015-04-09 06:09:43
【问题描述】:

谁能指出使用Thread.CurrentPrincipal as ClaimsPrincipal的NT凭证主动发出RequestSecurityToken的示例代码?

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

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

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

-- 以下 .Net4.5 代码在访问 /adfs/services/trust/13/windowsmixed 端点时确实会获得 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 配置。

【问题讨论】:

  • 因此,根据 minimumprivilege 的回答和进一步阅读,这种情况似乎遇到了“双跳”问题,即从客户端验证的 WindowsIdentity 无法转发到另一台服务器...

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


【解决方案1】:

嗯 - 这实际上不是微不足道的。您需要为此进行 Kerberos 模拟和委派。

首先是模仿。您需要在从 Thread.CurrentPrincipal 获得的 WindowsIdentity 上调用 Impersonate()。

您可以通过调用 WindowsIdentity.GetCurrent 来确保您正在模拟。这个身份必须指向客户端(而不是服务器身份)。

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

【讨论】:

  • (抱歉,上述编辑超时)我在上面的原始帖子中添加了带有模拟代码的试用版。模拟显示我的域身份,但对 STS 的调用导致“调用者未通过服务进行身份验证”(使用 WCF 跟踪)。但是,显然在被动情况下,我的身份由同一个 STS 进行身份验证。您能否解释一下您的建议的第二部分:为 STS 配置服务器身份的委托?
  • 没关系。我搜索了“Kerberos 代表团”,这让我对这里的障碍有了更好的了解……感谢您指出这一点……
  • 虽然事实证明 appPoolIdentity 是一个服务帐户设置,在 AD 中具有“信任此帐户以委托给任何服务”...但是服务器本身并未设置。鉴于“kernalMode”是 IIS 7.5 中的默认设置,这会是问题吗?
猜你喜欢
  • 1970-01-01
  • 2012-04-01
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-21
  • 2014-08-23
  • 1970-01-01
相关资源
最近更新 更多