-
Notifications
You must be signed in to change notification settings - Fork 1.6k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
AuthenticationHandler<TOptions>.ChallengeAsync isn't called #1144
Comments
Hi @horato. I think that ChallengeAsync is typically used when interactive authentication needs to happen for the user. This is not a typical scenario for API's. Perhaps you could explain a little bit more about what you're trying to do so we can help you out? |
Hi, From what I read online, the ChallengeAsync method is to be used to alter HTTP response and to generate WWW-Authenticate header. |
Could you share your Program.cs, Startup.cs and configuration? Maybe I can figure out what's going wrong. |
Here is a quick and dirty sample that seems to ilustrate my issue. If you call GET on http://localhost:10000/gateway/test you will end up in NtlmAuthHandler.HandleAuthenticateAsync, which fails auth. Code in HandleChallengeAsync doesn't get called and the response is plain 401 without any additional data. protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
HandleChallengeAsync(null);
return Task.FromResult(AuthenticateResult.Fail("failed"));
} Then it works as expected: One request is sent without auth, server responds with 401 and WWW-Authenticate NTLM and then second request is sent which contains the auth. Nugets: using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Security.Authentication;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using AuthenticationSchemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes;
namespace ConsoleApp2
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, configurationBuilder) => configurationBuilder.AddConfiguration(new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddEnvironmentVariables().Build()))
.ConfigureLogging(x => x.AddConsole())
.UseUrls("http://localhost:10000")
.UseStartup<Startup>()
.UseHttpSys(x =>
{
x.Authentication.AllowAnonymous = true;
x.Authentication.Schemes = AuthenticationSchemes.None;
})
.Build();
host.StartAsync();
Console.ReadLine();
host.StopAsync().Wait();
}
}
public class Startup
{
private const string OcelotConfigPath = "ConsoleApp2.ocelot.json";
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(OcelotConfigPath, optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddScheme<NtlmAuthOptions, NtlmAuthHandler>("Windows", _ => { });
services.AddCors();
services.AddMvc(x => x.EnableEndpointRouting = false).PartManager.ApplicationParts.Add(new AppPart());
services.AddOcelot(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseMvc();
app.UseOcelot().Wait();
}
}
public class AppPart : ApplicationPart, IApplicationPartTypeProvider
{
public override string Name => "AppPart";
public IEnumerable<TypeInfo> Types => new[] { typeof(TestController).GetTypeInfo() };
}
[Route("test")]
[ApiController]
public class TestController : Controller
{
[HttpGet]
[ProducesResponseType(typeof(void), (int)HttpStatusCode.OK)]
public IActionResult BasicHealthCheck()
{
return Ok();
}
}
public class NtlmAuthHandler : AuthenticationHandler<NtlmAuthOptions>
{
public NtlmAuthHandler(IOptionsMonitor<NtlmAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.Fail("failed"));
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
return Task.Run(() =>
{
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
Response.Headers.Add(HeaderNames.WWWAuthenticate, "NTLM");
});
}
}
public class NtlmAuthOptions : AuthenticationSchemeOptions
{
}
} Thank you |
Any luck with getting windows auth working with http.sys? I've been trying but not had much success. Is there somewhere with a quick example on how to get this working? |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
I am not entierly sure how to fill the issue template, I am sorry.
Is there any reason why AuthenticationHandler.ChallengeAsync doesn't get called when auth fails? Is this by design or am I doing something wrong? Is this implemented?
Thank you
The text was updated successfully, but these errors were encountered: