Closed daniefer closed 6 years ago
Hi @daniefer. Thanks for all the details you've provided. Do you happen to have a small sample project we can use to repro the issue? //cc @danroth27, @rynowak
Cleaned up the example a bit and made a repo here https://github.com/daniefer/AspWebApiIssueExample. Thanks @mkArtakMSFT for getting this started.
Any update or ideas @mkArtakMSFT / @danroth27 / @rynowak ?
@dougbu, do you have any thoughts about this?
Clearing the IOwinContext.User
property is mainly the result of calling HttpConfiguration.SuppressDefaultHostAuthentication()
in the Startup
class. That method adds the PassiveAuthenticationMessageHandler
which (in part) sets OwinHttpRequestContext.Principal
to the anonymous user. That Principal
property writes through to IOwinContext.User
.
The test application seems to work as expected if I remove the SuppressDefaultHostAuthentication()
call.
If you need that call, I suggest creating a new message handler (DelegatingHandler
subclass) to wrap PassiveAuthenticationMessageHandler
(i.e. use PassiveAuthenticationMessageHandler
as the InnerHandler
) and inserting that handler instead of calling SuppressDefaultHostAuthentication()
. The handler should save IOwinContext.User
and restore it after the usual base.SendAsync(...)
call.
Changing PassiveAuthenticationMessageHandler
to restore HttpRequestContext.Principal
after its base.SendAsync(...)
call seems like the obvious fix. But, the code may be as it is for a reason i.e. not just because we were thinking Web API would always be at the end of the Owin pipeline. That is, we may need to add a configuration switch to opt into (or out of) the new behaviour to avoid a breaking change.
Don't need much more investigation. But, I'm leaving the investigate
label 'til we discuss whether my suggested fix is a breaking change.
BTW we should change SuppressHostPrincipalMessageHandler
if we update PassiveAuthenticationMessageHandler
. That also sets but does not restore HttpRequestContext.Principal
.
Adding public bool RestorePrincipal { get; set; }
which naturally will be by default false
sounds to me as the right approach.
We discussed this internally and decided two things:
PassiveAuthenticationMessageHandler
and SuppressHostPrincipalMessageHandler
to restore the Principal
before SendAsync(...)
returns. Must both use an Owin host and perform authentication within the Owin pipeline (not the inner Web API pipeline) to see this issue.
Admittedly, could see something similar with another custom host that has an independent "outer" pipeline of its own.Principal
.Therefore, we should fix this problem without a fallback to the previous, incorrect behaviour.
Clearing assignment and investigate
label. Over to the triage team…
Thanks for investigation everyone. It is good to hear that I am not losing my mind.
Another bit of info that might be useful, I was able to work around this without adding a wrapper around the PassiveAuthenticationMessageHandler
. The issue does not appear if I put the web api on a sub route, e.g.:
appBuilder.Map("api" app => {
app.UseWebApi(config);
};
appBuilder.RunSignalR();
Luckily we were already prefixing all our routes with a consistent name so it was a pretty simple transition.
Thanks @dougbu , @daniefer. I'm closing this issue as it seems the workaround was pretty cheap to apply.
Reopening, as the actual fix is very cheap too... Better to do it and forget!
f9e06d60e4
I am trying to setup a web api with signalr and during the process I noticed this oddity. I cannot seem to find a documented reason why the Identity on the OwinContext would be emptied out after there was no match on the web api route table. I put together a simple project to show this in action:
Startup
Dummy token formatter
Controller
Hub
If I attempt to connect to a Hub (at the end of the pipeline) the OwinContext is no longer authenticated. The output from each DebugMiddleware shows:
Output
Is this a bug or is there a reason for this maddening quirk?