【问题标题】:WCF with Kerberos Authentication: The request for security token could not be satisfied because authentication failed带有 Kerberos 身份验证的 WCF:无法满足对安全令牌的请求,因为身份验证失败
【发布时间】:2015-03-05 21:12:50
【问题描述】:

我正在尝试从客户端应用程序(Windows 窗体)到在 IIS 下运行的一个 Windows 2008 R2 服务器上的 WCF Web 服务执行 Kerberos 身份验证,这反过来又调用在另一个也在运行的 Windows 2008 R2 服务器上运行的另一个 WCF 服务在 IIS 下。我已经看到这被称为 Kerberos 双跳身份验证。

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

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

  • 我创建了一个 Windows 窗体客户端应用程序,该应用程序连接到 WCF Web 服务(我将其称为中间服务),以及 将登录用户的用户名从 服务。
  • 在客户端 app.config(见下文)中,我们指定了“Windows” 身份验证(请参阅下面的配置)。
  • 中间服务在我们的服务器“SERVER1”上运行。
  • 中间服务将用户名返回给客户端应用程序, 因此,中间服务身份验证必须正常工作。
  • 我在中间服务中有另一个方法调用另一个 WCF Web 服务(我将这第二个服务称为 End 服务), 并再次在绑定中指定 Windows 身份验证 中间服务到终端服务。如果我在 与中间服务相同的服务器,然后再次进行身份验证 预期,登录用户的用户名(即:我)是 从 End 服务返回到客户端应用程序,通过 Middle 服务。但是,如果我在不同的服务器上找到 End 服务 (SERVER2)身份验证(双跳)失败,'内部异常: 无法满足对安全令牌的请求,因为 身份验证失败。'
  • Client 应用程序、Middle 服务和 End 服务都存在于同一个 域 (MYDOMAIN)。
  • 我正在使用服务帐户 (MYDOMAIN\MY-HOST_ACCOUNT) 来运行两者 中间和终端服务,并创建了服务主体名称 (SPN) 为此称为“HTTP/SERVER1.int.mydomain.com”。我也信任过 此服务帐户,以及 Kerberos 的计算机/机器“SERVER1” Active Directory 中的委派(信任此用户/计算机 委托给任何服务)。绑定使用“消息”安全模式 这在 Web 服务绑定中指定。
  • 我已经包含了客户端 app.config 和 Web 服务 web.configs(请参见下文)。
  • 我尝试了各种不同的配置设置,这些 当服务位于同一位置时,当前设置工作正常 服务器,但是当服务不同时会发生错误 服务器。我已经尝试过“真”和“假” 'negotiateServiceCredential',但相信这需要是“真实的”。一世 设置为 false 时会收到不同的错误消息( 使用 Kerberos 的身份验证模式不支持模拟 “代表团”级别。指定身份或冒名顶替)。

希望以前处理过“双跳”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)

【问题讨论】:

    标签: c# web-services wcf authentication kerberos


    【解决方案1】:

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

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

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

    由于 MiddleService 需要模拟/委托给 EndService,您需要使用本地安全策略 - 本地策略 - 用户权限分配给域帐户授予权限:

    作为操作系统的一部分

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

    身份验证后模拟客户端

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

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

    【讨论】:

    • 非常感谢,是的,这一切都有帮助。我还必须在 web.config 中为端点行为添加 allowNtlm="false,如下所示:
    猜你喜欢
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多