简体   繁体   English

ASP.NET 核心红隼 windows 身份验证在 docker 中识别错误用户

[英]ASP.NET Core kestrel windows authentication in docker identifies wrong user

I'm using docker (windows nanoserver), traefik, asp.net core 3.1 and windows authentication/negotiate.我正在使用 docker(windows nanoserver)、traefik、asp.net core 3.1 和 windows 身份验证/协商。 If a user connects to the container, he or she logs in and their user is bound to the httpcontext.如果用户连接到容器,他或她登录并且他们的用户被绑定到 httpcontext。 If another user connects afte that, the first user is still bound to the context.如果之后有另一个用户连接,第一个用户仍然绑定到上下文。

This is my setup in code:这是我在代码中的设置:

docker-compose.yml docker-compose.yml

version: "3.7"
services:
  webapplication:
    image: <repository>/webapplication:8-1
    networks:
      webapplication-network:
        aliases:
          - webapplication
      traefik:      
        aliases:
          - traefik-webapplication
    credential_spec:  
      file: webapp({GMSA_ACCOUNT})_credential.json
    secrets:
      - source: config_secrets
        target: C:/app/appsettings.json
    deploy:
      mode: replicated
      replicas: 1
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 10
        window: 30s
      labels: 
        - applicationname=({APPLICATIONNAME})
        - "traefik.enable=true"
        - "traefik.http.routers.({APPLICATIONNAME})-webapplication.rule=Host(`({APPLICATIONNAME})-webapplication.({DOMAIN})`)"
        - "traefik.http.routers.({APPLICATIONNAME})-webapplication.service=({APPLICATIONNAME})-webapplication"
        - "traefik.http.routers.({APPLICATIONNAME})-webapplication.entrypoints=https"
        - "traefik.http.routers.({APPLICATIONNAME})-webapplication.tls=true"
        - "traefik.http.services.({APPLICATIONNAME})-webapplication.loadbalancer.server.scheme=http"
        - "traefik.http.services.({APPLICATIONNAME})-webapplication.loadbalancer.server.port=80"

        # redirect http to https
        - traefik.http.middlewares.({APPLICATIONNAME})-webapplication-unsecure-redirect-secure.redirectscheme.scheme=https
        - traefik.http.routers.({APPLICATIONNAME})-webapplication-unsecure.middlewares=({APPLICATIONNAME})-webapplication-unsecure-redirect-secure
        - traefik.http.routers.({APPLICATIONNAME})-webapplication-unsecure.rule=Host(`({APPLICATIONNAME})-webapplication.({DOMAIN})`)
        - traefik.http.routers.({APPLICATIONNAME})-webapplication-unsecure.entrypoints=http

        # Attempt to make Windows authentication work through TCP
        - "traefik.tcp.routers.({APPLICATIONNAME})-webapplication.rule=HostSNI(`({APPLICATIONNAME})-webapplication.({DOMAIN})`)"
        - "traefik.tcp.routers.({APPLICATIONNAME})-webapplication.service=({APPLICATIONNAME})-webapplication"
        - "traefik.tcp.routers.({APPLICATIONNAME})-webapplication.tls=true"
        - "traefik.tcp.services.({APPLICATIONNAME})-webapplication.loadbalancer.server.port=80"         
        - "traefik.http.services.({APPLICATIONNAME})-webapplication.loadbalancer.sticky=true"

Dockerfile webapplication-windows-netcore-base Dockerfile webapplication-windows-netcore-base

# escape=`
FROM mcr.microsoft.com/windows/servercore:ltsc2019 AS installer
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

# Retrieve .NET Core Runtime
RUN $dotnet_version = '3.1.3'; `
    Invoke-WebRequest -OutFile dotnet.zip https://dotnetcli.azureedge.net/dotnet/Runtime/$dotnet_version/dotnet-runtime-$dotnet_version-win-x64.zip; `
    $dotnet_sha512 = '62a18838664afd6f08cdb9a90a96a67626743aab1f0de0065eadfd7d1df31681c90f96744ccb5b7e40834c9e3c4952125c8c83625867c500692050cdd113ff50'; `
    if ((Get-FileHash dotnet.zip -Algorithm sha512).Hash -ne $dotnet_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `
    Expand-Archive dotnet.zip -DestinationPath dotnet; `
    Remove-Item -Force dotnet.zip; `
# Install ASP.NET Core Runtime
    $aspnetcore_version = '3.1.3'; `
    Invoke-WebRequest -OutFile aspnetcore.zip https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$aspnetcore_version/aspnetcore-runtime-$aspnetcore_version-win-x64.zip; `
    $aspnetcore_sha512 = '6d8a21a7420db9091fc05613ef0a923c7b86cc995360c9f0133d632020e042db0efac0343ee6516a28feb2c1dd004b33b74bfdcc1a687efdefa9db1a486c1ca2'; `
    if ((Get-FileHash aspnetcore.zip -Algorithm sha512).Hash -ne $aspnetcore_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `
    Expand-Archive aspnetcore.zip -DestinationPath dotnet -Force; `
    Remove-Item -Force aspnetcore.zip
# Runtime image
FROM mcr.microsoft.com/windows/servercore:ltsc2019

ENV `
    # Configure web servers to bind to port 80 when present
    ASPNETCORE_URLS=http://+:80 `
    # Enable detection of running in a container
    DOTNET_RUNNING_IN_CONTAINER=true

WORKDIR C:\app
USER ContainerAdministrator
RUN setx /M PATH "%PATH%;C:\Program Files\dotnet" && `
    REG ADD HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 -f
COPY --from=installer ["/dotnet", "/Program Files/dotnet"]

Dockerfile webapplication Dockerfile 网络应用程序

# escape=`
##### Runtime #####
ARG baseImageVersie
ARG buildNumber
ARG release
FROM <repository>/webapplication-build:$release-$buildNumber AS buildtools
FROM webapplication-windows-netcore-base:$baseImageVersie 
ENV DOTNET_RUNNING_IN_CONTAINER=true
ENTRYPOINT ["dotnet", "webapplication.dll"]
COPY --from=buildtools C:/publish .

Startup.cs looks like this Startup.cs 看起来像这样

public class Startup
{
    private readonly IConfiguration configuration;

    public Startup(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers(o =>
        {
            o.Filters.Add(typeof(GlobalExceptionFilter));
        });
        services
            .AddAuthentication(NegotiateDefaults.AuthenticationScheme)
            .AddNegotiate(o => o.Validate());

        var appsettings = configuration.Get<Appsettings>();

        services.AddCors(options =>
        {
            options.AddPolicy("cors",
            builder =>
            {
                builder.WithOrigins(appsettings.Origins)
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { 
                Title = "Webapplication", 
                Version = "v1" ,
            });
            c.ExampleFilters();

            var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
            var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
            c.IncludeXmlComments(xmlPath); 
            c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); 
        });

        services.AddSwaggerExamplesFromAssemblyOf<AuthorizeModelExample>();

    }

    // ReSharper disable once UnusedMember.Global
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();

        app.UseCors("cors");
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints
                .MapControllers()
                .RequireAuthorization()
                .RequireCors("cors");
        });
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Webapplication V1");
        });
    }
}

UserController用户控制器

[Produces("application/json")]
[ApiController]
[Route("api/connect/[controller]")]
public class UserController : ControllerBase
{
    [HttpGet]
    public ActionResult Get()
    {
        return Ok(User?.Identity?.Name)
    }
}

What happens - User 1 logs in (using incognito mode) by filling in his credentials - User 1 calls /api/connect/user and it returns "user 1" - User 2 opens webapplication and does not have to provide any credentials - User 2 calls /api/connect/user and it still returns "user 1"会发生什么- 用户 1 通过填写他的凭据登录(使用隐身模式) - 用户 1 调用 /api/connect/user 并返回“用户 1” - 用户 2 打开 Web 应用程序并且不必提供任何凭据 - 用户 2调用 /api/connect/user仍然返回“user 1”

Question: How do i prevent my asp.net core application returning the wrong windows authentication user?问题:如何防止我的 asp.net 核心应用程序返回错误的 windows 身份验证用户?

I managed to make it work using traefik TLS passthrough.我设法使用 traefik TLS passthrough 使其工作。 So I had to change the application to serve https itself instead of having traefik do SSL termination.所以我不得不改变应用程序来服务 https 本身,而不是让 traefik 做 SSL 终止。 My application's compose file now looks like this:我的应用程序的撰写文件现在如下所示:

docker-compose.yml docker-compose.yml

version: "3.7"
services:
  webapplication:
    image: <repository>/webapplication:8-1
    environment:
      - ASPNETCORE_Kestrel__Certificates__Default__Path=wildcard_certificate.pfx
    networks:
      webapplication-network:
        aliases:
          - webapplication
      traefik:      
        aliases:
          - traefik-webapplication
    credential_spec:  
      file: webapp({GMSA_ACCOUNT})_credential.json
    secrets:
      - source: config_secrets
        target: C:/app/appsettings.json
      - source: wildcard_certificate_pfx
        target: c:\certificates\wildcard_certificate.pfx
    deploy:
      mode: replicated
      replicas: 1
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 10
        window: 30s
      labels: 
        - applicatienaam=({APPLICATIENAAM})
        - "traefik.enable=true"
        - "traefik.http.routers.({APPLICATIENAAM})-webapplication.rule=Host(`({APPLICATIENAAM})-webapplication.({DOMAIN})`)"
        - "traefik.http.routers.({APPLICATIENAAM})-webapplication.entrypoints=https"
        - "traefik.http.routers.({APPLICATIENAAM})-webapplication.tls=true"
        - "traefik.http.services.({APPLICATIENAAM})-webapplication.loadbalancer.server.scheme=https"
        - "traefik.http.services.({APPLICATIENAAM})-webapplication.loadbalancer.server.port=443"

        # Windows authentication works through TCP
        # TLS passtrough, because otherwise windows authentication won't support multiple users
        - "traefik.tcp.routers.({APPLICATIENAAM})-webapplication.tls=true"
        - "traefik.tcp.routers.({APPLICATIENAAM})-webapplication.tls.options=default"
        - "traefik.tcp.routers.({APPLICATIENAAM})-webapplication.tls.passthrough=true"
        - "traefik.tcp.routers.({APPLICATIENAAM})-webapplication.rule=HostSNI(`({APPLICATIENAAM})-webapplication.({DOMAIN})`)"
        - "traefik.tcp.routers.({APPLICATIENAAM})-webapplication.entrypoints=https"
        - "traefik.tcp.services.({APPLICATIENAAM})-webapplication.loadbalancer.server.port=443"

I think the first user that logs in is bound to the traefik connection, so all next users will use the first users session, but I don't know for sure.我认为第一个登录的用户绑定到traefik连接,所以所有下一个用户将使用第一个用户session,但我不确定。 All I know is that the solution above prevents mixing up user sessions.我所知道的是,上面的解决方案可以防止混淆用户会话。

I also had to make a change to my dockerfile to make serving https from the container work, because of a WindowsCryptographicException bug .由于WindowsCryptographicException 错误,我还必须更改我的 dockerfile 以使从容器工作的 https 工作。

# escape=`
##### Runtime #####
ARG baseImageVersie
ARG buildNumber
ARG release
FROM <repository>/webapplication-build:$release-$buildNumber AS buildtools
FROM webapplication-windows-netcore-base:$baseImageVersie 
ENV DOTNET_RUNNING_IN_CONTAINER=true

# The copy is done, because wildcard_certificate.pfx is put into the container using docker secrets, which makes it a symlink. 
# Reading a certificate as a symlink is not supported at this moment: https://stackoverflow.com/q/43955181/1608705
# After doing a copy, the copied version is not a symlink anymore.
ENTRYPOINT (IF EXIST "c:\certificates\wildcard_certificate.pfx" (copy c:\certificates\wildcard_certificate.pfx c:\app\wildcard_certificate.pfx)) && dotnet webapplication.dll

COPY --from=buildtools C:/publish .

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

相关问题 ASP.NET vNext Kestrel + Windows身份验证 - ASP.NET vNext Kestrel + windows authentication 在 Windows 身份验证的 ASP.Net 5 中使用 IIS Express/Kestrel 时,User.IsInRole 始终为 false - User.IsInRole is always false when using IIS Express / Kestrel in ASP.Net 5 with Windows Authentication Kestrel on https with asp.net core 1.0 - Kestrel on https with asp.net core 1.0 记录asp.net core / kestrel中的异常 - Logging exceptions in asp.net core / kestrel 使用没有ASP.NET核心的Kestrel - Using Kestrel without ASP.NET core ASP.Net Core:保持Windows身份验证 - ASP.Net Core: keep windows authentication 使用 Windows 身份验证的 ASP.NET Core 标识 - ASP.NET Core Identity with Windows Authentication OnCertificateValidated 未运行 - 自签名证书客户端身份验证 - ASP.NET Core 和 Kestrel - OnCertificateValidated not running - Self-Signed Certificate Client Authentication - ASP.NET Core and Kestrel 在 Linux Docker 中查询 Asp.net Core/Kestrel 中的布尔属性的 Firestore 崩溃 - Querying Firestore for Boolean property in Asp.net Core/Kestrel Crashes in Linux Docker 当Kestrel收到请求时,无法停止asp.net核心Windows服务 - Unable to stop asp.net core Windows Service when Kestrel receives requests
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM