具有 Kerberos 身份验证的 WCF:无法满足对安全令牌的请求,因为身份验证失败

WCF with Kerberos Authentication: The request for security token could not be satisfied because authentication failed

我正在尝试从客户端应用程序(Windows 表单)到一个 Windows 2008 R2 服务器上的 WCF Web 服务执行 Kerberos 身份验证 运行ning 在 IIS 下,它在-turn 在另一个 Windows 2008 R2 服务器上调用另一个 WCF 服务 运行ning,也在 IIS 下 运行ning。我看到这被称为 Kerberos 双跃点身份验证。

当我在同一个 Windows 2008 R2 服务器上找到两个 Web 服务时,我们的双跳身份验证工作正常。但是,当我们将第二个 WCF 服务移动到不同的服务器时,两个 Web 服务之间的身份验证失败。我不知道是什么导致了这个问题,这可能是配置问题,或者是我们的 server/network 设置中的问题。客户端和服务器都在同一个域中。

这里是我目前所做工作的更多细节。关于这个问题,我已经尝试了其他相关 topics/questions 中的许多建议,但到目前为止没有任何乐趣。

希望之前处理过 'double hop' WCF Kerberos 身份验证的人可以认识到这个问题并能够帮助我。

非常感谢

客户端应用配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IMiddleService">
                    <security mode="Message">
                        <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" algorithmSuite="Default" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <behaviors>
          <endpointBehaviors>
            <behavior name="DelegationBehavior">
              <clientCredentials>
                <windows allowedImpersonationLevel="Delegation" />
              </clientCredentials>
            </behavior>
          </endpointBehaviors>
        </behaviors>
        <client>
          <endpoint address="http://SERVER1/KerberosMiddleService/MiddleService.svc"
              behaviorConfiguration="DelegationBehavior" binding="wsHttpBinding"
              bindingConfiguration="WSHttpBinding_IMiddleService" contract="KerberosMiddleService.IMiddleService"
              name="WSHttpBinding_IMiddleService">
            <identity>
              <servicePrincipalName value="HTTP/SERVER1.int.mydomain.com"/>
              <userPrincipalName value="MYDOMAIN\MY-HOST_ACCOUNT@int.mydomain.com"/>
            </identity>
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>

中间服务网络配置

<?xml version="1.0"?>
<configuration>
  <appSettings/>
  <system.web>
    <compilation targetFramework="4.0"/>
    <httpRuntime/>
    <customErrors mode="Off"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IEndService">
          <security mode="Message">
            <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" algorithmSuite="Default"/>
          </security>
         </binding>
          <binding name="WSHttpBinding_IEndService1">
          <security mode="Message">
            <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" algorithmSuite="Default" />
          </security>
         </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceAuthorization impersonateCallerForAllOperations="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="DelegationBehavior">
         <clientCredentials>
           <windows allowedImpersonationLevel="Delegation" />
         </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <endpoint address="http://SERVER2/endservice/endservice.svc" 
                behaviorConfiguration="DelegationBehavior" binding="wsHttpBinding" 
                bindingConfiguration="WSHttpBinding_IEndService" contract="KerberosEndService.IEndService"
                name="WSHttpBinding_IEndService">
      </endpoint>
      <endpoint address="http://SERVER1/kerberosendservice/endservice.svc" 
                behaviorConfiguration="DelegationBehavior" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IEndService1" contract="BT01_KerberosEndService.IEndService"
                name="WSHttpBinding_IEndService1">
      </endpoint>
    </client>
    <protocolMapping>
      <add binding="wsHttpBinding" scheme="http"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

结束服务网络配置

<?xml version="1.0"?>
<configuration>
  <appSettings/>
<system.web>
    <customErrors mode="Off"/>
    <compilation targetFramework="4.0"/>
    <httpRuntime/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceAuthorization impersonateCallerForAllOperations="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="wsHttpBinding" scheme="http"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

WCF 堆栈跟踪的一部分

<ExceptionString>System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service. ---&amp;gt; System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
   at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
   at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
   --- End of inner exception stack trace ---</ExceptionString><InnerException><ExceptionType>System.ServiceModel.FaultException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>The request for security token could not be satisfied because authentication failed.</Message><StackTrace>   at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
   at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)</StackTrace><ExceptionString>System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
   at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
   at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)</ExceptionString></InnerException></Exception></TraceRecord></DataItem></TraceData></ApplicationData></E2ETraceEvent><E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent"><System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system"><EventID>131075</EventID><Type>3</Type><SubType Name="Error">0</SubType><Level>2</Level><TimeCreated SystemTime="2015-03-02T21:04:14.4059347Z" /><Source Name="System.ServiceModel" /><Correlation ActivityID="{acfc80d6-b119-4f57-aaf2-65f1319b9fca}" /><Execution ProcessName="w3wp" ProcessID="1432" ThreadID="43" /><Channel/><Computer>SERVER1</Computer></System><ApplicationData><TraceData><DataItem><TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error"><TraceIdentifier>http://msdn.microsoft.com/en-NZ/library/System.ServiceModel.Diagnostics.ThrowingException.aspx</TraceIdentifier><Description>Throwing an exception.</Description><AppDomain>/LM/W3SVC/1/ROOT/KerberosMiddleService-6-130698038017642990</AppDomain><Exception><ExceptionType>System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>The caller was not authenticated by the service.</Message><StackTrace>   at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
   at System.ServiceModel.Security.IssuanceTokenProviderBase`1.GetNextOutgoingMessage(Message incomingMessage, T negotiationState)
   at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)</StackTrace><ExceptionString>System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service. ---&amp;gt; System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
   at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)

好的,您还需要为终端服务添加另一个 SPN:

HTTP/SERVER2.int.mydomain.com MYDOMAIN\MY-HOST_ACCOUNT)
HTTP/SERVER2 MYDOMAIN\MY-HOST_ACCOUNT)

最好同时指定 FQDN 和 Netbios 名称。确保您没有重复的 SPN,否则 Kerberos 身份验证将无法工作。将 SPN 作为委派目标添加到域帐户(这可能不需要,因为您对两个服务器使用相同的域帐户)。

由于 MiddleService 需要 impersonate/delegate 到 EndService,您需要使用本地安全策略 - 本地策略 - 用户权限分配来授予域帐户权限:

作为操作系统的一部分

此用户权限允许进程在未经身份验证的情况下模拟任何用户。因此,该进程可以访问与该用户相同的本地资源。

身份验证后模拟客户端

将此权限分配给用户允许程序 运行 代表该用户模拟客户端。

记得更改您的 IIS 应用程序设置以使用应用程序池凭据,以便使用域帐户进行身份验证。