外部信任的WCF SSPI失败 - 选择性与域宽

时间:2010-02-23 18:55:59

标签: wcf active-directory cross-domain

我在工作中遇到问题,因为在与其他域通信时对域信任使用选择性身份验证时,使用WCF进行SSO的应用程序失败。这是在Server 2k8R2机器上,两个域的完整2k8R2功能级别(这是一个测试系统,因为我们有一个客户想要部署这类东西)。

基本上,我们有两个域,称为A和B.当我们在域之间执行完全双向EXTERNAL(非林)信任时,应用程序正常工作(将用户放在另一个域的适当组中之后)当然)。然后我们将关系从“域范围”身份验证转换为“选择性身份验证”。根据我们读过的一些文档,我们需要直接将用户添加到AD中每台计算机的条目中,并为其授予“允许进行身份验证”权限。

它不起作用。

此外,我们在某个地方看到ELSE暗示我们必须在DC上给予他们相同的权限。这样就完成了。再次,失败。

应用程序抛出的异常如下(我将其转储到文件中)

A call to SSPI failed, see inner exception. Stacktrace: 
Server stack trace: 
   at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)
   at System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorBase.InitiateUpgrade(Stream stream)
   at System.ServiceModel.Channels.ConnectionUpgradeHelper.InitiateUpgrade(StreamUpgradeInitiator upgradeInitiator, IConnection& connection, ClientFramingDecoder decoder, IDefaultCommunicationTimeouts defaultTimeouts, TimeoutHelper& timeoutHelper)
   at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
   at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper)
   at System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout)
   at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
   at System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
(A couple of calls in our own code below here)
InnerException: System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: Unknown error (0xc0000413)
   --- End of inner exception stack trace ---
   at System.Net.Security.NegoState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.NegotiateStream.AuthenticateAsClient(NetworkCredential credential, String targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel)
   at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity) 

所以,基本就是这样。某种类型的“AuthorizationException”正在发生。正如我所说,当它是一个域范围的双向信任时,它不会发生,因此我们认为我们缺少一些设置来“重新启用”以使其工作。是否有人充分了解信任,以便为正确的方向指出我们选择性身份验证的启用方式并使SSO / SSPI为此工作?它已经在整个域范围内工作了,但是我们需要打开什么才能使它适用于选择性的(并且最好只用于我们希望它工作的用户)?

感谢。

1 个答案:

答案 0 :(得分:10)

在致电Microsoft之后,解决了这个问题:我们没有对主机上运行服务的许多用户进行“允许验证”权限。文档都提到必须为您的客户提供您正在访问的计算机的权限(在某些情况下包括DC),但没有说明还必须将您的远程客户端添加到“安全性”运行服务的主机用户的选项卡。

因此,我将总结一些人为的用户,域名和机器名称,以及默认存在的一个实际服务帐户。

“A”域:客户端尝试连接的域 “B”域:这是一台机器托管由域A中的用户连接的服务的域。 Client @ A:来自A域的用户连接到B域中的服务。 ServiceAccount @ B:来自承载Client @ A所连接的WCF服务的B域的用户。 krbtgt @ B:这是一个内置用户,其描述是“密钥分发中心服务帐户”。只要您在“视图”菜单下启用了“高级功能”,它就会位于“用户”下的“Active Directory用户和计算机”下。除非你这样做,否则它根本不会显示出来。 B-DC:域B的域控制器 B-host:我们要连接的WCF服务的主机。

因此,要让Client @ A通过使用SSPI / Windows身份验证连接到用户ServiceAccount @ B在B主机上运行的WCF服务,在具有选择性身份验证的外部信任上,您需要执行以下操作: p>

  1. 打开AD用户&计算机和“视图”菜单下启用“高级功能”
  2. 找到B-DC对象(默认情况下在域控制器下,但如果您移动它可能在其他位置)并打开“安全”选项卡。除非您在步骤1中启用了高级功能,否则该选项卡将不存在。将Client @ A用户添加到组或用户名,并确保为该用户选中“读取”和“允许进行身份验证”。 / LI>
  3. 找到B-host对象(默认情况下位于“计算机”下,但如果您已将其移动,则可能位于其他位置)并打开“安全”选项卡。除非您在步骤1中启用了高级功能,否则该选项卡将不存在。将Client @ A用户添加到组或用户名,并确保为该用户选中“读取”和“允许进行身份验证”。 / LI>
  4. 在“用户”下找到krbtgt @ B用户。如果未启用“高级功能”,则帐户本身将不可见。转到安全选项卡,添加Client @ A用户,并选中“允许身份验证”和“读取”权限。
  5. 找到serviceaccount @ B用户并执行与krbtgt相同的操作。
  6. 现在它应该工作。奇怪的是,你需要所有这些只是为了跨越边界运行经过Windows认证(因此不是证书)的WCF连接,但是你去了。您需要将远程用户添加到AD中的四个不同对象才能使其正常工作。据推测,将远程用户添加到域B中具有正确权限的某些域本地组也可以正常工作,但尚未测试。

    编辑:然后在一小时内获得具有AdminSDHolder权限的PDC模拟器覆盖的krbtgt。每小时一次。

    基本上,krbtgt是超级保护的。你必须改变AdminSDHolder,它会传播很多东西。添加JUST“允许进行身份验证”的命令是:

    dsacls "[DN of object]" /g "[groupname]:ca;allowed to authenticate"
    

    如果您想了解更多有关它的信息,请查看“dsacls”工具。这对于更改访问控制列表和打印出来都非常方便。事实上比GUI更好。

    无论如何,这实际上现在有效。有完整的答案。