Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Securing SignalR Calls

Tags:

signalr

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?
like image 567
reach4thelasers Avatar asked Apr 03 '12 10:04

reach4thelasers


People also ask

How can I secure my SignalR?

If you want to restrict access to it you need to authenticate users and authorize their actions. You authenticate using standard web auth methods (forms auth, cookies, Windows auth, etc.) and you can authorize in code using SignalR constructs (like the Authorize attribute you point out) or with your own code.

Does SignalR need SSL?

If your SignalR application transmits sensitive information between the client and server, use SSL for the transport.

How do you implement authentication in SignalR?

When using the browser client, no additional configuration is needed. If the user is logged in to your app, the SignalR connection automatically inherits this authentication. Cookies are a browser-specific way to send access tokens, but non-browser clients can send them.

Does SignalR keep connection alive?

You can handle this event if you want your application to take some action when a transport connection is lost. The default keepalive timeout period is currently 20 seconds. If your client code tries to call a Hub method while SignalR is in reconnecting mode, SignalR will try to send the command.


4 Answers

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";
    }
like image 161
AlignedDev Avatar answered Oct 17 '22 09:10

AlignedDev


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
like image 14
Jared Kells Avatar answered Oct 17 '22 09:10

Jared Kells


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);
    }
}
like image 4
nawdzy Avatar answered Oct 17 '22 10:10

nawdzy


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.

like image 1
Ian Avatar answered Oct 17 '22 09:10

Ian