该场景是一个启用了Windows身份验证的asp.net Web应用程序(因此有一个经过身份验证的WindowsIdentity).我的愿望是主动调用STS而不是启用passiveRedirect,并使用.Net 4.5身份库执行此操作.
大多数代码示例(例如Claims Helper for Windows Phone或Using an Active STS)使用username / pwd输入和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); } }
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配置.