WCF和Kerberos身份验证

时间:2009-08-18 18:01:13

标签: wcf wcf-security kerberos

我已经关注了许多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's debug site,该网站传递了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

阅读this SO question后,我删除了元数据端点。这还没有解决问题。

修订版2

经过更多的研究,我发现了一些建议将wsHttpBinding更改为basicHttpBinding的帖子。下面包含了对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请求未经授权   客户认证方案   '谈判'。身份验证标头   从服务器收到了   '谈判SOMEHUGESCARYKEYHERE

4 个答案:

答案 0 :(得分: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,Sven

答案 1 :(得分:3)

我注意到的一点:客户端和服务器配置似乎不同意安全模式。

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

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

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

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

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

大卫·萨克斯坦(David Sackstein)有一个great series of blog posts解释了行业大师Juval Lowy已经确定的五种安全方案(在他的Programming WCF书中 - WCF圣经)是最常见和最有用的 - 以限制您可能想要调整的参数组合的数量。其中一个是“互联网”场景,如果您的服务面向外,这可能适用于此。

马克

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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