Scenario:

I ended up with this scenario after using IIS Express which worked fine to produce a Windows Identity object. Switching to Kestrel (on Windows) I got the result above.
There are two problems here:
[Authorize]After a Twitter discussion with Damien and Barry it turns out that this specific scenario was caused by a specific middleware order, but only on Kestrel. The same code below works when using IIS Express.
In ConfigureServices():
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
In Configure():
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("CorsPolicy");
// THIS IS THE PROBLEM - has to happen BEFORE .UseAuthorization
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Note .UseRouting() comes after .UseAuthorization() and .UseAuthentication() and that's what's apparently causing the non-authorization on the controller.
Switching the configuration code to:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
makes the problem go away. WIth this in place both IIS Express and Kestrel now work with Windows Auth and produce a proper WindowsIdentity.
That the middleware order needs to be a certain way is understandable if confusing and non-discoverable, although it would be nice if there was some way to notify via error or warning if the order is not viable (if possible).
The more serious problem though is that the [Authorize] attribute on the controller in the failure scenario fails to block the request completely. Instead it passes through the request as if there was no authorization present at all. This should fail.
@RickStrahl I can't reproduce the behavior where IIS Express provides an identity but Kestrel doesn't, when the order of the middleware is wrong. Can you share your launchSettings.json configuration for IIS/IIS Express please?
I can reproduce the IIS Express behavior of always getting an identity (even when the middleware are in the wrong order) but only if I disable anonymous authentication. This essentially forces IIS Express to always authenticate so you always get an identity flowing from IIS Express.
Somewhat related to #9041 and #8526
@DamianEdwards - Double checked and the following is true:
anonymousAuthentication=true in IISExpress Windows Auth works with the 'wrong' orderanonymousAuthentication=false IISExpressWindows Auth doesn't work with the 'wrong' order and fails in the same way as the KestrelSwapping the order properly makes it work on all platforms.
Thanks @RickStrahl. To be clear, with IIS Express, when Windows authentication is enabled and anonymous disabled, it will always attempt to authenticate the user, irrespective of any challenge originating from the application. So while you may indeed end up with an identity being created, that doesn't mean the endpoint itself is being authorized if you get the middleware in the wrong order (i.e. the authentication, presence of an identity, and authorization of the endpoint, are all orthogonal).
We're looking at making a slight change to the current check we have to tighten this up and have the app throw an exception in the case that an endpoint with authorization metadata is to be executed, but the authorization middleware wasn't executed in the context of an endpoint being set. Today it just checks that the endpoint middleware executed anywhere in the pipeline, but that's not enough.
This is patch worthy
I have the same problem using Bearer token auth
public void Configure(IApplicationBuilder app)
{
app.UseCors("corsGlobalPolicy");
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseRouting(); // no auth active because this is after the UseAuth..,
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
If I switch the UseRouting above the auth stuff, then the auth stuff works, otherwise all requests pass through.
If I switch the UseRouting above the auth stuff, then the auth stuff works, otherwise all requests pass through.
That's by design but it should throw.
@mkArtakMSFT are we in a position to prepare this as a patch for 3.0.x, rather than waiting for 3.1?
@mkArtakMSFT are we in a position to prepare this as a patch for 3.0.x, rather than waiting for 3.1?
We'll be fixing this as part of 3.0.2 (November) release.
Most helpful comment
That's by design but it should throw.