.NET Core 3.1 API Calling .NET Framework WCF Service secured using windows authentication (AD Group)

问题


I am trying to call a .NET Framework WCF Service (which is secured by Windows Authentication using an AD group) from a .NET Core 3.1 API however I am getting the error message:

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

The .NET Core API is hosted in IIS both on windows and the app pool that it runs under has a domain account which is in the AD Group required for access. We currently have other .NET Framework applications calling the WCF service and they all work however this is the first .NET Core application to call it. Both servers which the API is deployed to and the WCF service is deployed to exist on the same domain that support Kerberos protocol.

It works successfully when running locally however when deployed onto a server it gives the above error message.

IIS Logs from the error message occuring:

POST /Broadcast.svc - 8081 - 172.27.19.200 - - 401 2 5 0
POST /Broadcast.svc - 8081 - 172.27.19.200 - - 401 1 3221225581 0

This is the client proxy creation code in the API:

    public IWcfClient<IBroadcastService> CreateBroadcastService()
    {
        var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
        binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Windows;

        var client = new WcfClient<IBroadcastService>(
            binding,
            new EndpointAddress($"{remoteUrl}/Broadcast.svc"));

        //My expectation is that the below line would make the call send the AppPoolIdentity Credentials?
        client.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;

        return client;
    }

WcfClient.cs (Wrapper for ClientBase):

public class WcfClient<TChannel> : ClientBase<TChannel>, IWcfClient<TChannel> where TChannel : class
{
    public WcfClient(Binding binding, EndpointAddress endpointAddress)
        : base(binding, endpointAddress)
    { }

    /// <summary>
    /// Executes a given action against <see cref="TChannel" />.
    /// </summary>
    /// <param name="invokeAction">The invocation action.</param>
    public void Invoke(Action<TChannel> invokeAction)
    {
        try
        {
            invokeAction(Channel);
            Close();
        }
        catch (CommunicationException)
        {
            Abort();
            throw;
        }
        catch (TimeoutException)
        {
            Abort();
            throw;
        }
    }

    /// <summary>
    /// Executes the given action against <see cref="TChannel" /> and returns the result.
    /// </summary>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    /// <param name="invokeFunc">The invocation function.</param>
    /// <returns>An instance of <see cref="TResult" /></returns>
    public TResult Invoke<TResult>(Func<TChannel, TResult> invokeFunc)
    {
        TResult result;

        try
        {
            result = invokeFunc(Channel);
            Close();
        }
        catch (CommunicationException)
        {
            Abort();
            throw;
        }
        catch (TimeoutException)
        {
            Abort();
            throw;
        }

        return result;
    }
}

Startup.cs Configure method for API:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        logger.Information("Configuring application middleware...");

        if (env.IsDevelopment())
            app.UseDeveloperExceptionPage();

        app.UseSwaggerMiddleware();

        app.UseSerilogRequestLogging();

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

        ConfigCache.SetRootDirectory(Path.Combine(env.ContentRootPath, "App_Data"));

        logger.Information("Application middleware configured successfully.");
    }

Program.cs for API:

public class Program
{
    [UsedImplicitly]
    public static void Main(string[] args)
    {
        var appConfig = new ConfigurationBuilder()
            // ReSharper disable once StringLiteralTypo
            .AddJsonFile("appsettings.json")
            .Build();

        Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(appConfig)
            .Enrich.FromLogContext()
            .CreateLogger();

        CreateHostBuilder(args).Build().Run();
    }

    [UsedImplicitly]
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(
                webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseIIS();
                    webBuilder.UseSerilog();
                });
}

The web.config for the .NET Framework WCF service web.config has the specified role in like so (I have removed actual name)

<system.web>
    <authentication mode="Windows"/>
    <authorization>
      <allow roles="DOMAIN\GROUPNAME"/>
      <deny users="*"/>
    </authorization>
</system.web>

Can anyone tell me if I have missed anything or provide any ideas on how to narrow down the problem? Also please comment if you need to see any other areas of the code and will be happy to supply them.


回答1:


The fact they are both are hosted on the same machine, you may need to populate the BackConnectionHostNames registry key to disable the loopback security functionality.

Steps here: https://stackoverflow.com/a/48086033/4813939




回答2:


I see that you use windows authentication. When you use windows authentication, the server should also exist in a Windows domain that uses the Kerberos protocol as its domain controller. If the server is not on a Kerberos supported domain, or if the Kerberos system fails, you can use NT LAN Manager.

        <bindings>
            <basicHttpBinding>
                <binding name="SecurityByTransport">
                    <security mode="Transport">
                        <transport clientCredentialType="Ntlm"/>
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>

For more information about Transport Security,Please refer to the following link:

https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-overview



来源:https://stackoverflow.com/questions/62328027/net-core-3-1-api-calling-net-framework-wcf-service-secured-using-windows-authe

标签

更多相关内容:请点击查看