WCF和Kerberos身份验证

blu*_*blu 9 wcf kerberos wcf-security

我已经关注了许多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服务的站点.

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>
Run Code Online (Sandbox Code Playgroud)

Web服务 - Web方法

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

客户端应用程序 - App配置

<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>
Run Code Online (Sandbox Code Playgroud)

应用程序错误

当我的测试应用程序(WinForms应用程序)尝试调用Web方法时,会发生以下错误:

"HTTP请求未经授权使用客户端身份验证方案'匿名'.从服务器收到的身份验证标头是'Negotiate,NTLM'."

事件簿

事件日志中存在以下错误:

异常:System.ServiceModel.ServiceActivationException:由于编译期间发生异常,无法激活服务'/Service.svc'.例外消息是:此服务的安全设置需要"匿名"身份验证,但未为承载此服务的IIS应用程序启用.

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

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

修订版1

在阅读此SO问题后,我删除了元数据端点.这还没有解决问题.

修订版2

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

Web服务 - Web配置(修订版)

<basicHttpBinding>
    <binding name="basicBindingConfig">
        <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" 
                proxyCredentialType="Windows" 
                realm="" />
        </security>
    </binding>
</basicHttpBinding>
Run Code Online (Sandbox Code Playgroud)

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

<!-- ... -->
<security mode="TransportCredentialOnly">
    <transport clientCredentialType="Windows" 
        proxyCredentialType="Windows"
        realm="" />
    <message clientCredentialType="UserName" 
        algorithmSuite="Default" />
</security>
<!-- ... -->
Run Code Online (Sandbox Code Playgroud)

错误(修订)

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

HTTP请求未经授权使用客户端身份验证方案"Negotiate".从服务器收到的身份验证标头是"Negotiate SOMEHUGESCARYKEYHERE"

Sve*_*sen 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>
Run Code Online (Sandbox Code Playgroud)

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

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
Run Code Online (Sandbox Code Playgroud)

在客户端:

<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>
Run Code Online (Sandbox Code Playgroud)

HTH,斯文


mar*_*c_s 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(在他的WCF 编程书籍 - WCF 圣经)中确定的五种最常见和最有用的安全场景 - 以限制可能的组合数量您可能想要调整的参数。其中之一是“互联网”场景,如果您的服务是面向外部的,则可能适用于此。

马克