WCF + NTLM身份验证和负载平衡问题

时间:2011-09-20 17:15:04

标签: .net wcf wcf-security

再一次尝试让我的WCF服务在我们的负载平衡环境中工作,我一直充满希望。我已经开始使用<customBinding>了,因为recommendation似乎是设置keepAliveEnabled指令。

也就是说,我在服务器端设置Windows身份验证时遇到问题,因为<customBinding>似乎没有以相同的方式运行。

服务器端看起来像这样:

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
  <customBinding>
    <binding name="HttpBinding" closeTimeout="00:00:45">
      <textMessageEncoding>
        <readerQuotas maxStringContentLength="200000" maxArrayLength="200000" />
      </textMessageEncoding>
      <httpTransport keepAliveEnabled="false" maxReceivedMessageSize="200000" authenticationScheme="Negotiate"/>
    </binding>
  </customBinding>
</bindings>
<services>
    <endpoint address="http://svcserv/Services/ReportService/Reports.svc" binding="customBinding"
              bindingConfiguration="HttpBinding" contract="ReportService.IReports" >
    </endpoint>
    <endpoint address="mex" binding="customBinding" bindingConfiguration="HttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="ReportService.ReportsBehavior">
      <serviceMetadata httpGetEnabled="true"  />
      <serviceDebug includeExceptionDetailInFaults="true"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
</system.serviceModel>

客户端看起来像这样:

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
  <basicHttpBinding>
    <binding name="CustomBinding_IReports" maxReceivedMessageSize="200000">
      <security mode="TransportCredentialOnly">
        <transport clientCredentialType="Windows"/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<client>
  <endpoint name="CustomBinding_IReports" address="http://omsnetdev/Services/ReportService/Reports.svc"
            binding="basicHttpBinding" bindingConfiguration="CustomBinding_IReports" contract="ReportService.IReports">
    <identity>
      <servicePrincipalName value="host/svcserv"/>
      <dns value="svcserv"/>
    </identity>
  </endpoint>
</client>
</system.serviceModel>

如果我将authenticationScheme设置为“Negotiate”,那么我会收到SOAP header Action was not understood.Client found response content type of '', but expected 'application/soap+xml'.的某些内容,Exception: The request failed with HTTP status 401: Unauthorized. 如果我将authenticationScheme更改为“Ntlm”,那么我会收到{{1}}但我认为这是由于协商失败(due to the SPN value?)所以它会回落到“Ntlm”并失败。

我会在IIS服务器上将其写为配置,但我已验证了设置。

2 个答案:

答案 0 :(得分:4)

我认为这不仅是WCF问题,而且是概念模型。您希望完全构建无状态方案,但同时需要有状态地处理身份验证,因为在单个请求响应中执行NTLM(并且没有其他传输级别身份验证)。

以下简要说明握手的工作原理:

      Client                                                Server
-----------------------------------------------------------------------------------------
Send initial request ---------------------------->
                     <----------------------------  Returns 401 with WWW-Authenticate 
                                                    header demanding NTLM
Sends empty request  ---------------------------->  
with Authorization                                
header with initial 
token                                    
                     <----------------------------  Returns 401 with WWW-Authenticate 
                                                    header containing some server token
Sends request with   ---------------------------->  
Authorization header                                
with final token                                    
                     <----------------------------  Returns 200 and expected response

此握手必须使用单个负载平衡服务器执行,但是一旦关闭持久HTTP连接,您将强制客户端为每个呼叫打开新的TCP连接,并且每个呼叫都是单独负载平衡的。这很可能会以传递给不同服务器的这些调用结束=&gt;验证失败。简而言之,您需要:

  • 在HTTP之上运行的更高级别的负载平衡(将使用负载均衡器进行身份验证)并且对服务的调用将是匿名的
  • 另一种在消息
  • 中传递凭据的身份验证技术
  • 强制请求路由到正确服务器的持久连接。如果您在IIS中托管服务,您可以将保持活动间隔减少到几秒,并希望这将提高负载平衡的有效性

答案 1 :(得分:1)

如果您遇到与SPN相关的问题,请参阅以下答案:SO WCF-Security-Problem question

您应该在负载均衡器上遇到的唯一问题是您是否需要会话对一个主机保持“粘性”。对于给定的会话,如果正确配置,负载均衡器应该能够为您执行此操作。

请注意,如果您在同一台计算机上安装了服务器和客户端,则Windows服务器具有不使用SSPI的回退模式。当你从测试移动到prod时,这会让你被烧掉。