WCF和Kerberos身份验证

问题描述:

我遵循了许多msdn文章和codeplex指导,但无法让WCF与Kerberos身份验证和委派一起工作,并希望得到一些帮助。WCF和Kerberos身份验证

设置

我有一个IIS网站的WCF服务的远程机

  • 在IIS 6.0在Windows 2003 R2 - SP 2
  • 的SPN机已添加(http/myserver & & http/myserver:8080)
  • 为IIS应用程序池创建了一个AD帐户
  • 广告帐户的设置,允许委派(使用Kerberos),设置为true

我使用8080 Brian Booth's debug site和站点通行证Kerberos委派的所有要求。调试IIS站点关闭了匿名身份验证,并启用了集成Windows身份验证。

我已将这些设置镜像到承载WCF服务的网站。

Web服务 - Web配置(原件)

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

Web服务 - Web方法

[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'“

事件日志

下面的错误是在事件日志中:

例外: 系统.ServiceModel.ServiceActivationException: 由于 compila中的异常,服务“/Service.svc”不能为 激活灰。 的例外消息是:此服务的安全设置 需要“匿名”身份验证,但 未启用托管此服务的IIS 应用程序。

我不明白。此服务的重点是不允许匿名身份验证,每个用户/请求必须使用Kerberos票据进行身份验证,然后将其传递到其他计算机。

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

修订1

读取this SO question后我删除元数据端点。这并没有解决这个问题。

修订2

更多研发后,我发现了几个帖子建议改变的wsHttpBinding到basicHttpBinding的。对web.config的那部分的修改已经包含在下面,并且服务端点已经被更新以引用该绑定。

Web服务 - Web配置(修订)

<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请求是未经授权的客户端 认证方案 '协商'。从服务器接收认证头 是 “协商SOMEHUGESCARYKEYHERE

+1

请注意,我发布和删除了类似的东西昨天,这篇文章包括基于更多的研究修订,应该更清晰的阅读。 – blu 2009-08-18 18:02:22

+1

我根据marc_s的反馈添加了修改后的应用配置。 – blu 2009-08-18 21:06:44

东西我注意到:在客户端和服务器的配置似乎并没有在安全模式达成一致。

在原始部分中,您在web.config中有<security>.....(省略了mode =“message”),并且在客户端有<security mode="Message">

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

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

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

我会尝试在开始时忽略模拟部分,并首先获取服务和客户端之间的基本通信和相互身份验证,并首先运行 - 一旦到位,您可以开始向其添加模拟位,并且您可以始终使用已知的配置工作。

David Sackstein有一个great series of blog posts解释行业大师Juval Lowy已经确定的五个安全情景(在他的Programming WCF书--WCF圣经中)是最常见也是最有用的 - 为了限制可能的参数组合数量你可能想调整。其中之一是一个“互联网”的情况,如果你的服务是面向外部的话,这种情况可能适用于此。

马克

+1

感谢您的回复。我没有包含更新的客户端代码,我认为这个问题已经足够混乱了。我会翻阅你提供的信息,谢谢。 – blu 2009-08-18 21:02:53

+1

“用证书验证服务”,这是某人在尝试避免的情况。我们希望使用直接的Kerberos票证对用户进行身份验证,并一直到SP和SQL等后端机器进行委派。 – blu 2009-08-18 21:08:27

对我来说,当前的设置没有问题:

在服务器上:

<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,斯文

+1

身份验证方法的IIS设置如何?匿名访问是否关闭? – Jonathan 2011-06-10 09:38:08

+1

我启用了Windows身份验证和匿名访问。但是,在为您的服务添加mex(IMetadataExchange)端点时,您只需要匿名。 – 2011-06-14 14:11:03

你应该试试你的初始配置,并确保设置IIS是在同一time.The原因匿名和Windows身份验证时,您正在使用的wsHttpBinding默认的安全是信息安全除非您想要执行https,否则没有定义传输安全性。 SO Clr声明它需要在IIS上启用匿名身份验证。

您需要在客户端配置中指定一个behaviorConfiguration。 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>