Как добавить поддержку NTLM для хоста Kestrel? - PullRequest
1 голос
/ 10 октября 2019

Мы хотели бы использовать Kestrel для размещения нашего веб-API. Мы должны поддерживать аутентификацию NTLM и Negotiate.

Это должно быть возможно с Core 3.0 https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio

Однако, когда Kestrel отвечает только на вызов, возвращается схема согласования. Кому-нибудь удалось реализовать проверку подлинности NTLM с помощью Kestrel?

Приложение работает на компьютере с Windows 10

В основном мы следовали рекомендациям. Сначала добавили аутентификацию для сервисов:

        services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();

, а затем добавили аутентификацию в конвейер

        app.UseAuthentication();

Также в конвейере у нас есть собственное промежуточное программное обеспечение для проверки пользователя

        app.UseMiddleware<ValidateAuthentication>();

Реализация выглядит следующим образом

internal class ValidateAuthentication : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        if (context.User.Identity.IsAuthenticated)
            await next(context);
        else
            await context.ChallengeAsync();
    }
}

Проблема в том, что ответ на вызов имеет только Negotiate

    WWW-Authenticate Negotiate

Я ожидал бы и NTLM, и Negotiate

    WWW-Authenticate NTLM, Negotiate

1 Ответ

0 голосов
/ 10 октября 2019

Вы можете переопределить метод HandleChallengeAsync , а затем заменить обработчик:

public sealed class NtlmNegotiateHandler : NegotiateHandler
{
    public NtlmNegotiateHandler(
        IOptionsMonitor<NegotiateOptions> options, 
        ILoggerFactory logger, UrlEncoder encoder, 
        ISystemClock clock) : base(options, logger, encoder, clock)
    {
    }

    protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        await base.HandleChallengeAsync(properties);

        if (Response.StatusCode ==  StatusCodes.Status401Unauthorized)
        {
            Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.WWWAuthenticate, "NTLM");
        }
    }
}
public sealed class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddAuthentication(NegotiateDefaults.AuthenticationScheme)
            .AddNegotiate();

        // replace the handler
        var serviceDescriptor = new ServiceDescriptor(typeof(NegotiateHandler), 
                                                      typeof(NtlmNegotiateHandler), 
                                                      ServiceLifetime.Transient);

        services.Replace(serviceDescriptor);
    }
}
...