简体   繁体   English

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

[英]Problem with WCF + NTLM authentication and load balancing

Once again attempting to get my WCF service working in our load balanced environment and I've been hopeful. 再次尝试使我的WCF服务在负载平衡的环境中工作,我一直抱有希望。 I've moved on to using a <customBinding> since it appears that the recommendation is to set the keepAliveEnabled directive. 我继续使用<customBinding>因为看来建议是设置keepAliveEnabled指令。

That said, I am having a problem setting up Windows authentication on the server side since the <customBinding> does not seem to function in the same way. 就是说,由于<customBinding>似乎无法以相同的方式运行,因此在服务器端设置Windows身份验证时遇到了问题。

The server side looks like this: 服务器端看起来像这样:

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

The client side looks like this: 客户端看起来像这样:

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

If I leave the authenticationScheme set to "Negotiate" then I receive something along the lines of either SOAP header Action was not understood. 如果我将authenticationScheme设置为“ Negotiate”,那么我将沿任一SOAP header Action was not understood.收到类似的消息SOAP header Action was not understood. or, at one point, Client found response content type of '', but expected 'application/soap+xml'. 或者,某一时刻, Client found response content type of '', but expected 'application/soap+xml'. If I change the authenticationScheme to "Ntlm" then I receive Exception: The request failed with HTTP status 401: Unauthorized. 如果我将authenticationScheme更改为“ Ntlm”,则会收到Exception: The request failed with HTTP status 401: Unauthorized. but I believe this is due to the negotiation failing ( due to the SPN value? ) so it falls back to "Ntlm" and fails. 但是我认为这是由于协商失败( 由于SPN值?导致的,因此回退到“ Ntlm”并失败了。

I would write this off as a configuration on the IIS server but I have verified the settings. 我将其注销为IIS服务器上的配置,但已验证了设置。

I belief this is not only WCF problem but a conceptual model. 我相信这不仅是WCF问题,而且是概念模型。 You want to make completely stateless scenario but in the same time you need stateful handling of authentication because NTLM (and no other transport level authentication) is performed within single request response. 您希望创建完全无状态的方案,但是同时您需要对认证进行有状态的处理,因为NTLM(并且没有其他传输级别的认证)是在单个请求响应中执行的。

Here is short description how the handshake works: 这是握手的简短说明:

      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

This handshake must be performed with single load balanced server but once you turn off persistent HTTP connections you will force your client to open new TCP connection for each call and each call is load balanced separately. 此握手必须在单个负载平衡服务器上执行,但是一旦关闭持久HTTP连接,您将强制客户端为每个调用打开新的TCP连接,并且每个调用将分别进行负载平衡。 That will most probably ends with these calls passed to different servers => authentication failed. 这很可能以将这些调用传递到其他服务器而结束=>身份验证失败。 In short you need either: 简而言之,您需要:

  • Higher level load balancing operating on top of HTTP (authentication will be done with load balancer) and calls to service will be anonymous 在HTTP之上运行更高级别的负载平衡(身份验证将通过负载平衡器完成),并且对服务的调用将是匿名的
  • Another authentication technique passing credentials in message 在消息中传递凭据的另一种身份验证技术
  • Persistent connections to force request routing to correct server. 持久连接强制将请求路由到正确的服务器。 If you are hosting services in IIS you can reduce keep alive interval to few seconds and hope that this will improve load balancing effectivity 如果您在IIS中托管服务,则可以将保持活动间隔减少到几秒钟,并希望这可以提高负载平衡的有效性。

If you have a problem related to the SPN, please see this answer: SO WCF-Security-Problem question 如果您有与SPN相关的问题,请参见以下答案: SO WCF-Security-Problem问题

The only issue you should have with the load balancer is whether you need your session to remain "sticky" to one host. 负载平衡器应该有的唯一问题是,是否需要让会话保持对某个主机的“粘性”。 For a given session the load balancer should be able to do this for you if you configure it correctly. 对于给定的会话,如果配置正确,负载均衡器应该可以为您执行此操作。

Note that windows server has a fallback mode that does not use SSPI if you have the server and client on the same machine. 请注意,如果服务器和客户端在同一台计算机上,则Windows服务器具有不使用SSPI的后备模式。 This lets you get burnt when you move from test to prod. 当您从测试转移到产品时,这会让您感到沮丧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM