使用 kerberos 的 WCF 配置在某些域上失败

WCF configuration using kerberos fails on certain domains

我不太确定,这个问题就在 Whosebug 上...也许它属于 serverfault...无论如何,它是这样的:

我们有 server/client 实施 WCF 服务的设置。客户端和服务都在域用户下 运行。托管服务器端服务的域用户也是服务器上的本地管理员。此设置适用于大多数客户。某些客户抱怨说,他们无法使用服务器的主机名进行单点登录 (SSO)。我们跟进了那个问题并发现,如果我们指定服务器的 IP 地址,一切正常。对我来说,这表明我们的配置工作正常,但某些域配置会干扰我们的设置。

WCF 配置:

<configuration>
  <system.serviceModel>
    <client>
      <!-- minimal needed config, address will be ignored -->
      <endpoint address="net.tcp://inihost:10100/ApplicationService" binding="netTcpBinding"
                bindingConfiguration="nosecNetTcpBinding" name="ApplicationServiceHost"
                    contract="Kaba.Exos.Transport.Infrastructure.ICommandExecutionService" />
      <endpoint address="net.tcp://inihost:10100/ApplicationServiceSSO"     binding="netTcpBinding"
                bindingConfiguration="ssoNetTcpBinding"     name="ApplicationServiceSsoHost"
                    contract="Kaba.Exos.Transport.Infrastructure.ICommandExecutionService" />
    </client>
    <bindings>
      <netTcpBinding>
        <binding name="nosecNetTcpBinding" receiveTimeout="00:30:00"     sendTimeout="00:30:00" maxBufferPoolSize="134217728" maxBufferSize="134217728"     maxReceivedMessageSize="134217728">
          <security mode="None"></security>
        </binding>
        <binding name="ssoNetTcpBinding" receiveTimeout="00:30:00"     sendTimeout="00:30:00" maxBufferPoolSize="134217728" maxBufferSize="134217728"     maxReceivedMessageSize="134217728">
          <security mode="Transport">
            <message clientCredentialType="Windows" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

设置 WCF 连接的 C# 代码:

        var exeConfigFileFullPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\" + exeConfigFilename;

        var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = exeConfigFileFullPath };

        var newConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

        try
        {
            this.channelFactory = new ConfigurationChannelFactory<ICommandExecutionServiceChannel>(endpointConfigurationName, newConfig, null);
        }
        catch (Exception e)
        {
            traceLogger.TraceException(e, "CommandExecutionServiceClient", "CommandExecutionServiceClient");
            throw;
        }

        if (!string.IsNullOrEmpty(serviceConnection.Item1))
        {
            var builder = new UriBuilder(this.channelFactory.Endpoint.Address.Uri) { Host = serviceConnection.Item1, Port = serviceConnection.Item2 };
            this.channelFactory.Endpoint.Address = new EndpointAddress(builder.Uri);
        }

        this.AddForwardExceptionToClientEndpointBehavior();
    }

实施两个小改动后....

在 WCF 文件中

  <!-- minimal needed config, address will be ignored -->
  <endpoint address="net.tcp://inihost:10100/ApplicationServiceSSO" binding="netTcpBinding"
            bindingConfiguration="ssoNetTcpBinding" name="ApplicationServiceSsoHost"
            contract="Kaba.Exos.Transport.Infrastructure.ICommandExecutionService" behaviorConfiguration="kerberosFallbackToNtlm">

    <behaviors>
      <endpointBehaviors>
        <behavior name="kerberosFallbackToNtlm">
          <clientCredentials>
            <!-- if Kerberos is required, set the following value to false and configure the proper identity for Exos9300ServiceSsoHost above. -->
            <windows allowNtlm="true" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>

在代码中

this.channelFactory.Endpoint.Address = new EndpointAddress(builder.Uri, EndpointIdentity.CreateSpnIdentity(String.Empty));

此设置适用于域设置,我们之前在域设置中遇到了 "SSPI context could not be established" 错误。

现在我的问题是:

为什么这个设置在一个域上运行良好,但在另一个域上却失败了。是否有任何可能影响此行为的 Active Directory 设置?

好吧,事实证明我被误导了....在它工作的情况下,我们有一个本地用户 运行 服务而不是域用户。因此,如果服务由本地管理员用户托管,服务身份验证将回退到 NTLM。

通过删除默认创建的 SPN 并手动添加新的 SPN,我确实设法让这个场景起作用。

删除默认创建的现有 SPN:

setspn -D HOST/{HOSTNAME server} {HOSTNAME server}

为域用户添加新的 SPN:

setspn -S HOST/{HOSTNAME server} {Domainuser service}

注意!!

一旦我发出命令:

setspn -D HOST/{FQDN server} {HOSTNAME server}

并设法禁止我的服务器使用域控制器对任何域用户进行身份验证,因为它不再位于信任数据库中。