任何人都可以指出使用 NT 凭证主动发出 RequestSecurityToken 的示例代码 Thread.CurrentPrincipal as ClaimsPrincipal
吗?
该场景是一个启用了 Windows 身份验证的 asp.net Web 应用程序(因此有一个经过身份验证的 WindowsIdentity)。我的愿望是主动调用 STS 而不是启用被动重定向,并使用 .Net 4.5 身份库来执行此操作。
大多数代码示例(例如Windows Phone 的声明帮助程序或使用活动 STS)使用用户名/密码输入和 UserNameWSTrustBinding 设置凭据。
我认为解决方案可能涉及模拟或调用channelFactory.CreateChannelWithActAsToken()
从 Windows 身份创建的令牌。
-- 以下 .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 配置。