artdolya
artdolya

Reputation: 39

Load Balancer "Invalid HTTP request for token endpoint"

I have an issue with a IdentityServer behind a load balancer,
Just to be clear if I'm using direct ips, evertything works as expected.

Currently I have an SSL configuration on LB with a valid certificate that redirects to a HTTP docker-engines hosted on 2 Linux machines.

I'm using an MVC hybrid flow on my Client:

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
    AuthenticationScheme = "oidc",
    SignInScheme = "Cookies",
    Authority = settings.Server,
    RequireHttpsMetadata = "false",
    ClientId = "MyMvcClient",
    ClientSecret = "MyMvcSuperPassword",
    ResponseType =  "code id_token",
    GetClaimsFromUserInfoEndpoint = true,
    SaveTokens = true,
    TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = JwtClaimTypes.Name,
        RoleClaimType = JwtClaimTypes.Role,
    },
    Events = new OpenIdConnectEvents()
    {
        OnRemoteFailure = context =>
        {
            context.Response.Redirect("/error");
            context.HandleResponse();
            return Task.FromResult(0);
        }
    },
    "Scope": { "openid", "profile", "email", "myclient", "offline_access" }
});

On the server side, I have the following setup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<IdentityDbContext>(builder);
    services.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddEntityFrameworkStores<IdentityDbContext, Guid>()
        .AddUserStore<UserStore<ApplicationUser, ApplicationRole, IdentityDbContext, Guid>>()
        .AddRoleStore<RoleStore<ApplicationRole, IdentityDbContext, Guid>>()
        .AddUserManager<LdapUserManager>()
        .AddSignInManager<LdapSignInManager>()
        .AddDefaultTokenProviders()
        .AddIdentityServerUserClaimsPrincipalFactory();
    ...
    string redisSettings = $"{redisHost}:{redisPort},ssl={redisSsl},abortConnect={redisAbortConnect},password={redisPassword}";
    services.AddDataProtection().PersistKeysToRedis(redis, redisKey);
    ...
    // Adds IdentityServer
    services.AddIdentityServer()
        .AddSigningCredential(new X509Certificate2("IdentityServerAuth.pfx"))
        .AddConfigurationStore(builder)
        .AddOperationalStore(builder)
        .AddAspNetIdentity<ApplicationUser>()
        .AddProfileService<IdentityProfileService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
    app.UseIdentity();
    app.UseForwardedHeaders(new ForwardedHeadersOptions
    {
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
    });
    // Adds IdentityServer
    app.UseIdentityServer();
}

As I already mentioned, it works for configuration without Load balancer, but client fails with error "Message contains error: 'invalid_request', error_description: 'error_description is null', error_uri: 'error_uri is null'."

And on the server side I'm receiving info: IdentityServer4.Hosting.IdentityServerMiddleware[0] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.TokenEndpoint for /connect/token warn: IdentityServer4.Endpoints.TokenEndpoint[0] Invalid HTTP request for token endpoint

Upvotes: 1

Views: 1206

Answers (1)

artdolya
artdolya

Reputation: 39

I have solved the problem. The solution was found tracing the Request.HttpContext.Connection.RemoteIpAddress It was invalid, and was equal to IP of the Load balancer. So the solution was to add the Ip using:

options.KnownProxies.Clear();
options.KnownProxies.Add(IPAddress.Parse("LoadBalancer IP"));
app.UseForwardedHeaders(options);

or by mask e.g. 192.168.1.0/8:

options.KnownNetworks.Clear();
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.1.0"), 8));
app.UseForwardedHeaders(options);

In this case the IP of Client will be passed to Identity server and you won't receive exception:

Invalid HTTP request for token endpoint

Upvotes: 1

Related Questions