简体   繁体   English

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

[英]Delegate IIS Application Pool account to WCF service calls

I have developed a WCF service which is running in IIS (IIS 7.5 to be exact). 我已经开发了在IIS(准确地说是IIS 7.5)中运行的WCF服务。 This service runs under its own app pool, under a specific domain identity. 此服务在特定域标识下在其自己的应用程序池中运行。 This service references & calls other WCF services hosted elsewhere in the network, which in turn access various resources (Event Log, SQL Servers etc). 该服务引用并调用网络中其他地方托管的其他WCF服务,这些服务依次访问各种资源(事件日志,SQL Server等)。

Calls to my service are authenticated using username & password, through a custom UserNamePasswordValidator . 通过自定义UserNamePasswordValidator使用用户名和密码来验证对我的服务的调用。 The username(s) used are not domain credentials. 使用的用户名不是域凭据。

What I'm trying to do, is that when my service is called & it in turn calls the referenced services using the generated proxy classes, that it delegates the application pool identity as the calling identity, since this domain account has been granted rights to access the background resources like SQL Server. 我想做的是,当调用我的服务时,它又使用生成的代理类依次调用引用的服务,它委托应用程序池标识作为调用标识,因为该域帐户已被授予访问权限。访问SQL Server等后台资源。

My current implementation is as follows: 我当前的实现如下:

Service Configuration 服务配置

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

Service behavior code 服务行为代码

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

    return client.PerformAction();
}

Using this code, whenever a client makes a call to my service, the following is thrown: 使用此代码,每当客户调用我的服务时,就会引发以下情况:

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

Could someone please assist me, or point me in the right direction on how to implement this authentication configuration? 有人可以为我提供帮助,或者为我指出如何实施此身份验证配置的正确方向吗?

I've managed to find a working solution. 我设法找到了可行的解决方案。 It is implemented as such: 它是这样实现的:

The client proxy credentials need to be set to those of the IIS Application Pool, since these don't get picked up automatically: 客户端代理凭据需要设置为IIS应用程序池的凭据,因为不会自动获取这些凭据:

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

Also, the remote service I was connecting to had a service principal that needed to be included in the endpoint configuration. 另外,我连接到的远程服务的服务主体需要包含在端点配置中。 So I modified the config that was generated by the VS tooling to the following: 因此,我将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>

With this configuration, I was able to authenticate to my service by username & password, then have my service access a SQL Server instance using the domain credentials that the application pool was running under in IIS. 使用此配置,我能够通过用户名和密码对我的服务进行身份验证,然后让我的服务使用应用程序池在IIS下运行的域凭据来访问SQL Server实例。

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

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