Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WindowsIdentity.RunImpersonated sending wrong credentials #58033

Closed
daniilzaonegin opened this issue Aug 24, 2021 · 33 comments · Fixed by #58922
Closed

WindowsIdentity.RunImpersonated sending wrong credentials #58033

daniilzaonegin opened this issue Aug 24, 2021 · 33 comments · Fixed by #58922
Assignees
Milestone

Comments

@daniilzaonegin
Copy link

Hi all!

I'm experiencing the problem described in issue #38414.

I have a ASP.NET Core app with a Middleware, that authenticate user via windows authentication and runs under his account an http-request to get a jwt-token.

Startup.cs

 public class Startup
    {
      //...
      //omitted for brevity
      //...
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDistributedMemoryCache();
            services.AddSession(conf => conf.Cookie.MaxAge = TimeSpan.FromMinutes(30));
            services.AddAuthentication(IISDefaults.AuthenticationScheme).AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.Authority = _configuration.GetValue<string>("IdentityServer");
                options.SupportedTokens = SupportedTokens.Both;
                options.ApiSecret = _configuration.GetValue<string>("ClientSecret");
                options.RequireHttpsMetadata = false;
            });
            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new SocketsHttpHandler()
                    {
                        UseProxy = false,
                        Credentials = CredentialCache.DefaultCredentials
                    });

            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders =
                    ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;

                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });
          //...
          //omitted for brevity
          //...
        }
      
       public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseSession();
            
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseForwardedHeaders();
            app.Use(async (context, next) =>
            {
                string ip = context.Connection.RemoteIpAddress.ToString();
                context.Request.Headers[ForwardedIpToken] = ip;
                await next.Invoke();
            });
            app.UseMiddleware<WinTokenMiddleware>();
            app.UseOcelot().Wait();
        }

      //...
      //omitted for brevity
      //...
}

WinTokenMiddleware.cs

   [SupportedOSPlatform("windows")]
    public class WinTokenMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IConfiguration _configuration;
        private readonly IHttpClientFactory _httpClientFactory;
        private static readonly ILogger Logger = Log.ForContext<WinTokenMiddleware>();
        private const string TokenSessionKey = "AuthToken";

        public WinTokenMiddleware(RequestDelegate next, IConfiguration configuration, IHttpClientFactory httpClientFactory)
        {
            _next = next;
            _configuration = configuration;
            _httpClientFactory = httpClientFactory;
        }

        // ReSharper disable once UnusedMember.Global
        public async Task InvokeAsync(HttpContext context)
        {
           //...
           //... omitted for brevity
           //...
                AuthenticateResult winAuthenticateResult = await context.AuthenticateAsync(IISServerDefaults.AuthenticationScheme);
                if (!winAuthenticateResult.Succeeded)
                {
                    await context.ChallengeAsync(IISDefaults.AuthenticationScheme);
                    return;
                }

                if (!(winAuthenticateResult?.Principal?.Identity is WindowsIdentity windowsIdentity))
                {
                    Logger.Warning("Couldn't get user windows account!'");
                    await WriteErrorResponse(context,
                        "Couldn't get user windows account! Please enable windows authentication on server.");
                    return;
                }
           //...
           //... omitted for brevity
           //...
                TokenResponse tokenResponse = await WindowsIdentity.RunImpersonated(
                        windowsIdentity.AccessToken,
                        () =>
                        {
                            Logger.Debug($"Current user {WindowsIdentity.GetCurrent().Name}");
                            HttpClient impersonatedClient = _httpClientFactory.CreateClient(ServiceConsts.ImpersonatedHttpClientName);

                            //получаем токен под пользователем
                            return impersonatedClient.RequestTokenAsync(new TokenRequest()
                            {
                                Address = disco.TokenEndpoint,

                                ClientId = _configuration.GetValue<string>("ClientId"),
                                ClientSecret = _configuration.GetValue<string>("ClientSecret"),
                                GrantType = "windows"

                            });
                        });
//...
//... omitted for brevity
//...
        }
}

The Code above gets jwt-Token authenticated under user account with windows authentication.
When we deploy application, we see that users get tokens of other users. For example, if user A gets authenticated correctly and received his token, and few seconds later comes user B, he gets authenticated by user A and therefore gets the wrong token.

If I set PooledConnectionLifetime to TimeSpan.Zero, it works as expected

            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new SocketsHttpHandler()
                    {
                        UseProxy = false,
                        Credentials = CredentialCache.DefaultCredentials,
                        PreAuthenticate = false,
                        PooledConnectionLifetime = TimeSpan.Zero
                    });

The service is running on net5.0 on windows server 2016, IIS 10.

Is this a bug or am I doing it the wrong way?

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@jeffschwMSFT jeffschwMSFT transferred this issue from dotnet/runtime Aug 24, 2021
@Tratcher
Copy link
Member

await WindowsIdentity.RunImpersonated(

This is a bit of a trap. RunImpersonated Takes a Func<T> and reverts the impersonation when the Func exits. You're returning a Task and waiting for the task outside of the impersonation. That can end up reverting the impersonation in the middle of the operation.

.NET 5 added RunImersonatedAsync to mitigate this issue. Try that and see if it helps.
https://docs.microsoft.com/en-us/dotnet/api/system.security.principal.windowsidentity.runimpersonatedasync?view=net-5.0

@Tratcher
Copy link
Member

For example, if user A gets authenticated correctly and received his token, and few seconds later comes user B, he gets authenticated by user A and therefore gets the wrong token.

This sounds like HttpClient failing to account for the impersonation context when selecting pooled connections. Transferring back to runtime for followup.

@Tratcher Tratcher transferred this issue from dotnet/aspnetcore Aug 24, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Aug 24, 2021
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost
Copy link

ghost commented Aug 24, 2021

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Hi all!

I'm experiencing the problem described in issue #38414.

I have a ASP.NET Core app with a Middleware, that authenticate user via windows authentication and runs under his account an http-request to get a jwt-token.

Startup.cs

 public class Startup
    {
      //...
      //omitted for brevity
      //...
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDistributedMemoryCache();
            services.AddSession(conf => conf.Cookie.MaxAge = TimeSpan.FromMinutes(30));
            services.AddAuthentication(IISDefaults.AuthenticationScheme).AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.Authority = _configuration.GetValue<string>("IdentityServer");
                options.SupportedTokens = SupportedTokens.Both;
                options.ApiSecret = _configuration.GetValue<string>("ClientSecret");
                options.RequireHttpsMetadata = false;
            });
            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new SocketsHttpHandler()
                    {
                        UseProxy = false,
                        Credentials = CredentialCache.DefaultCredentials
                    });

            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders =
                    ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;

                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });
          //...
          //omitted for brevity
          //...
        }
      
       public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseSession();
            
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseForwardedHeaders();
            app.Use(async (context, next) =>
            {
                string ip = context.Connection.RemoteIpAddress.ToString();
                context.Request.Headers[ForwardedIpToken] = ip;
                await next.Invoke();
            });
            app.UseMiddleware<WinTokenMiddleware>();
            app.UseOcelot().Wait();
        }

      //...
      //omitted for brevity
      //...
}

WinTokenMiddleware.cs

   [SupportedOSPlatform("windows")]
    public class WinTokenMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IConfiguration _configuration;
        private readonly IHttpClientFactory _httpClientFactory;
        private static readonly ILogger Logger = Log.ForContext<WinTokenMiddleware>();
        private const string TokenSessionKey = "AuthToken";

        public WinTokenMiddleware(RequestDelegate next, IConfiguration configuration, IHttpClientFactory httpClientFactory)
        {
            _next = next;
            _configuration = configuration;
            _httpClientFactory = httpClientFactory;
        }

        // ReSharper disable once UnusedMember.Global
        public async Task InvokeAsync(HttpContext context)
        {
           //...
           //... omitted for brevity
           //...
                AuthenticateResult winAuthenticateResult = await context.AuthenticateAsync(IISServerDefaults.AuthenticationScheme);
                if (!winAuthenticateResult.Succeeded)
                {
                    await context.ChallengeAsync(IISDefaults.AuthenticationScheme);
                    return;
                }

                if (!(winAuthenticateResult?.Principal?.Identity is WindowsIdentity windowsIdentity))
                {
                    Logger.Warning("Couldn't get user windows account!'");
                    await WriteErrorResponse(context,
                        "Couldn't get user windows account! Please enable windows authentication on server.");
                    return;
                }
           //...
           //... omitted for brevity
           //...
                TokenResponse tokenResponse = await WindowsIdentity.RunImpersonated(
                        windowsIdentity.AccessToken,
                        () =>
                        {
                            Logger.Debug($"Current user {WindowsIdentity.GetCurrent().Name}");
                            HttpClient impersonatedClient = _httpClientFactory.CreateClient(ServiceConsts.ImpersonatedHttpClientName);

                            //получаем токен под пользователем
                            return impersonatedClient.RequestTokenAsync(new TokenRequest()
                            {
                                Address = disco.TokenEndpoint,

                                ClientId = _configuration.GetValue<string>("ClientId"),
                                ClientSecret = _configuration.GetValue<string>("ClientSecret"),
                                GrantType = "windows"

                            });
                        });
//...
//... omitted for brevity
//...
        }
}

The Code above gets jwt-Token authenticated under user account with windows authentication.
When we deploy application, we see that users get tokens of other users. For example, if user A gets authenticated correctly and received his token, and few seconds later comes user B, he gets authenticated by user A and therefore gets the wrong token.

If I set PooledConnectionLifetime to TimeSpan.Zero, it works as expected

            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new SocketsHttpHandler()
                    {
                        UseProxy = false,
                        Credentials = CredentialCache.DefaultCredentials,
                        PreAuthenticate = false,
                        PooledConnectionLifetime = TimeSpan.Zero
                    });

The service is running on net5.0 on windows server 2016, IIS 10.

Is this a bug or am I doing it the wrong way?

Author: daniilzaonegin
Assignees: -
Labels:

area-System.Net.Http, untriaged

Milestone: -

@daniilzaonegin
Copy link
Author

Thanks for reply! But I've tried this

                TokenResponse tokenResponse = await WindowsIdentity.RunImpersonatedAsync(
                        windowsIdentity.AccessToken,
                        async () =>
                        {
                            Logger.Debug($"Current user {WindowsIdentity.GetCurrent().Name}");
                            HttpClient impersonatedClient = _httpClientFactory.CreateClient(ServiceConsts.ImpersonatedHttpClientName);

                            return await impersonatedClient.RequestTokenAsync(new TokenRequest()
                            {
                                Address = disco.TokenEndpoint,

                                ClientId = _configuration.GetValue<string>("ClientId"),
                                ClientSecret = _configuration.GetValue<string>("ClientSecret"),
                                GrantType = "windows"

                            });
                        });

Startup.cs

            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new SocketsHttpHandler()
                    {
                        UseProxy = false,
                        Credentials = CredentialCache.DefaultCredentials
                    });

Issue is still present. When I open page under first account I receive correct token, when I open page under different account after that, I receive token of previous user.

@Tratcher
Copy link
Member

Can you confirm the issue goes away if you create a new HttpClient instance for each call to RequestTokenAsync (without the factory) and dispose it afterwards? That should help confirm if it's a connection pooling issue.

@daniilzaonegin
Copy link
Author

Yes, issue goes away if I create a new HttpClient instance for each call to RequestTokenAsync. It also goes away when I set up HttpClient not to use connection pooling like this PooledConnectionLifetime = TimeSpan.Zero

            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new SocketsHttpHandler()
                    {
                        UseProxy = false,
                        Credentials = CredentialCache.DefaultCredentials,
                        PooledConnectionLifetime = TimeSpan.Zero
                    });

@daniilzaonegin
Copy link
Author

Just checked, this works

TokenResponse tokenResponse = await WindowsIdentity.RunImpersonatedAsync(
                        windowsIdentity.AccessToken,
                        async () =>
                        {
                            Logger.Debug($"Current user {WindowsIdentity.GetCurrent().Name}");
                            using HttpClient impersonatedClient = new HttpClient(new HttpClientHandler(){UseDefaultCredentials = true});

                            //получаем токен под пользователем
                            return await impersonatedClient.RequestTokenAsync(new TokenRequest()
                            {
                                Address = disco.TokenEndpoint,

                                ClientId = _configuration.GetValue<string>("ClientId"),
                                ClientSecret = _configuration.GetValue<string>("ClientSecret"),
                                GrantType = "windows"

                            });
                        });

But it isn't optimal solution, because it could lead to socket exhaustion.

@geoffkizer
Copy link
Contributor

We have code to handle this here: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs#L281

Sounds like something is broken somewhere, though...

@geoffkizer
Copy link
Contributor

@alnikola Can you take a look at this?

@geoffkizer
Copy link
Contributor

In particular, these two lines seem wrong: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs#L78

We only seem to set these properties in the constructor, so when the credentials are set this won't get updated properly.

@alnikola Does that seem right to you?

How do we test this functionality? Are there manual tests? When do we run them?

@karelz
Copy link
Member

karelz commented Aug 26, 2021

Triage: @alnikola does not have the context (discussed offline).
We need to investigate. This is not regression in 6.0, moving to 7.0.

@karelz karelz added this to the 7.0.0 milestone Aug 26, 2021
@karelz karelz removed the untriaged New issue has not been triaged by the area owner label Aug 26, 2021
@wfurt wfurt self-assigned this Sep 1, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Sep 10, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Sep 15, 2021
@karelz karelz modified the milestones: 7.0.0, 6.0.0 Sep 16, 2021
@karelz
Copy link
Member

karelz commented Sep 16, 2021

Fixed in 6.0 RC2 in PR #59155.
Fixed in 7.0 (main) in PR #58922.

@karelz
Copy link
Member

karelz commented Sep 30, 2021

@daniilzaonegin will you be able to validate that it solved your problem on 6.0 RC2 daily builds? Thanks!

@daniilzaonegin
Copy link
Author

@karelz, just installed VS2022 Pre on my desktop, I'll try to check if the problem is still there later today

@karelz
Copy link
Member

karelz commented Oct 1, 2021

@daniilzaonegin I don't think 6.0 RC2 is yet part of any VS install, you would need to install 6.0 RC2 daily build from https://github.com/dotnet/core/blob/main/daily-builds.md#future-releases (they are marked as 6.0 daily builds) as it is not officially released yet.

@daniilzaonegin
Copy link
Author

@karelz, ok, I'll install it, thank you!

@daniilzaonegin
Copy link
Author

daniilzaonegin commented Oct 2, 2021

Hello @karelz !
I have tried it on my machine, but the issue is still there.
What I did:

  1. I've downloaded the installer https://aka.ms/dotnet/6.0.1XX-rc2/daily/dotnet-sdk-win-x64.exe.
  2. Then I patched my project to dotnet 6;
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Ocelot" Version="17.0.0" />
    <PackageReference Include="Ocelot.Administration" Version="17.0.0" />
    <PackageReference Include="Serilog" Version="2.10.0" />
    <PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
    <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
    <PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
    <PackageReference Include="System.Security.Principal.Windows" Version="6.0.0-preview.5.21301.5" />
  </ItemGroup>

</Project>

When I run it using dotnet run , I get an error

2021-10-02 16:07:54.302 +03:00 [ERR] <18> Exception occured during WinToken generation.
System.InvalidOperationException: No authentication handler is registered for the scheme 'Windows'. The registered schemes are: BearerIdentityServerAuthenticationJwt, BearerIdentityServerAuthenticationIntrospection, Bearer. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Windows",...)?
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at ApiGateway.WinTokenMiddleware.InvokeAsync(HttpContext context) in C:\Users\ruazed1\repo\Source\dms.services.apigateway\ApiGateway\WinTokenMiddleware.cs:line 67       
[SupportedOSPlatform("windows")]
    public class WinTokenMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IConfiguration _configuration;
        private readonly IHttpClientFactory _httpClientFactory;
        private static readonly ILogger Logger = Log.ForContext<WinTokenMiddleware>();
        private const string TokenSessionKey = "AuthToken";

        public WinTokenMiddleware(RequestDelegate next, IConfiguration configuration, IHttpClientFactory httpClientFactory)
        {
            _next = next;
            _configuration = configuration;
            _httpClientFactory = httpClientFactory;
        }

        // ReSharper disable once UnusedMember.Global
        public async Task InvokeAsync(HttpContext context)
        {
            Logger.Information("User is not authenticated by jwt token. Authenticating user using windows authentication.");
            try
            {
                AuthenticateResult winAuthenticateResult = await context.AuthenticateAsync(IISServerDefaults.AuthenticationScheme);
                if (!winAuthenticateResult.Succeeded)
                {
                    await context.ChallengeAsync(IISDefaults.AuthenticationScheme); //<--The error happens here
                    return;
                }
           // ------ omitted for brevity ----------
        }
   }

And when I run it on IIS Express, the issue is still there.
May be I need to install a Hosting Bundle for this?

@karelz
Copy link
Member

karelz commented Nov 2, 2021

@daniilzaonegin it does seem like failure to set up a working test case, not sign that it is the same issue. Or am I reading it incorrectly?
I don't know how to set it up, I would expect you just repeat what you did previously with .NET 5.0.
Perhaps @Tratcher has some thoughts?

@wfurt
Copy link
Member

wfurt commented Nov 2, 2021

In essence, the old code would run as wrong user but it would not fail to run.

@daniilzaonegin
Copy link
Author

@karelz, maybe we better wait till dotnet 6 will be released? It is only one week left. Then I can definitely check it.

@karelz
Copy link
Member

karelz commented Nov 3, 2021

@daniilzaonegin that is fine with me. Would be great to have final confirmation that we truly addressed the end-to-end scenario, given that this is 2nd attempt to fix it.

@karelz
Copy link
Member

karelz commented Nov 9, 2021

@daniilzaonegin 6.0 is now GA. If you could check your scenario, that would be helpful for us. Thanks!

@daniilzaonegin
Copy link
Author

daniilzaonegin commented Nov 12, 2021

Hi @karelz! I tried to reproduce it today and the bug is still there.
I have installed on our widows server 2012 Hosting bundle https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-aspnetcore-6.0.0-windows-hosting-bundle-installer. Then installed our application there and tested it.
csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Ocelot" Version="17.0.0" />
    <PackageReference Include="Ocelot.Administration" Version="17.0.0" />
    <PackageReference Include="Serilog" Version="2.10.0" />
    <PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
    <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
    <PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
    <PackageReference Include="System.Security.Principal.Windows" Version="6.0.0-preview.5.21301.5" />
  </ItemGroup>

</Project>

Startup.cs:

using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.IISIntegration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Hosting;

    public class Startup
    {
        private readonly IConfiguration _configuration;
        private const string ForwardedIpToken = "X-Forwarded-For";

        public Startup(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDistributedMemoryCache();
            services.AddSession(conf => conf.Cookie.MaxAge = TimeSpan.FromMinutes(30));
            services.AddAuthentication(IISDefaults.AuthenticationScheme).AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.Authority = _configuration.GetValue<string>("IdentityServer");
                options.SupportedTokens = SupportedTokens.Both;
                options.ApiSecret = _configuration.GetValue<string>("ClientSecret");
                options.RequireHttpsMetadata = false;
            });

            services.AddHttpClient(ServiceConsts.IdentityHttpClientName,
                    c => c.Timeout = Timeout.InfiniteTimeSpan)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new HttpClientHandler()
                    {
                        UseProxy = false,
                        UseDefaultCredentials = true
                    });

            services.AddHttpClient(ServiceConsts.ImpersonatedHttpClientName)
                .ConfigurePrimaryHttpMessageHandler(_ =>
                    new HttpClientHandler()
                    {
                        UseProxy = false,
                        UseDefaultCredentials = true
                    });

            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders =
                    ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;

                // Включаем чтение Header от всех источников, вне зависимости от подсети
                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });

            services.AddOcelot();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseSession();
            
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseForwardedHeaders();
            app.Use(async (context, next) =>
            {
                string ip = context.Connection.RemoteIpAddress.ToString();
                //выставляем ip-адрес пользователя для сервисов-потребителей
                context.Request.Headers[ForwardedIpToken] = ip;
                await next.Invoke();
            });
            app.UseMiddleware<WinTokenMiddleware>();
            app.UseOcelot().Wait();
        }
    }

WinTokenMiddleware

    [SupportedOSPlatform("windows")]
    public class WinTokenMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IConfiguration _configuration;
        private readonly IHttpClientFactory _httpClientFactory;
        private static readonly ILogger Logger = Log.ForContext<WinTokenMiddleware>();
        private const string TokenSessionKey = "AuthToken";

        public WinTokenMiddleware(RequestDelegate next, IConfiguration configuration, IHttpClientFactory httpClientFactory)
        {
            _next = next;
            _configuration = configuration;
            _httpClientFactory = httpClientFactory;
        }

        // ReSharper disable once UnusedMember.Global
        public async Task InvokeAsync(HttpContext context)
        {
            if (context.Request.Method == "OPTIONS")
            {
                //OPTIONS requests not needed to be authorized
                await _next.Invoke(context);
                return;
            }
            //try to get token from session
            string sessionToken = context.Session.GetString(TokenSessionKey);

            if (sessionToken != null)
                UpdateOrAddAuthHeader(context, sessionToken);

            AuthenticateResult authResult =
                await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
            context.User = authResult.Principal;

            if (context.User.Identity.IsAuthenticated)
            {
                //jwt-token is ok, no need to get it
                Logger.Information($"Request is authorized by jwt token in it.");
                await _next.Invoke(context);
                return;
            }

            Logger.Information("User is not authenticated by jwt token. Authenticating user using windows authentication.");
            try
            {
                AuthenticateResult winAuthenticateResult = await context.AuthenticateAsync(IISServerDefaults.AuthenticationScheme);
                if (!winAuthenticateResult.Succeeded)
                {
                    //user is not authenticated by windows, making challenge request
                    await context.ChallengeAsync(IISDefaults.AuthenticationScheme);
                    return;
                }

                if (!(winAuthenticateResult?.Principal?.Identity is WindowsIdentity windowsIdentity))
                {
                    //user is not authenticated after challenge request - Error
                   //stop processing
                    Logger.Warning("Couldn't get user windows account!'");
                    await WriteErrorResponse(context,
                        "Couldn't get user windows account! Please enable windows authentication on server.");
                    return;
                }

                //user is successfully authenticated using windows auth.
                Logger.Debug($"Current windows user:'{WindowsIdentity.GetCurrent().Name}'");
                Logger.Information("Discovering token end point...");

                HttpClient httpClient =
                    _httpClientFactory.CreateClient(ServiceConsts.IdentityHttpClientName);

                DiscoveryDocumentResponse disco = await httpClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
                {
                    Address = _configuration.GetValue<string>("IdentityServer"),
                    Policy =
                                {
                                    RequireHttps = false
                                }
                });

                if (disco.IsError)
                {
                    //token end-point not found stop processing, we can't get jwt-token
                    Logger.Error($"Indentity server discovery error:{disco.Error}");
                    await WriteErrorResponse(context,
                        $"Indentity server discovery error:{disco.Error}");
                    return;
                }

                Logger.Information($"Token end point found '{disco.TokenEndpoint}'. Requesting token...");
               
                TokenResponse tokenResponse = await WindowsIdentity.RunImpersonated(
                        windowsIdentity.AccessToken,
                        () =>
                        {
                            Logger.Debug($"Current user {WindowsIdentity.GetCurrent().Name}");
                            HttpClient impersonatedClient = _httpClientFactory.CreateClient(ServiceConsts.ImpersonatedHttpClientName);

                            //making call of token-endpoint using user windows credentials
                            return impersonatedClient.RequestTokenAsync(new TokenRequest()
                            {
                                Address = disco.TokenEndpoint,

                                ClientId = _configuration.GetValue<string>("ClientId"),
                                ClientSecret = _configuration.GetValue<string>("ClientSecret"),
                                GrantType = "windows"

                            });
                        });

                if (tokenResponse.IsError)
                {
                    Logger.Warning($"Token getting error:{tokenResponse.Error}");
                    await WriteErrorResponse(context, $"Token getting error:{ tokenResponse.Error}");
                    return;
                }

                Logger.Information($"Got Token! Setting authorization header...");
                UpdateOrAddAuthHeader(context, tokenResponse.AccessToken);

                Logger.Information($"Storing Token to session for future use.");
                context.Session.SetString(TokenSessionKey, tokenResponse.AccessToken);

            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Exception occured during WinToken generation.");
                await WriteErrorResponse(context, "Exception occured during WinToken generation.");
                return;
            }

            await _next(context);
        }

        private static async Task WriteErrorResponse(HttpContext context, string message)
        {
            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            await context.Response.WriteAsync(message);
        }

        private void UpdateOrAddAuthHeader(HttpContext context, string token)
        {
            if (context.Request.Headers.ContainsKey("Authorization") &&
                !context.Request.Headers["Authorization"]
                                .Contains(JwtBearerDefaults.AuthenticationScheme, StringComparer.OrdinalIgnoreCase))
            {
                //we update the header only if it doesn't contain Jwt-token
                context.Request.Headers["Authorization"] =
                    JwtBearerDefaults.AuthenticationScheme + " " + token;
            }
            else
            {
                context.Request.Headers.Add("Authorization",
                    JwtBearerDefaults.AuthenticationScheme + " " + token);
            }
        }
    }
}

First call using credetials of account RAIFFEISEN\admzed1

1 	2021-11-12 21:30:46.424 +03:00 [DBG] <1> Hosting started
2 	2021-11-12 21:30:46.462 +03:00 [INF] <9> Request starting HTTP/1.1 GET <service_uri>/api/User - -
3 	2021-11-12 21:30:46.465 +03:00 [DBG] <9> Wildcard detected, all requests with hosts will be allowed.
4 	2021-11-12 21:30:46.510 +03:00 [DBG] <9> AuthenticationScheme: Bearer was not authenticated.
5 	2021-11-12 21:30:46.512 +03:00 [INF] <9> User is not authenticated by jwt token. Authenticating user using windows authentication.
6 	2021-11-12 21:30:46.530 +03:00 [INF] <9> Request finished HTTP/1.1 GET <service_uri>/api/User - - - 401 - - 71.4191ms
7 	2021-11-12 21:30:46.636 +03:00 [INF] <9> Request starting HTTP/1.1 GET <service_uri>/api/User - -
8 	2021-11-12 21:30:46.643 +03:00 [DBG] <9> AuthenticationScheme: Bearer was not authenticated.
9 	2021-11-12 21:30:46.643 +03:00 [INF] <9> User is not authenticated by jwt token. Authenticating user using windows authentication.
10	2021-11-12 21:30:46.651 +03:00 [DBG] <9> Current windows user:'RAIFFEISEN\srv-d-dms'
11	2021-11-12 21:30:46.651 +03:00 [INF] <9> Discovering token end point...
12	2021-11-12 21:30:46.683 +03:00 [INF] <9> Start processing HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration"
13	2021-11-12 21:30:46.686 +03:00 [INF] <9> Sending HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration"
14	2021-11-12 21:30:48.476 +03:00 [INF] <7> Received HTTP response headers after 1786.2055ms - 200
15	2021-11-12 21:30:48.478 +03:00 [INF] <7> End processing HTTP request after 1798.8238ms - 200
16	2021-11-12 21:30:48.504 +03:00 [INF] <7> Start processing HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration/jwks"
17	2021-11-12 21:30:48.504 +03:00 [INF] <7> Sending HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration/jwks"
18	2021-11-12 21:30:48.569 +03:00 [INF] <7> Received HTTP response headers after 64.2022ms - 200
19	2021-11-12 21:30:48.569 +03:00 [INF] <7> End processing HTTP request after 64.6888ms - 200
20	2021-11-12 21:30:48.582 +03:00 [INF] <7> Token end point found '<IdentityServer4_uri>/connect/token'. Requesting token...
21	2021-11-12 21:30:48.583 +03:00 [DBG] <7> Current user RAIFFEISEN\admzed1
22	2021-11-12 21:30:48.587 +03:00 [INF] <7> Start processing HTTP request POST "<IdentityServer4_uri>/connect/token"
23	2021-11-12 21:30:48.587 +03:00 [INF] <7> Sending HTTP request POST "<IdentityServer4_uri>/connect/token"
24	2021-11-12 21:30:48.852 +03:00 [INF] <7> Received HTTP response headers after 265.2413ms - 200
25	2021-11-12 21:30:48.852 +03:00 [INF] <7> End processing HTTP request after 265.6052ms - 200
26	2021-11-12 21:30:48.855 +03:00 [INF] <7> Got Token! Setting authorization header...
27	2021-11-12 21:30:48.855 +03:00 [INF] <7> Storing Token to session for future use.
28	2021-11-12 21:30:48.859 +03:00 [DBG] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: ocelot pipeline started
29	2021-11-12 21:30:48.862 +03:00 [DBG] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Upstream url path is /helios/api/User
30	2021-11-12 21:30:48.881 +03:00 [DBG] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: downstream templates are /{heliosPath}
31	2021-11-12 21:30:48.925 +03:00 [INF] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /{heliosPath}
32	2021-11-12 21:30:48.928 +03:00 [INF] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: No authentication needed for /helios/api/User
33	2021-11-12 21:30:48.930 +03:00 [INF] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: /{heliosPath} route does not require user to be authorized
34	2021-11-12 21:30:48.942 +03:00 [DBG] <7> requestId: 80002578-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Downstream url is http://localhost:6700/api/User

User is correct, see above on line 21.
One more time under different credentials, new login=RAIFFEISEN\ruazed1

1 	2021-11-12 21:31:01.471 +03:00 [INF] <18> Request starting HTTP/1.1 GET <service_uri>/api/User - -
2 	2021-11-12 21:31:01.472 +03:00 [DBG] <18> Session loaded; Key:9a4ee089-089e-ba7a-0d25-79efe5480597, Id:3babf1ab-1d1a-92ae-e0c9-417f80c517c7, Count:1
3 	2021-11-12 21:31:01.473 +03:00 [ERR] <18> Exception occurred while processing message.
4 	System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
5 	   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
6 	   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
7 	2021-11-12 21:31:01.473 +03:00 [ERR] <18> IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
8 	System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
9 	   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
10	   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
11	   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
12	   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
13	   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
14	   at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler.HandleAuthenticateAsync()
15	2021-11-12 21:31:01.474 +03:00 [INF] <18> Bearer was not authenticated. Failure message: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
16	2021-11-12 21:31:01.474 +03:00 [INF] <18> User is not authenticated by jwt token. Authenticating user using windows authentication.
17	2021-11-12 21:31:01.475 +03:00 [DBG] <18> Current windows user:'RAIFFEISEN\srv-d-dms'
18	2021-11-12 21:31:01.475 +03:00 [INF] <18> Discovering token end point...
19	2021-11-12 21:31:01.475 +03:00 [INF] <18> Start processing HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration"
20	2021-11-12 21:31:01.475 +03:00 [INF] <18> Sending HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration"
21	2021-11-12 21:31:01.481 +03:00 [INF] <6> Received HTTP response headers after 5.1084ms - 200
22	2021-11-12 21:31:01.481 +03:00 [INF] <6> End processing HTTP request after 5.3288ms - 200
23	2021-11-12 21:31:01.481 +03:00 [INF] <6> Start processing HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration/jwks"
24	2021-11-12 21:31:01.481 +03:00 [INF] <6> Sending HTTP request GET "<IdentityServer4_uri>/.well-known/openid-configuration/jwks"
25	2021-11-12 21:31:01.483 +03:00 [INF] <6> Received HTTP response headers after 1.9606ms - 200
26	2021-11-12 21:31:01.483 +03:00 [INF] <6> End processing HTTP request after 2.1157ms - 200
27	2021-11-12 21:31:01.483 +03:00 [INF] <6> Token end point found '<IdentityServer4_uri>/connect/token'. Requesting token...
28	2021-11-12 21:31:01.484 +03:00 [DBG] <6> Current user RAIFFEISEN\admzed1
29	2021-11-12 21:31:01.484 +03:00 [INF] <6> Start processing HTTP request POST "<IdentityServer4_uri>/connect/token"
30	2021-11-12 21:31:01.484 +03:00 [INF] <6> Sending HTTP request POST "<IdentityServer4_uri>/connect/token"
31	2021-11-12 21:31:01.501 +03:00 [INF] <6> Received HTTP response headers after 16.8754ms - 200
32	2021-11-12 21:31:01.501 +03:00 [INF] <6> End processing HTTP request after 17.0766ms - 200
33	2021-11-12 21:31:01.501 +03:00 [INF] <6> Got Token! Setting authorization header...
34	2021-11-12 21:31:01.501 +03:00 [INF] <6> Storing Token to session for future use.
35	2021-11-12 21:31:01.501 +03:00 [DBG] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: ocelot pipeline started
36	2021-11-12 21:31:01.501 +03:00 [DBG] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Upstream url path is /helios/api/User
37	2021-11-12 21:31:01.502 +03:00 [DBG] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: downstream templates are /{heliosPath}
38	2021-11-12 21:31:01.502 +03:00 [INF] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /{heliosPath}
39	2021-11-12 21:31:01.502 +03:00 [INF] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: No authentication needed for /helios/api/User
40	2021-11-12 21:31:01.502 +03:00 [INF] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: /{heliosPath} route does not require user to be authorized
41	2021-11-12 21:31:01.502 +03:00 [DBG] <6> requestId: 80002579-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Downstream url is http://localhost:6700/api/User

User is incorrect. See above line 28.

@Tratcher
Copy link
Member

Note you should be using the new RunInpersonatedAsync API so the impersonation isn't reverted before the async operation completes.

@daniilzaonegin
Copy link
Author

Ok, I will try it! Thanks

@daniilzaonegin
Copy link
Author

daniilzaonegin commented Nov 12, 2021

Hi, @Tratcher!

I changed the code of WinTokenMiddleware and called RunImpersonatedAsync method

                TokenResponse tokenResponse = await WindowsIdentity.RunImpersonatedAsync(
                        windowsIdentity.AccessToken,
                        () =>
                        {
                            Logger.Debug($"Current user {WindowsIdentity.GetCurrent().Name}");
                            HttpClient impersonatedClient = _httpClientFactory.CreateClient(ServiceConsts.ImpersonatedHttpClientName);

                            //получаем токен под пользователем
                            return impersonatedClient.RequestTokenAsync(new TokenRequest()
                            {
                                Address = disco.TokenEndpoint,

                                ClientId = _configuration.GetValue<string>("ClientId"),
                                ClientSecret = _configuration.GetValue<string>("ClientSecret"),
                                GrantType = "windows"

                            });
                        });

But the issue is still there.

First call under user RAIFFEISEN\ruazed1. Line 23 correct login:

1 	2021-11-12 21:53:56.979 +03:00 [DBG] <1> Hosting started
2 	2021-11-12 21:53:57.015 +03:00 [INF] <9> Request starting HTTP/1.1 GET <service_uri>/api/User - -
3 	2021-11-12 21:53:57.017 +03:00 [DBG] <9> Wildcard detected, all requests with hosts will be allowed.
4 	2021-11-12 21:53:57.054 +03:00 [INF] <9> Accessing expired session, Key:9a4ee089-089e-ba7a-0d25-79efe5480597
5 	2021-11-12 21:53:57.067 +03:00 [DBG] <9> AuthenticationScheme: Bearer was not authenticated.
6 	2021-11-12 21:53:57.069 +03:00 [INF] <9> User is not authenticated by jwt token. Authenticating user using windows authentication.
7 	2021-11-12 21:53:57.092 +03:00 [INF] <9> Request finished HTTP/1.1 GET <service_uri>/api/User - - - 401 - - 80.5112ms
8 	2021-11-12 21:53:57.192 +03:00 [INF] <9> Request starting HTTP/1.1 GET <service_uri>/api/User - -
9 	2021-11-12 21:53:57.197 +03:00 [INF] <9> Accessing expired session, Key:9a4ee089-089e-ba7a-0d25-79efe5480597
10	2021-11-12 21:53:57.197 +03:00 [DBG] <9> AuthenticationScheme: Bearer was not authenticated.
11	2021-11-12 21:53:57.198 +03:00 [INF] <9> User is not authenticated by jwt token. Authenticating user using windows authentication.
12	2021-11-12 21:53:57.204 +03:00 [DBG] <9> Current windows user:'RAIFFEISEN\srv-d-dms'
13	2021-11-12 21:53:57.204 +03:00 [INF] <9> Discovering token end point...
14	2021-11-12 21:53:57.233 +03:00 [INF] <9> Start processing HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration"
15	2021-11-12 21:53:57.236 +03:00 [INF] <9> Sending HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration"
16	2021-11-12 21:53:58.913 +03:00 [INF] <7> Received HTTP response headers after 1673.0108ms - 200
17	2021-11-12 21:53:58.915 +03:00 [INF] <7> End processing HTTP request after 1686.7312ms - 200
18	2021-11-12 21:53:58.940 +03:00 [INF] <7> Start processing HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration/jwks"
19	2021-11-12 21:53:58.940 +03:00 [INF] <7> Sending HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration/jwks"
20	2021-11-12 21:53:59.004 +03:00 [INF] <7> Received HTTP response headers after 63.9827ms - 200
21	2021-11-12 21:53:59.004 +03:00 [INF] <7> End processing HTTP request after 64.3829ms - 200
22	2021-11-12 21:53:59.016 +03:00 [INF] <7> Token end point found '<IdentityServer4_uri>connect/token'. Requesting token...
23	2021-11-12 21:53:59.018 +03:00 [DBG] <7> Current user RAIFFEISEN\ruazed1
24	2021-11-12 21:53:59.021 +03:00 [INF] <7> Start processing HTTP request POST "<IdentityServer4_uri>connect/token"
25	2021-11-12 21:53:59.021 +03:00 [INF] <7> Sending HTTP request POST "<IdentityServer4_uri>connect/token"
26	2021-11-12 21:53:59.297 +03:00 [INF] <7> Received HTTP response headers after 275.6388ms - 200
27	2021-11-12 21:53:59.297 +03:00 [INF] <7> End processing HTTP request after 275.9566ms - 200
28	2021-11-12 21:53:59.300 +03:00 [INF] <7> Got Token! Setting authorization header...
29	2021-11-12 21:53:59.300 +03:00 [INF] <7> Storing Token to session for future use.
30	2021-11-12 21:53:59.303 +03:00 [DBG] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: ocelot pipeline started
31	2021-11-12 21:53:59.306 +03:00 [DBG] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Upstream url path is /helios/api/User
32	2021-11-12 21:53:59.325 +03:00 [DBG] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: downstream templates are /{heliosPath}
33	2021-11-12 21:53:59.366 +03:00 [INF] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /{heliosPath}
34	2021-11-12 21:53:59.368 +03:00 [INF] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: No authentication needed for /helios/api/User
35	2021-11-12 21:53:59.371 +03:00 [INF] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: /{heliosPath} route does not require user to be authorized
36	2021-11-12 21:53:59.383 +03:00 [DBG] <7> requestId: 8000260a-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Downstream url is http://localhost:6700/api/User

First call under user RAIFFEISEN\admzed1. Line 28 incorrect login:

1 	2021-11-12 21:54:14.008 +03:00 [INF] <9> Request starting HTTP/1.1 GET <service_uri>/api/User - -
2 	2021-11-12 21:54:14.008 +03:00 [DBG] <9> Session loaded; Key:9a4ee089-089e-ba7a-0d25-79efe5480597, Id:b5adf28a-7b04-23ec-9815-14eda865b0c0, Count:1
3 	2021-11-12 21:54:14.009 +03:00 [ERR] <9> Exception occurred while processing message.
4 	System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
5 	   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
6 	   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
7 	2021-11-12 21:54:14.009 +03:00 [ERR] <9> IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
8 	System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
9 	   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
10	   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
11	   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
12	   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
13	   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
14	   at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler.HandleAuthenticateAsync()
15	2021-11-12 21:54:14.010 +03:00 [INF] <9> Bearer was not authenticated. Failure message: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
16	2021-11-12 21:54:14.010 +03:00 [INF] <9> User is not authenticated by jwt token. Authenticating user using windows authentication.
17	2021-11-12 21:54:14.010 +03:00 [DBG] <9> Current windows user:'RAIFFEISEN\srv-d-dms'
18	2021-11-12 21:54:14.010 +03:00 [INF] <9> Discovering token end point...
19	2021-11-12 21:54:14.011 +03:00 [INF] <9> Start processing HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration"
20	2021-11-12 21:54:14.011 +03:00 [INF] <9> Sending HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration"
21	2021-11-12 21:54:14.018 +03:00 [INF] <3> Received HTTP response headers after 7.0588ms - 200
22	2021-11-12 21:54:14.018 +03:00 [INF] <3> End processing HTTP request after 7.3104ms - 200
23	2021-11-12 21:54:14.018 +03:00 [INF] <3> Start processing HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration/jwks"
24	2021-11-12 21:54:14.018 +03:00 [INF] <3> Sending HTTP request GET "<IdentityServer4_uri>.well-known/openid-configuration/jwks"
25	2021-11-12 21:54:14.021 +03:00 [INF] <3> Received HTTP response headers after 2.3399ms - 200
26	2021-11-12 21:54:14.021 +03:00 [INF] <3> End processing HTTP request after 2.5501ms - 200
27	2021-11-12 21:54:14.021 +03:00 [INF] <3> Token end point found '<IdentityServer4_uri>connect/token'. Requesting token...
28	2021-11-12 21:54:14.021 +03:00 [DBG] <3> Current user RAIFFEISEN\ruazed1
29	2021-11-12 21:54:14.022 +03:00 [INF] <3> Start processing HTTP request POST "<IdentityServer4_uri>connect/token"
30	2021-11-12 21:54:14.022 +03:00 [INF] <3> Sending HTTP request POST "<IdentityServer4_uri>connect/token"
31	2021-11-12 21:54:14.061 +03:00 [INF] <3> Received HTTP response headers after 39.1561ms - 200
32	2021-11-12 21:54:14.061 +03:00 [INF] <3> End processing HTTP request after 39.3876ms - 200
33	2021-11-12 21:54:14.061 +03:00 [INF] <3> Got Token! Setting authorization header...
34	2021-11-12 21:54:14.061 +03:00 [INF] <3> Storing Token to session for future use.
35	2021-11-12 21:54:14.061 +03:00 [DBG] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: ocelot pipeline started
36	2021-11-12 21:54:14.061 +03:00 [DBG] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Upstream url path is /helios/api/User
37	2021-11-12 21:54:14.062 +03:00 [DBG] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: downstream templates are /{heliosPath}
38	2021-11-12 21:54:14.062 +03:00 [INF] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /{heliosPath}
39	2021-11-12 21:54:14.062 +03:00 [INF] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: No authentication needed for /helios/api/User
40	2021-11-12 21:54:14.062 +03:00 [INF] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: /{heliosPath} route does not require user to be authorized
41	2021-11-12 21:54:14.062 +03:00 [DBG] <3> requestId: 8000260b-0001-f400-b63f-84710c7967bb, previousRequestId: no previous request id, message: Downstream url is http://localhost:6700/api/User

@daniilzaonegin
Copy link
Author

I don't know, maybe there an error in my code somewhere?

@daniilzaonegin
Copy link
Author

@karelz , I've checked my scenario on dotnet 6.

@karelz
Copy link
Member

karelz commented Nov 23, 2021

Thanks @daniilzaonegin! Would you mind opening a new bug -- and referencing this one?
We need to try to narrow down your scenario to minimal repro (if you can help with removing unnecessary parts on your side that would be great) and then look into it deeper.

@daniilzaonegin
Copy link
Author

Ok, I'll do it in one or two days. I'll try to create a minimal solution to check it.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 24, 2021
@karelz
Copy link
Member

karelz commented Jan 4, 2022

To close the loop: It works as expected after all - see new issue discussion: #63136 (comment)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants