9

我关注了许多 msdn 文章和 codeplex 指南,但无法让 WCF 与 Kerberos 身份验证和委派一起使用,希望能得到一些帮助。

设置

我在远程机器上的 IIS 网站中有 WCF 服务

  • Windows 2003 R2 上的 IIS 6.0 - SP 2
  • 已添加机器的 SPN (http/myserver && http/myserver:8080)
  • 已为 IIS 应用程序池创建 AD 帐户
  • AD 帐户具有设置,允许委派(对于 Kerberos),设置为 true

我在 8080 上使用Brian Booth 的调试站点,该站点通过了 Kerberos 委派的所有要求。调试 IIS 站点关闭了匿名身份验证,并打开了集成 Windows 身份验证。

我已将这些设置镜像到托管 WCF 服务的站点。

网络服务 - 网络配置(原始)

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WsHttpBindingConfig">
                <security>
                    <message negotiateServiceCredential="true" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings> 
    <services>
        <service behaviorConfiguration="ServiceBehavior" name="Service">    
            <endpoint address="" 
                binding="wsHttpBinding" 
                bindingConfiguration="WsHttpBindingConfig" 
                contract="IService">    
                <identity>    
                    <servicePrincipalName value="http/myserver" />    
                    <dns value="" />    
                </identity>    
            </endpoint>    
            <endpoint address="mex" 
                binding="mexHttpBinding" 
                contract="IMetadataExchange" />    
        </service>    
    </services>    
    <behaviors>    
        <serviceBehaviors>    
            <behavior name="ServiceBehavior">    
                <serviceMetadata httpGetEnabled="true"/>    
                <serviceDebug includeExceptionDetailInFaults="true"/>    
                <serviceAuthorization 
                    impersonateCallerForAllOperations="true" />    
            </behavior>    
        </serviceBehaviors>    
    </behaviors>    
</system.serviceModel>

网络服务 - 网络方法

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetCurrentUserName()
{
    string name = WindowsIdentity.GetCurrent().Name;
    return name;
}

客户端应用程序 - 应用程序配置

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IService" 
                ... />
                ...
                <security mode="Message">
                    <transport clientCredentialType="Windows" 
                        proxyCredentialType="None" 
                        realm="" />
                    <message clientCredentialType="Windows" 
                        negotiateServiceCredential="true"
                        algorithmSuite="Default" 
                        establishSecurityContext="true" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://myserver/Service.svc" 
            binding="wsHttpBinding" 
            bindingConfiguration="WSHttpBinding_IService"
            contract="KerberosService.IService" 
            name="WSHttpBinding_IService">
            <identity>
                <servicePrincipalName value="http/myserver" />
            </identity>
        </endpoint>
     </client>
</system.serviceModel>

应用程序错误

当我的测试应用程序(一个 WinForms 应用程序)尝试调用 web 方法时,会出现以下错误:

“HTTP 请求未经客户端身份验证方案‘匿名’未经授权。从服务器收到的身份验证标头是‘协商,NTLM’。”

事件簿

事件日志中出现以下错误:

异常:System.ServiceModel.ServiceActivationException:由于编译期间出现异常,无法激活服务“/Service.svc”。异常消息是:此服务的安全设置需要“匿名”身份验证,但托管此服务的 IIS 应用程序未启用它。

我不明白。该服务的重点是不允许匿名身份验证,每个用户/请求都必须使用 Kerberos 票证进行身份验证,然后将它们传递给其他机器。

我应该如何为 Kerberos 身份验证和委派配置此 WCF 服务?

修订版 1

在阅读了这个 SO question之后,我删除了元数据端点。这并没有解决问题。

修订版 2

经过更多研究,我发现一些帖子建议将 wsHttpBinding 更改为 basicHttpBinding。对 web.config 的该部分的修改已包含在下面,并且服务端点已更新为引用该绑定。

Web 服务 - Web Config(修订版)

<basicHttpBinding>
    <binding name="basicBindingConfig">
        <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" 
                proxyCredentialType="Windows" 
                realm="" />
        </security>
    </binding>
</basicHttpBinding>

客户端应用程序 - 应用程序配置(修订)

<!-- ... -->
<security mode="TransportCredentialOnly">
    <transport clientCredentialType="Windows" 
        proxyCredentialType="Windows"
        realm="" />
    <message clientCredentialType="UserName" 
        algorithmSuite="Default" />
</security>
<!-- ... -->

错误(修订)

当前错误看起来像是包含 Kerberos 身份验证标头。

HTTP 请求未经客户端身份验证方案“协商”的授权。从服务器收到的身份验证标头是 'Negotiate SOMEHUGESARYKEYHERE

4

4 回答 4

7

对我来说,当前的设置确实有效:

在服务器上:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="wsHttpBindingConf" useDefaultWebProxy="true"/>
    </wsHttpBinding>
  </bindings>

  <services>
    <service behaviorConfiguration="returnFaults" name="Epze.BusinessLayer.ZeitManager">
        <endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConf" contract="Epze.Contract.IZeitManager"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
  </services>

  <behaviors>
    <serviceBehaviors>
        <behavior name="returnFaults">
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
            <serviceAuthorization impersonateCallerForAllOperations="true"/>
        </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

为 WCF 的所有方法设置以下属性:

[OperationBehavior(Impersonation = ImpersonationOption.Required)]

在客户端:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
        <binding name="WSHttpBinding_IZeitManager" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
            <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
            <security mode="Message">
                <transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
                <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"/>
            </security>
        </binding>
    </wsHttpBinding>
  </bindings>

  <behaviors>
    <endpointBehaviors>
        <behavior name="Delegation">
        <clientCredentials>
            <windows allowedImpersonationLevel="Delegation" />
        </clientCredentials>
        </behavior>
    </endpointBehaviors>
  </behaviors>        

  <client>
    <endpoint address="http://server.mydomain.net/ePZEsvc/ZeitManager.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IZeitManager" 
              contract="External.Epze.IZeitManager" name="WSHttpBinding_IZeitManager" behaviorConfiguration="Delegation">
        <identity>
            <servicePrincipalName value="HOST/localhost"/>
        </identity>                      
    </endpoint>
  </client>
</system.serviceModel>

HTH,斯文

于 2009-09-10T09:18:12.733 回答
3

我注意到的一些事情:客户端和服务器配置似乎没有就安全模式达成一致。

在原始部分中,您<security>.....在 web.config 中(省略了 mode="message")和<security mode="Message">客户端。

编辑后,客户端似乎没有变化,但服务器(web.config)现在包含<security mode="TransportCredentialOnly">.

真正的问题是:你能保证在客户端和被调用的服务器之间只有一个网络支路吗?即这是在企业防火墙后面吗?在这种情况下,我建议<security mode="Transport">在两端使用 netTcp 绑定。

如果不是这种情况,那么您可以使用 wsHttpBinding(它支持更多的安全性和可靠性功能,但速度较慢且“更重”)或 basicHttpBinding。在这种情况下,您必须<security mode="Message">在两端都使用,并使用证书对服务进行身份验证(以便服务和客户端有一个共同的“秘密”用于加密)。

我会尝试在一开始就省略模拟部分,并首先启动并运行服务和客户端之间的基本通信和相互身份验证 - 一旦到位,您就可以开始向其中添加模拟位,并且您总是可以回退到有效的已知配置。

David Sackstein 有一系列精彩的博客文章,解释了行业大师 Juval Lowy (在他的Programming WCF书籍 - WCF 圣经中)确定为最常见和最有用的五种安全场景 - 以限制可能组合的数量您可能想要调整的参数。其中之一是“Internet”场景,如果您的服务是面向外部的,则可能适用于此处。

马克

于 2009-08-18T20:49:37.950 回答
2

您需要在客户端配置中指定行为配置。SVCUtil 不会自动生成。这解决了我的问题,我现在可以成功使用 Kerberos。这是一个任务!

<client>           
    <endpoint address="..."               
    binding="customBinding" bindingConfiguration="..."               
    contract="..." name="..."  behaviorConfiguration="ImpersonationBehavior" />                 
    </client>         
    <behaviors>
         <endpointBehaviors>            
         <behavior name="ImpersonationBehavior">               
              <clientCredentials>                 
              <windows allowedImpersonationLevel="Impersonation"/>                      </clientCredentials>             
    </behavior>                       
    </endpointBehaviors>                   
    </behaviors> 
于 2011-06-14T15:34:51.930 回答
1

您应该尝试您的初始配置,并确保将 IIS 同时设置为匿名和 Windows 身份验证。原因是当您使用 wsHttpBinding 时,默认安全性是消息安全性,并且没有定义传输安全性,除非您想做 https . SO Clr 声明它需要在 IIS 上打开匿名身份验证。

于 2010-11-17T02:29:18.887 回答