Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR - The connection id is in the incorrect format when using Windows and Anonymous authentication

I use SignalR 1.0.1 as a chat core for ASP.NET MVC3 application. Using IIS 7.5

There are two methods in MVC controller which provides access to chat views:
1. First method is public, allowing anonymous users to chat - no authorization.
2. Access to second method is restricted with [Authorize] attribute, for domain users - chat agents.

There is no explicitly specified authorization in the Hub.
For this scenario I involved both Windows and Anonymous authentication on IIS.

I also implemented custom Role Provider, which operates only in memory - not persisting anything to database.

What happens is that using '[Authorize]' attribute in controller method leads to responsing 500 from Hub, both when call is coming from authorized view, and the anonymous one:

Request (send is Hub method for sending messages):

http://localhost:8101/signalr/send?transport=serverSentEvents&connectionToken=VIXEZzWQSn5SNlA8RUy4iaOPDFdvuPBjMvFBiG2FLfvfxF347XHwtapsEV5ndU4OEI0Xb64W2ZRXTqwBiL2CXg2_JlTaTJ2RnVOj4bjvx6tQaYhAqTaXs9k2853GYqzd0

Response:

The connection id is in the incorrect format.

Server stack trace:
   at Microsoft.AspNet.SignalR.PersistentConnection.GetConnectionId(HostContext context, String connectionToken)
   at Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequest(HostContext context)
   at Microsoft.AspNet.SignalR.Owin.CallHandler.Invoke(IDictionary2 environment)
   at Microsoft.AspNet.SignalR.Owin.Handlers.HubDispatcherHandler.Invoke(IDictionary2 environment)
   at Microsoft.Owin.Host.SystemWeb.OwinCallContext.Execute()
   at Microsoft.Owin.Host.SystemWeb.OwinHttpHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object extraData)<br/><br/>

But notice, that connecting to Hub works fine, returns 200 OK:
http://localhost:8101/signalr/connect?transport=serverSentEvents&connectionToken=dYOwFxa1mkgdpzw-jitRpWq9oxRlrTet8U_dAzWjFQEdGNJfVXeG7Op0NZZwvznxeNdJCuPT75CKzQqI9HRPThV3uEDt-Z2qtIl9E02gF481&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&tid=9

I found little similiar thread here on stackoverflow:
signalr The connection id is in the incorrect format


from which I understand, that when invoking my Send method, the Hub is processing request with Identity different than the one used to connect to Hub, OR Hub's GetConnectionId finds, that user is actually not authorized - but how it checks that assumption, when there is no authorization specified on the Hub itself?

Can someone put some light on this?

Thanks in advance :)

like image 328
mskuza Avatar asked Mar 19 '13 13:03

mskuza


2 Answers

SignalR signs both your connection id and your Identity together in order to create a new connectionToken every time you start a new connection. This connectionToken is then sent to the SignalR client as part of the negotiate response.

Every time you make a request to SignalR, whether it be a connect, reconnect, or send request, SignalR verifies that your connectionToken matches both your client's connection id AND Identity.

The connectionToken is essentially a CSRF token used in order to prevent attackers running third-party websites from surreptitiously making SignalR requests on behalf of shared clients. Obviously this doesn't help if you've enabled SignalR's cross-domain support, but the connectionToken still works the same in this case.

Taylor's answer was correct. You should stop and then start your SignalR connection when your client's Identity changes. This will force a new negotiate request which will give your client a new connection id with a new connectionToken signed with your client's updated Identity.

P.S. The server-sent events connect request isn't failing because it was established before your client's Identity was changed. The connectionToken is only checked at the request is received, but server-sent events keeps the response open indefinitely.

like image 152
halter73 Avatar answered Sep 22 '22 11:09

halter73


That's all true what you said and it actually takes place in my issue.

But I also found the the root cause:
One of main assumptions during design was to allow both anonymous users to use the chat without need to sign-in and the back-end users (agents) to sign-in to restricted area of chat using their Windows credentials.

So on the IIS manager I enabled both Anonymous authentication (allowing anonymous users to use the chat) and the Windows authentication (allowing agents to access using their Windows credentials).
MVC application is configured to use Windows authentication - the [Authorize] attribute mentioned in question, but only to restrict access for agent's view of chat.

What actually happens with above configuration is:
1. When client (agent) requests restricted View (let's say it's /Chat/Agent) the [Authorize] attribute initializes authentication (Windows)
2. Client-side Javascript requests Negotiate, what generates connectionId and binds it with client's Windows Identity
3. Here is the tricky part: Because Hub not uses any authentication explicitly, calling send method does not result in any authentication request - IIS Anonymous authentication takes precedency before Windows authentication, and send request is sent with anonymous Identity - but in Hub actual connectionId is related to Identity passed in point 2.

This scenario leads to situation you described - connect is called with different Identity than send and Hub returns The connection id is in the incorrect format.

like image 38
mskuza Avatar answered Sep 21 '22 11:09

mskuza