I am working on a WebDAV service, i.e. it is an ASP.NET application, but without routing or endpoints.
So far I have used Http.sys as server, where you could use Basic, NTLM and Negotiate as authentication methods at the same time. This means that users could log in with Windows authentication (NTLM, Negotiate) or with Basic Authentication as required.
This worked well so far. In the case of an incorrectly authenticated request, the response was 401 Unauthorized and contained the following headers:
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
WWW-Authenticate: Basic
However, there is now a requirement that Basic Authentication should contain a realm, which should also be returned in the WWW-Authenticate header:
WWW-Authenticate: Basic realm="MyRealm"
I couldn't get it to work with Http.sys.
That's why I'm currently evaluating Kestrel.
But there I have the problem that I can't manage to make both Basic and Negotiate available.
If I first register Negotiate in the Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication("Negotiate")
.AddNegotiate()
.AddBasic(options =>
{
options.Realm = "MyReallyRealm";
options.SuppressWWWAuthenticateHeader = false;
options.Events = new BasicAuthenticationEvents
{
OnValidateCredentials = ValidateCredentials
};
});
...
}
then Windows Authentication works (WebDAV access via Explorer), but Basic Authentication does not work. I.e. the handler for Basic Authentication is not called at all. I have tried this with a self-written BasicAuthenticationHandler and with idunno.Authentication.Basic.
If I reverse the order in ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication("Basic")
.AddBasic(options =>
{
options.Realm = "MyReallyRealm";
options.SuppressWWWAuthenticateHeader = false;
options.Events = new BasicAuthenticationEvents
{
OnValidateCredentials = ValidateCredentials
}
.AddNegotiate();
});
...
}
Then only Basic Authentication works, but Negotiate does not.
And yes, Authentication has been added to the middleware pipeline:
public void Configure(IApplictionBuilder app, ...)
{
...
app.UseAuthentication();
}
And even with the variants that "worked", only one WWW-Authenticate header was ever returned in the event of an incorrect login, and it always contained the scheme that was specified as the default scheme in AddAuthentication().
How do I have to configure the whole thing so that both Negotiate and Basic Authentication are supported at the same time and so that multiple WWW-Authenticate headers are returned in the event of an error (401)?