如何为 Kestrel 主机添加 NTLM 支持?

Posted

技术标签:

【中文标题】如何为 Kestrel 主机添加 NTLM 支持?【英文标题】:How do I add NTLM support for a Kestrel host? 【发布时间】:2020-02-07 15:43:21 【问题描述】:

我们想使用 Kestrel 来托管我们的 web-api。我们必须同时支持 NTLM 和协商身份验证。

Core 3.0 应该可以做到这一点 https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio

但是,当 Kestrel 响应挑战时,只会返回协商方案。有没有人设法使用 Kestrel 实现 NTLM 身份验证?

应用程序在 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();
    

问题是挑战响应只有协商

    WWW-Authenticate Negotiate

我本来期望 NTLM 和协商

    WWW-Authenticate NTLM, Negotiate

【问题讨论】:

【参考方案1】:

您可以覆盖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);
    

【讨论】:

谢谢 Andriy 现在看来挑战是正确的。并且通过正确的挑战,我的客户将响应一个包括 NTLM 令牌的新请求。只有服务仍然无法进行身份验证。我想我也必须重写 HandleAuthenticateAsync 。只有我不知道如何验证 NTLM 令牌?【参考方案2】:

对于 .NET 6

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
app.UseAuthorization();
app.MapControllers().RequireAuthorization();

或者您可以将 [Authorize] 注释添加到您的控制器类中,而不是要求所有控制器进行身份验证。

【讨论】:

谢谢@Michal 这真的很有帮助。我们的团队肯定会使用它【参考方案3】:

对于那些感兴趣的人,根据迈克尔的回复,我们现在已经开始工作了

但是有一个问题。 Kestrel 不会自行发起挑战响应。我们使用类似的代码构建自己的

public class ValidateAuthentication : IMiddleware

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    
        if (context.Request.Method == "OPTIONS")
        
            await next(context);
            return;
        

        if (context.User.Identity != null && context.User.Identity.IsAuthenticated)
        
            await next(context);
        
        else
        
            context.Response.StatusCode = 401;
            context.Response.Headers["Proxy-Authenticate"] = "Negotiate";
            context.Response.Headers["WWW-Authenticate"] = "Negotiate";
            context.Response.Headers["Access-Control-Allow-Origin"] = context.Request.Headers["Origin"];
        
    

【讨论】:

以上是关于如何为 Kestrel 主机添加 NTLM 支持?的主要内容,如果未能解决你的问题,请参考以下文章

如何为自己的WordPress站点安装SSL证书开启https访问

如何为我的 SQL 数据库添加远程主机以将其与我开发的应用程序连接

如何为现有 iOS 应用添加 CarPlay 支持? [复制]

如何为你的 Flutter 项目添加 Kotlin 支持?

如何为 xampp 的 php 7.3 添加 GD 支持?

如何为自己的WordPress站点安装SSL证书开启https访问