如果需要,如何编写调用 WCF 服务并从 Kerberos 回退到 NTLM 的代码?
Posted
技术标签:
【中文标题】如果需要,如何编写调用 WCF 服务并从 Kerberos 回退到 NTLM 的代码?【英文标题】:How to write code that calls a WCF service and falls back from Kerberos to NTLM if needed? 【发布时间】:2011-04-10 00:38:32 【问题描述】:我需要以编程方式调用 WCF 服务。该服务可能使用 NTLM 或 Kerberos 身份验证托管,并且需要在其中任何一个下工作。也就是说,如果通过 Kerberos 连接到服务失败,那么它应该回退到 NTLM。
这是我用于 Kerberos 身份验证的代码(如果相关,该服务托管在 SharePoint 2010 中并从 Web 部件调用):
public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
url = url.EndsWith("/") ? url + SiteMembershipAddress : url + "/" + SiteMembershipAddress;
var endpoint = new EndpointAddress(url);
var proxy = new SiteMembershipSvc.SiteMembershipServiceClient(binding, endpoint);
proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
return proxy;
在 NTLM 环境中运行时调用代理上的方法会报错:
HTTP 请求未经授权 客户端认证方案 '谈判'。身份验证标头 从服务器收到的是“NTLM”。
注意:该 URL 可能位于另一个服务器上的另一个 Web 应用程序中。我无法检查 Web 部件的 Web 应用程序在何种身份验证下运行,并假设它与 WCF 服务的托管位置相同。
我如何(自动或手动)确保身份验证在失败时从 Kerberos 回退到 NTLM?
更新:
如前所述,当调用 Web 方法时会发生身份验证错误。但是,我不想等那么久,因为服务中有几个 Web 方法是从多个地方调用的。我想在配置代理的地方测试身份验证(在上面的代码 sn-p 中)。
我尝试过使用proxy.Open()
,但这似乎不会导致失败。
【问题讨论】:
【参考方案1】:这有点离题了,但为什么要退回到 NTLM。我在活动目录和 WCF 的安全性方面都遇到了很大的困难,这些都与服务主体名称 (SPN) 相关。
如果您将服务作为网络服务以外的方式运行,Kerberos 将失败,除非您在域中为您的服务声明了 SPN。要设置 SPN,您需要 windows 服务器管理工具包,其中包含命令 setspn。
setspn -A HTTP\machinename domain\service_account
这将允许 Kerberos 在域内将客户端凭据共享给您的服务。
请做一些阅读,因为根据您的设置,您可能会破坏在同一机器上运行的任何其他服务的 kerberos。
【讨论】:
嗯,我希望它首先尝试 Kerberos,如果失败,然后使用 NTLM。我希望使用 Kerberos 身份验证会自动执行此操作,但似乎没有。 我的第一个假设也是如此。思考的方式是,如果企业中的任何服务是受信任的,那么您可能有一个流氓服务窃取凭据,冒充并做一些淘气的事情。 SPN 强制企业管理员说该服务是可信的,拥有您的 kerberos 凭证,否则不要要求它。 很高兴知道这一点。我已经重新构建了这个问题,因为我认为它不是很清楚。我需要 Web 部件“自动选择”正确的身份验证,具体取决于服务是托管在 Kerberos 还是 Windows 身份验证中。【参考方案2】:(我知道原来的帖子很老了。)
你可以使用 BasicHttpBinding 以外的东西(比如 WsHttpBinding)吗?根据this 文章,BasicHttpBinding 是绑定对象的一个例外,因为它不会自动协商。这就是 allowNTLM 无效的原因。
【讨论】:
不知道,看起来 WsHttpBinding 可以在 SharePoint 中使用。感谢您的提示!【参考方案3】:我有同样的错误消息,我发布了关于 here 并通过创建一个动态端点来解决它,如下所示:
public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
//create endpoint
EndpointAddress ep = new EndpointAddress(new Uri(string), EndpointIdentity.CreateUpnIdentity("MyDomain\WCFRunAsUser"));
//create proxy with new endpoint
SiteMembershipSvc.SiteMembershipServiceClient service = new SiteMembershipSvc.SiteMembershipServiceClient("wsHttp", ep);
//allow client to impersonate user
service.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
//return our shiny new service
return service;
我以特定 Active Directory 用户而不是默认的 NETWORK_SERVICE 用户身份运行 WCF 服务。
【讨论】:
这很酷,但我需要将当前用户的凭据传递给 Web 服务。【参考方案4】:尝试设置:
proxy.ClientCredentials.Windows.AllowNTLM = true;
根据this,AllowNTLM 现已过时 - 我不确定正确的替代方案是什么。
【讨论】:
幸运的是,我使用的是 .NET 3.5,它没有被标记为过时。我会试一试 - 谢谢! 我检查了这一点,发现 AllowNTLM 默认为 true,所以很遗憾这不起作用。我已经更新了问题。【参考方案5】:我猜你正在使用服务器的完整 dns 名称作为服务的地址。尝试使用 NETBios 名称或 IP 地址。这应该会强制它使用 NTLM。
如果您知道服务器使用的协议,您可以将您的应用配置为使用全名或 ip。
希望对你有用。
【讨论】:
你说得对,我使用的是 DNS 名称。这是我唯一的选择,因为系统是负载平衡的,我忘了提到 WCF 服务托管在 SharePoint 中 - 它只会响应该 DNS 名称上的请求。【参考方案6】:如果您的 Kerberos 失败,它将自动默认为 NTLM,您无需执行任何特殊操作。
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part1.html
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part2.html
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part3.html
【讨论】:
事实并非如此。如果我指定HttpClientCredentialType.Windows
,我会收到问题中写的错误。【参考方案7】:
我无法找到自动执行此操作的方法。相反,我已将 UI 添加到必须选择身份验证类型的应用程序中。
【讨论】:
以上是关于如果需要,如何编写调用 WCF 服务并从 Kerberos 回退到 NTLM 的代码?的主要内容,如果未能解决你的问题,请参考以下文章