HTTP请求未经授权使用客户端身份验证方案'Ntlm'从服务器收到的身份验证头是'NTLM'

时间:2010-04-09 15:55:11

标签: c# .net sharepoint authentication ntlm

我知道有很多关于SO的问题与此相似,但我找不到这个问题。

有几点,第一点:

  • 我对Sharepoint服务器无法控制。我无法调整任何IIS设置。
  • 我相信我们的IIS服务器版本是IIS 7.0。
  • 我们的Sharepoint服务器通过NTLM预测请求。
  • 我们的Sharepoint服务器与我的客户端计算机位于同一个域中。
  • 我使用的是.NET Framework 3.5,Visual Studio 2008

我正在尝试编写一个简单的控制台应用程序来使用Sharepoint Web Services操作Sharepoint数据。我添加了服务参考,以下是我的app.config:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="ListsSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
                receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
                bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://subdomain.companysite.com/subsite/_vti_bin/Lists.asmx"
            binding="basicHttpBinding" bindingConfiguration="ListsSoap"
            contract="ServiceReference1.ListsSoap" name="ListsSoap" />
    </client>
</system.serviceModel>

这是我的代码:

static void Main(string[] args)
{
    using (var client = new ListsSoapClient())
    {
        client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("username", "password", "domain");
        client.GetListCollection();
    }
}

当我调用GetListCollection()时,会抛出以下 MessageSecurityException

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

内部WebException:

"The remote server returned an error: (401) Unauthorized."

我尝试过各种绑定和各种代码调整来尝试正确验证,但无济于事。我将列出以下内容。


我尝试了以下步骤:

在创建客户端

之前使用本机Win32模拟器
using (new Impersonator.Impersonator("username", "password", "domain"))
using (var client = new ListsSoapClient())
{
    client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("dpincas", "password", "domain");
    client.GetListCollection();
}

这会产生相同的错误消息。


为我的客户端凭据设置TokenImpersonationLevel

using (var client = new ListsSoapClient())
{
    client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
    client.GetListCollection();
}

这会产生相同的错误消息。


使用安全模式= TransportCredentialOnly

<security mode="TransportCredentialOnly">
    <transport clientCredentialType="Ntlm" />
</security>

这导致了不同的错误消息:

The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via

但是,我需要使用https,因此我无法更改我的URI方案。


我已经尝试了一些我不记得的其他组合,但是当我这样做时我会发布它们。我真的很有智慧。我在Google上看到很多链接都说“切换到Kerberos”,但我的服务器似乎只接受NTLM,而不是“Negotiate”(如果它正在寻找Kerberos就会说),所以很遗憾不是一个选择

那里有任何帮助,伙计们?

10 个答案:

答案 0 :(得分:40)

Visual Studio 2005

  1. 在Visual Studio中创建一个新的控制台应用程序项目
  2. 向Lists.asmx Web服务添加“Web引用”。
    • 您的网址可能如下:http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx
    • 我将我的网址引用命名为:ListsWebService
  3. 在program.cs中编写代码(我这里有一个问题列表)
  4. 这是代码。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Xml;
    
    namespace WebServicesConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    ListsWebService.Lists listsWebSvc = new WebServicesConsoleApp.ListsWebService.Lists();
                    listsWebSvc.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                    listsWebSvc.Url = "http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx";
                    XmlNode node = listsWebSvc.GetList("Issues");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }
    }
    

    Visual Studio 2008

    1. 在Visual Studio中创建一个新的控制台应用程序项目
    2. 右键单击“引用”和“添加服务引用”
    3. 输入服务器上Lists.asmx服务的URL
      • 例如:http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx
    4. 点击开始
    5. 点击确定
    6. 进行以下代码更改:
    7. 从以下位置更改app.config文件:

      <security mode="None">
          <transport clientCredentialType="None" proxyCredentialType="None"
              realm="" />
          <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
      

      要:

      <security mode="TransportCredentialOnly">
        <transport clientCredentialType="Ntlm"/>
      </security>
      

      更改program.cs文件并将以下代码添加到Main函数中:

      ListsSoapClient client = new ListsSoapClient();
      client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
      client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
      XmlElement listCollection = client.GetListCollection();
      

      添加using语句:

      using [your app name].ServiceReference1;
      using System.Xml;
      

      参考:http://sharepointmagazine.net/technical/development/writing-caml-queries-for-retrieving-list-items-from-a-sharepoint-list

答案 1 :(得分:8)

经过大量的反复试验,在我等待与我们的服务器人员交谈的机会之后停滞了一段时间,我终于有机会与他们讨论问题并询问他们是否不介意切换我们的Sharepoint身份验证到Kerberos。

令我惊讶的是,他们说这不是问题,实际上很容易做到。 他们启用了Kerberos ,我修改了我的app.config,如下所示:

<security mode="Transport">
    <transport clientCredentialType="Windows" />
</security>

作为参考,我的app.config中的完整serviceModel条目如下所示:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="TestServerReference" closeTimeout="00:01:00" openTimeout="00:01:00"
             receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
             bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
             maxBufferSize="2000000" maxBufferPoolSize="2000000" maxReceivedMessageSize="2000000"
             messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
             useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                 maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="Windows" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://path/to/site/_vti_bin/Lists.asmx"
         binding="basicHttpBinding" bindingConfiguration="TestServerReference"
         contract="TestServerReference.ListsSoap" name="TestServerReference" />
    </client>
</system.serviceModel>

在此之后,一切都像魅力一样。我现在(最后!)可以使用Sharepoint Web Services。因此,如果其他任何人无法使其Sharepoint Web服务与NTLM一起使用,请查看您是否可以说服系统管理员切换到Kerberos。

答案 2 :(得分:5)

在许多无效的答案之后,我终于在IIS服务器上禁用匿名访问时找到了解决方案。我们的服务器使用的是Windows身份验证,而不是Kerberos。这要归功于this blog posting

未对web.config进行任何更改。

在服务器端,ISAPI文件夹中的.SVC文件使用MultipleBaseAddressBasicHttpBindingServiceHostFactory

该服务的类属性是:

[BasicHttpBindingServiceMetadataExchangeEndpointAttribute]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class InvoiceServices : IInvoiceServices
{
...
}

在客户端,使其工作的密钥是http绑定安全属性:

EndpointAddress endpoint =
  new EndpointAddress(new Uri("http://SharePointserver/_vti_bin/InvoiceServices.svc"));
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
InvoiceServicesClient myClient = new InvoiceServicesClient(httpBinding, endpoint);
myClient.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; 

(call service)

我希望这适合你!

答案 3 :(得分:3)

如果我没记错的话,将SharePoint Web服务添加为VS2K8“服务参考”存在一些问题。您需要将其添加为旧式“Web引用”才能正常工作。

答案 4 :(得分:2)

我有与你相同的设置,这对我来说很好。我想也许问题可能出在你的苔藓配置或你的网络上。

你说苔藓与你的应用程序位于同一个域中。如果您可以与您的用户访问该站点(已登录到您的计算机)...您是否尝试过:

client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;

答案 5 :(得分:2)

我上周遇到了完全相同的问题 - WCF program behaves strangely on one server - why?

对我来说,解决方案相当简单。 Sharepoint拥有自己的一组权限。我的客户端尝试以未通过Sharepoint管理面板明确授予访问Web服务权限的用户身份登录。

我将用户添加到Sharepoint的白名单并发出声响 - 它刚刚起作用。

即使不是问题,请注意

HTTP请求未经授权使用客户端身份验证方案“Ntlm”。从服务器收到的身份验证标头是“NTLM”。

意味着(英文)您根本没有权限。您的协议可能是正确的 - 您的用户只是没有权限。

答案 6 :(得分:2)

我会尝试使用此工具here连接到您的Sharepoint网站。如果可行,您可以确定问题出在您的代码/配置中。这可能不会立即解决您的问题,但它排除了服务器出现问题。假设它不起作用,我会调查以下内容:

  • 您的用户是否真的拥有该网站的足够权利?
  • 是否存在干扰的代理? (您的配置看起来有点像代理。可以绕过它吗?)

我认为使用安全模式传输没有任何问题,但我对proxyCredentialType="Ntlm"不太确定,也许这应该设置为

答案 7 :(得分:2)

我以前遇到过这个问题。

client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;

在拨打电话之前对你的wcf代理执行此操作。

答案 8 :(得分:0)

试试这个

<client>
  <endpoint>
    <identity>
      <servicePrincipalName value="" />
    </identity>
  </endpoint>
</client>

我在使用webfarm之前遇到过这个错误,并且这个问题已经解决了。

答案 9 :(得分:0)

这个问题对我们来说更加奇怪。如果您之前从浏览器访问过sharepoint站点,那么在您进行SOAP调用之前,一切都有效。但是,如果您先进行SOAP调用,我们会抛出上述错误。

我们可以通过在客户端上安装sharepoint证书并将域添加到本地Intranet站点来解决此问题。