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

时间:2015-03-24 13:12:22

标签: c# .net web-services iis-7.5 wcf-security

我开发了一个在IIS中运行的WCF服务(确切地说是IIS 7.5)。此服务在其自己的应用程序池下,在特定的域标识下运行。这项服务参考&调用网络中其他地方托管的其他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'.

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

1 个答案:

答案 0 :(得分:0)

我设法找到了一个有效的解决方案。它实现如下:

客户端代理凭据需要设置为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>

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