代码之家  ›  专栏  ›  技术社区  ›  Kevin Anderson

具有外部信任的WCF SSPI失败-选择性与全域性

  •  2
  • Kevin Anderson  · 技术社区  · 15 年前

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

    基本上,我们有两个域,分别称为A和B。当我们在域之间进行完全的双向外部(而不是林)信任时,应用程序工作正常(当然,在将用户放入另一个域的适当组之后)。然后,我们将“全域”认证的关系转换为“选择性认证”,根据我们读到的一些文档,我们需要将用户直接添加到每台计算机在广告中的条目中,并授予他们“允许认证”的权限。

    它不起作用。

    此外,我们还看到了其他地方,这意味着我们还必须给他们在分布式控制系统上的相同权限。这样就完成了。再次,失败。

    应用程序引发的异常如下(我将其转储到一个文件中)

    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) 
    

    基本上就是这样。正在发生某种类型的“授权异常”。正如我所说,当它是一个全域双向信任时,就不会发生这种情况,所以我们认为我们缺少一些设置来“重新启用”以使其工作。是否有人非常了解信任,能够为我们指明正确的方向,以实现选择性身份验证,并使SSO/SSPI为此发挥作用?它已经在整个领域中起作用了,但是我们必须打开什么才能使它有选择性地工作(而且最好只对我们希望它为之工作的用户开放)?

    谢谢。

    1 回复  |  直到 12 年前
        1
  •  10
  •   Kevin Anderson    15 年前

    在调用Microsoft之后,解决了这个问题:我们没有在主机上运行服务的许多用户上放置“允许验证”权限。所有的文件都提到了必须给你的客户在 机器 您正在访问(在某些情况下包括DC),但没有提到还必须将远程客户机添加到运行服务的主机用户的“安全”选项卡中。

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

    “A”域:客户端尝试连接的域 “B”域:这是主机所在的域,服务由域A中的用户连接。 client@a:a域中的用户,连接到b域中的服务。 serviceaccount@b:来自b域的用户,该域承载客户@a正在连接的WCF服务。 krbtgt@b:这是一个内置的用户,其描述是“密钥分发中心服务帐户”。只要在“查看”菜单下启用了“高级功能”,它就位于“用户”下的Active Directory用户和计算机下。如果你不这样做,它就不会出现。 B-DC:B域的域控制器 B-host:我们正在连接的WCF服务的主机。

    因此,要让客户机@a通过使用sspi/windows身份验证连接到由用户serviceaccount@b在b-host上运行的wcf服务,在具有选择性身份验证的外部信任上,需要执行以下操作:

    1. 打开广告用户和计算机,并在“查看”菜单下启用“高级功能”
    2. 找到b-dc对象(默认情况下在域控制器下,但如果移动了它,可能会在其他地方)并打开“安全”选项卡。除非在步骤1中启用了高级功能,否则该选项卡将不存在。将客户机@a user添加到组或用户名中,并确保选中该用户的“read”和“allowed to authenticate”。
    3. 找到b-host对象(默认情况下在“计算机”下,但如果移动了它,可能会在其他地方),然后打开“安全”选项卡。除非在步骤1中启用了高级功能,否则该选项卡将不存在。将客户机@a user添加到组或用户名中,并确保选中该用户的“read”和“allowed to authenticate”。
    4. 在“用户”下找到krbtgt@b用户。如果不启用“高级功能”,帐户本身将不可见。转到“安全”选项卡,添加客户端@a用户,并选中“允许验证”和“读取”权限。
    5. 找到serviceaccount@b用户,并执行与krbtgt相同的操作。

    现在应该可以了。奇怪的是,你只需要运行一个经过Windows身份验证(而不是证书)的WCF连接就可以了,但现在你可以了。您需要将远程用户添加到AD中的四个不同对象中,才能使其正常工作。假设将远程用户添加到域B中具有正确权限的某些域本地组也可以工作,但还没有测试。

    编辑:然后让PDC仿真器覆盖krbtgt,在不到一小时的时间内拥有管理员的权限。每小时。

    基本上,krbtgt是超级保护的。你必须改变管理员的身份,这会增加很多麻烦。添加“允许验证”的命令是:

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

    如果您想了解“dsacls”工具的功能,请查看它。它对于修改访问控制列表和打印它们都非常方便。实际上比图形用户界面要好。

    不管怎样,这实际上是可行的。有完整的答案。

    推荐文章