如何编写调用 WCF 服务并在需要时从 Kerberos 回退到 NTLM 的代码?

发布于 2024-09-18 21:13:21 字数 1377 浏览 9 评论 0原文

我需要以编程方式调用 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 方法是从多个地方调用的。我想在配置代理的地方测试身份验证(在上面的代码片段中)。

我尝试过使用 proxy.Open() 但这似乎不会导致失败。

I need to call a WCF service programmatically. The service may be hosted with either NTLM or Kerberos authentication and needs to work under either. That is, if connecting to the service via Kerberos fails, then it should fall back to NTLM.

Here's the code I'm using for Kerberos auth (if relevant, the service is hosted in SharePoint 2010 and is being called from a web part):

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;
}

Calling a method on the proxy when run in an NTLM environment gives the error:

The HTTP request is unauthorized with
client authentication scheme
'Negotiate'. The authentication header
received from the server was 'NTLM'.

Note: The URL may be in another web application on another server. I can't check what authentication the web part's web app runs under and assume it is the same as where the WCF service is hosted.

How can I (automatically or manually) ensure authentication falls back from Kerberos back to NTLM on failure?

Update:

As mentioned, the authentication error occurs when a web method is called. However I don't want to wait that long as there are several web methods in the service called from several places. I'd like to test the authentication at the point where the proxy is configured (in the code snippet above).

I've tried using proxy.Open() but that doesn't seem to cause the failure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

却一份温柔 2024-09-25 21:13:21

这有点偏离曲线球,但为什么它又回到了 NTLM。我在 Active Directory 和 WCF 中的安全性方面遇到了很大的困难,所有这些都与服务主体名称 (SPN) 相关。

如果您将该服务作为网络服务以外的其他服务运行,Kerberos 将失败,除非您在域中为您的服务声明了 SPN。要设置 SPN,您需要 Windows 服务器管理工​​具包,其中包含命令 setspn。

setspn -A HTTP\machinename domain\service_account

然后,这将允许 Kerberos 与域内的服务共享客户端凭据。

请阅读一些内容,因为根据您的设置,您可能会破坏同一机器上运行的任何其他服务的 kerberos。

This is a bit off a curveball, but why is it falling back to NTLM. I've had significant difficulty with security in active directory and WCF all related to service principal names (SPNs).

Kerberos will fail if you are running the service as something other than Network Service unless you have an SPN declared in the domain for your service. To set the SPN you need the windows server administrative kit, which has the command setspn.

setspn -A HTTP\machinename domain\service_account

This will then allow Kerberos to share client credentials to your service within the domain.

Please do some reading, as you could break kerberos for any other services running on the same box depending on your setup.

暮倦 2024-09-25 21:13:21

(我知道原来的帖子很旧了。)

您可以使用 BasicHttpBinding 以外的其他东西(例如 WsHttpBinding)吗?根据 这篇 文章,BasicHttpBinding 是绑定对象的一个​​例外是它不会自动协商。这就是为什么allowNTLM没有效果。

(I recognize the original post is very old.)

Can you use something other than BasicHttpBinding (like WsHttpBinding)? According to this article, BasicHttpBinding is the one exception to the binding objects, in that it does not automatically negotiate. This is why allowNTLM has no effect.

美人迟暮 2024-09-25 21:13:21

我有同样的错误消息,我发布了关于 此处 并通过创建动态端点解决了这个问题,如下所示:

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 服务。

I had the same error msg which I posted about here and solved it by creating a dynamic endpoint like so:

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;
}

I was running the WCF service as a specific Active Directory user rather than the default NETWORK_SERVICE.

十年九夏 2024-09-25 21:13:21

尝试设置:

proxy.ClientCredentials.Windows.AllowNTLM = true;

根据 这个,AllowNTLM 现在已过时 - 我不确定正确的替代方案是什么。

Try setting:

proxy.ClientCredentials.Windows.AllowNTLM = true;

According to this, AllowNTLM is now obsolete - i'm not sure what the correct alternative is.

咿呀咿呀哟 2024-09-25 21:13:21

我猜你正在使用服务器的完整 dns 名称作为服务的地址。尝试使用 NETBIOS 名称或 IP 地址。这应该会强制它使用 NTLM。

如果您知道服务器使用的协议,您可以将应用程序配置为使用全名或 IP。

希望这对你有用。

I guess you are using the full dns name of the server as the address of the service. Try using the NETBIOS name or the IP address. That should force it to use NTLM.

If you know what protocol the server is using you can configure your app to use either the full name or the ip.

Hope that works for you.

朕就是辣么酷 2024-09-25 21:13:21

我一直无法找到自动执行此操作的方法。相反,我已将 UI 添加到必须选择身份验证类型的应用程序中。

I haven't been able to find a way to do this automatically. Instead I've added UI to the application where the type of authentication must be chosen.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文