将 IIS 应用程序池帐户委托给 WCF 服务调用

Delegate IIS Application Pool account to WCF service calls

我在 IIS(确切地说是 IIS 7.5)中开发了 运行 的 WCF 服务。此服务在其自己的应用程序池下运行,在特定的域身份下。此服务引用并调用网络中其他地方托管的其他 WCF 服务,这些服务依次访问各种资源(事件日志、SQL 服务器等)。

通过自定义 UserNamePasswordValidator 使用用户名和密码对对我的服务的调用进行身份验证。使用的用户名 不是 域凭据。

我想做的是,当我的服务被调用时,它又使用生成的代理 类 调用引用的服务,它将应用程序池身份委托为调用身份,因为此域帐户已被授予访问后台资源的权限,例如 SQL Server.

我目前的实现如下:

服务配置

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="RemoteServiceBinding" closeTimeout="00:10:00"
          openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
          maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
          <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"
            maxBytesPerRead="2147483647" />
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
      <wsHttpBinding>
        <binding name="MyServiceBinding" closeTimeout="00:10:00" openTimeout="00:10:00"
          receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="2147483647"
          maxReceivedMessageSize="2147483647">
          <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"
            maxBytesPerRead="2147483647" />
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://remote.service.address/Service.svc"
        binding="basicHttpBinding" bindingConfiguration="RemoteServiceBinding"
        contract="RemoteService.IRemoteService" name="RemoteServiceBinding" />
    </client>
    <services>
      <service name="MyService.MyService" behaviorConfiguration="MyServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyServiceBinding" contract="MyService.IMyService">
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/MyService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyServiceBehavior">
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="True" />
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="None" />
            </clientCertificate>
            <serviceCertificate findValue="AuthCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyService.CredentialValidator, MyService" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
</system.serviceModel>

服务行为代码

using (var client = new Proxy.RemoteServiceClient()) {
    client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;

    return client.PerformAction();
}

使用此代码,每当客户端调用我的服务时,都会抛出以下内容:

The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.

有人可以帮助我,或者为我指明如何实施此身份验证配置的正确方向吗?

我设法找到了可行的解决方案。它是这样实现的:

客户端代理凭据需要设置为 IIS 应用程序池的凭据,因为这些不会自动获取:

client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;

另外,我连接的远程服务有一个服务主体需要包含在端点配置中。所以我将 VS 工具生成的配置修改为以下内容:

<client>
  <endpoint address="http://remote.service.address/Service.svc"
    binding="basicHttpBinding" bindingConfiguration="RemoteServiceBinding"
    contract="RemoteService.IRemoteService" name="RemoteServiceBinding">
    <identity>
      <servicePrincipalName value="spn_name" />
    </identity>
  </endpoint>
</client>

使用此配置,我能够通过用户名和密码对我的服务进行身份验证,然后让我的服务使用应用程序池 运行 所在的域凭据访问 SQL 服务器实例在 IIS 中。