How to create custom authentication mechanism based on HTTP header?

I’m leaving old version of question on a bottom.

I’d like to implement custom authentication for SignalR clients. In my case this is java clients (Android). Not web browsers. There is no Forms authentication, there is no Windows authentication. Those are plain vanilla http clients using java library.

So, let’s say client when connects to HUB passes custom header. I need to somehow authenticate user based on this header. Documentation here mentions that it is possible but doesn’t give any details on how to implement it.

Here is my code from Android side:

hubConnection = new HubConnection("http://192.168.1.116/dbg", "", true, new NullLogger());
        hubConnection.getHeaders().put("SRUserId", userId);
        hubConnection.getHeaders().put("Authorization", userId);

        final HubProxy hubProxy = hubConnection.createHubProxy("SignalRHub");
        hubProxy.subscribe(this);


        // Work with long polling connections only. Don't deal with server sockets and we
        // don't have WebSockets installed
        SignalRFuture<Void> awaitConnection = hubConnection.start(new LongPollingTransport(new NullLogger()));
        try
        {
            awaitConnection.get();

            Log.d(LOG_TAG, "------ CONNECTED to SignalR -- " + hubConnection.getConnectionId());
        }
        catch (Exception e)
        {
            LogData.e(LOG_TAG, e, LogData.Priority.High);
        }

P.S. Original question below was my desire to “simplify” matter. Because I get access to headers in OnConnected callback. I thought there is easy way to drop connection right there..


Using Signal R with custom authentication mechanism. I simply check if connecting client has certain header passed in with connection request.

Question is – how do I DECLINE or NOT connect users who don’t pass my check? Documentation here doesn’t really explain such scenario. There is mentioning of using certificates/headers – but no samples on how to process it on server. I don’t use Forms or windows authentication. My users – android java devices.

Here is code from my Hub where I want to reject connection..

public class SignalRHub : Hub
{
    private const string UserIdHeader = "SRUserId";

    private readonly static SignalRInMemoryUserMapping Connections = new SignalRInMemoryUserMapping();

    public override Task OnConnected()
    {
        if (string.IsNullOrEmpty(Context.Headers[UserIdHeader]))
        {
            // TODO: Somehow make sure SignalR DOES NOT connect this user!
            return Task.FromResult(0);
        }

        Connections.Add(Context.Headers[UserIdHeader], Context.ConnectionId);
        Debug.WriteLine("Client {0}-{1} - {2}", Context.Headers[UserIdHeader], Context.ConnectionId, "CONNECTED");

        return base.OnConnected();
    }

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

So I just created a custom Authorization Attribute and overrode the AuthorizeHubConnection method to get access to the request and implemented the logic that you were trying to do with the Header and it appears to be working.

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace SignalR.Web.Authorization
{
    public class HeadersAuthAttribute : AuthorizeAttribute
    {
        private const string UserIdHeader = "SRUserId";

        public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
        {
            if (string.IsNullOrEmpty(request.Headers[UserIdHeader]))
            {
                return false;
            }

            return true;
        }
    }
}

Hub

 [HeadersAuth]
    [HubName("messagingHub")]
    public class MessagingHub : Hub
    {

    }

Which yields this in the console (if the picture doesn’t show up, it’s a [Failed to load resource: the server responded with a status of 401 (Unauthorized)]):

enter image description here

Method 2

In fact, accepted answer is wrong. Authorization attribute, surprisingly, shall be used for authorization (that is, you should use it for checking whether requesting authenticated user is authorized to perform a desired action).

Also, since you using incorrect mechanics, you don’t have HttpContext.Current.User.Identity set. So, you have no clear way to pass user info to your business / authorization logic.

And third, doing that you won’t be able to use Clients.User() method to send message to specific user, since SignalR will be not able to map between users and connections.

The correct way is to plug in into OWIN authentication pipeline. Here is an excellent article explaining and demonstrating in detail how to implement custom authentication to be used in OWIN.

I not going to copy-paste it here, just follow it and make sure you implement all required parts:

  • Options
  • Handler
  • Middleware

After you have these, register them into OWIN:

app.Map("/signalr", map =>
{
   map.UseYourCustomAuthentication();

   var hubConfiguration = new HubConfiguration
   {
       Resolver = GlobalHost.DependencyResolver,
   };

   map.RunSignalR(hubConfiguration);
});


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x