27

I'm using the SignalR Javascript client and ASP.NET ServiceHost. I need the SignalR hubs and callbacks to only be accessible to logged in users. I also need to be able to get the identity of the currently logged in user from the Hub using the FormsIdentity from HttpContext.Current.User.

  1. How do I secure the hub's so that only authenticated users can use SignalR?
  2. How do I get the identity of the currently logged in user from the Hub?
reach4thelasers
  • 26,181
  • 22
  • 92
  • 123
  • Another way to lock down signalr urls using signalr 1.0 and Owin: http://eworldproblems.mbaynton.com/2012/12/securing-signalr-to-your-sites-users/ – mbaynton Dec 22 '12 at 21:26

4 Answers4

20

You should use the this.Context.User.Identity that is available from the Hub. See a related question

EDIT: To stop unauthenticated users:

public void ThisMethodRequiresAuthentication()
{
  if(!this.Context.User.Identity.IsAuthenticated)
  {
    // possible send a message back to the client (and show the result to the user)
    this.Clients.SendUnauthenticatedMessage("You don't have the correct permissions for this action.");
    return;
  }

  // user is authenticated continue
}

EDIT #2: This might be better, just return a message

 public string ThisMethodRequiresAuthentication()
    {
      if(!this.Context.User.Identity.IsAuthenticated)
      {
        // possible send a message back to the client (and show the result to the user)
        return "You don't have the correct permissions for this action.");

       // EDIT: or throw the 403 exception (like in the answer from Jared Kells (+1 from me for his answer), which I actually like better than the string)
       throw new HttpException(403, "Forbidden");
      }

      // user is authenticated continue

      return "success";
    }
Community
  • 1
  • 1
AlignedDev
  • 8,102
  • 9
  • 56
  • 91
  • 1
    Great, now any idea how to secure hubs so that unauthenticated users can't connect? – reach4thelasers Apr 03 '12 at 14:52
  • @reach4thelasers please see my edit. That's what I would try. – AlignedDev Apr 03 '12 at 15:27
  • After looking at @Jared Kells' answer below, I'd recommend that if you need to force authentication on all your methods to use his approach, but if you only need it on a few methods, then use mine. – AlignedDev Oct 30 '12 at 14:04
14

You can lock down the SignalR URL's using the PostAuthenticateRequest event on your HttpApplication. Add the following to your Global.asax.cs

This will block requests that don't use "https" or aren't authenticated.

public override void Init()
{
    PostAuthenticateRequest += OnPostAuthenticateRequest; 
}

private void OnPostAuthenticateRequest(object sender, EventArgs eventArgs)
{
    if (Context.Request.Path.StartsWith("/signalr", StringComparison.OrdinalIgnoreCase))            
    {
        if(Context.Request.Url.Scheme != "https")
        {
            throw new HttpException(403, "Forbidden");
        }

        if (!Context.User.Identity.IsAuthenticated)
        {
            throw new HttpException(403, "Forbidden");
        }
    }            
}

Inside your hub you can access the current user through the Context object.

Context.User.Identity.Name
Jared Kells
  • 6,771
  • 4
  • 38
  • 43
4

For part 1. of your question you could use annotations like below (This worked with SignalR 1.1):

[Authorize]
public class MyHub : Hub
{
    public void MarkFilled(int id)
    {
        Clients.All.Filled(id);
    }
    public void MarkUnFilled(int id)
    {
        Clients.All.UnFilled(id);
    }
}
nawdzy
  • 41
  • 1
1

Something missing from the other answers is the ability to use SignalR's built in custom auth classes. The actual SignalR documentation on the topic is terrible, but I left a comment at the bottom of the page detailing how to actually do it (Authentication and Authorization for SignalR Hubs).

Basically you override the Provided SignalR AuthorizeAttribute class

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthAttribute : AuthorizeAttribute

Then you decorate your hubs with [CustomAuth] above the class declaration. You can then override the following methods to handle auth:

bool AuthorizeHubConnection(HubDescriptor hubDesc, IRequest request);
bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubContext, bool appliesToMethod);

Since I'm on IIS servers and have a custom auth scheme, I simply return true from the AuthorizeHubConnection method, because in my Auth HttpModule I already authenicate the /signalr/connect and /signalr/reconnect calls and save user data in an HttpContext item. So the module handles authenticating on the initial SignalR connection call (a standard HTTP call that initiates the web socket connection).

To authorize calls on specific hub methods I check method names against permissions saved in the HttpContext (it is the same HttpContext saved from the initial connect request) and return true or false based on whether the user has permission to call a certain method.

In your case you might be able to actually use the AuthorizeHubConnection method and decorate your hub methods with specific roles, because it looks like you are using a standardized identity system, but if something isn't working right you can always revert to brute force with HttpModule (or OWIN) middle-ware and looking up context data in on subsequent websocket calls with AuthorizeHubMethodInvocation.

Ian
  • 4,169
  • 3
  • 37
  • 62