-
Notifications
You must be signed in to change notification settings - Fork 107
Description
Describe the bug
Using UseAzureSignalR
does not inspect the Hub
objects for AuthorizeAttributes
prior to making the /negotiate
call like ASP .NET Core SignalR does. This results in Negotiation authorization to behave incorrectly. Authorization for Azure SignalR only takes place between the negotiate calls and the redirection to Azure SignalR, but if Authorization to /negotiate
fails, then the Authorization check against the Hubs can never happen.
How does it work in ASP .NET SignalR?
In ASP .NET Core SignalR, after a hub is started and a negotiation takes place, the DefaultHubDispatcher
calls a method called IsHubMethodAuthorized
here:
This uses the HubMethodDescriptor.Policies
to determine if the user is Authorized to perform negotiation. Those same HubMethodDescriptor.Policies
are accumulated using the following code:
This looks at the Hubs, and grabs the AuthorizeAttribute
s off each to build up a list of IAuthorizeData
(policies).
This allows ASP .NET Core to properly handle Authorization of Hubs exactly like Authorization of standard controller endpoints. This logic should probably be used in Azure SignalR as well so that policies can be enforced (or not enforced) in the same way.
I will add, I think the primary place that this metadata gets added to the /negotiate
endpoints is right here:
To Reproduce
See this forked branch -> https://github.com/mhintzke/azure-signalr/tree/matt/reproduce-1602
Just add a connection string and then toggle ShouldUseAzureSignalR
app setting between true
and false
and load the app. You will see that when using Azure SignalR we get a 401 on the /negotiate
(because the FallbackPolicy
is used) but on ASP .NET SignalR we get a 200.
Simply setup a FallbackPolicy
that will always fail authorization and a "foobar" policy (it can do anything, but you can set a breakpoint on this and see that it is never be invoked) using native ASP .NET AddAuthorization
method. Then, add [Authorize(Policy = "foobar")]
to a Hub and try to negotiate with it. You will see that rather than using "foobar"
to Authorize, it uses the FallbackPolicy
and will therefore fail Authorization. Setting FallbackPolicy
back to null
then allows the /negotiate
endpoint to pass Authorization upstream from Azure SignalR endpoint and then the Hub authorizes correctly.
Further technical details
- Azure SignalR v1.17.0 (also reproduced on 1.15.0)
- .NET 6 (but will reproduce in .NET 5 since .NET 6 doesn't seem to be officially supported)