6

I am trying to inject IPrincipal into my SignalR hub constructors. I already saw and tried the solution from "Selective IPrincipal Injection via StructureMap with SignalR", but unfortunately that doesn't seem to work anymore for SignalR 2.x.

In my debugging, I've discovered that sometimes, my hub constructor is called with my OWIN middleware in the stack. When that is the case, Thread.CurrentPrincipal is the correct value. Additionally (and surprisingly), HttpContext.Current is also not-null. I was under the impression this was always null in SignalR, and I'm not attempting to use it, but I'm just observing. It seems like these calls that do work come from the pipeline in the call stack.

Other times, calls seem to come from the thread pool. In those instances, Thread.CurrentPrincipal is a GenericPrincipal, HttpContext.Current is null (again just observing), and I cannot seem to get at the principal statically. However, inside the hub, the this.Context.User property does have the right principal.

How else can I get the principal statically so that I can inject it into the hub constructor?

Community
  • 1
  • 1
David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
  • To solve this, I made a WebAPI : users can join groups or send messages using my API. In this API I can check the identity/roles. – Guillaume Dec 15 '14 at 13:15
  • @Guillaume How does that solve SignalR? – David Pfeffer Dec 15 '14 at 13:24
  • That doesn't really solve your issue, that's why I didn't post an answer. That's a wrokaround to get the IPrincipal on all incoming action from users. The controller act as a proxy between the client and the hub. Probably not good for realtime (games,...). – Guillaume Dec 15 '14 at 13:28
  • 1
    I don't think you want to set IPrincipal on the Threadpool threads. It would be wrong in other contexts. – Brannon Aug 22 '15 at 04:41

3 Answers3

2

It is expected that HttpContext.Current and Thread.CurrentPrincipal will sometimes be set when SignalR Hubs get activated, but not always. This is because the activating thread often runs with ASP.NET's SynchronizationContext. There are situations when this isn't the case, such as when a Hub is activated in order to handle a WebSocket message or an unclean OnDisconnected event. Long story short, sometimes these statics happen to be there, but you cannot rely on it.

I don't know of any way to statically get the IPrincipal reliably. What's wrong with using Context.User inside your Hub?

halter73
  • 15,059
  • 3
  • 49
  • 60
  • 2
    `Context.User` relies on tighter coupling to the SignalR hubs framework, which reduces the ability for me to (for example) share code between SignalR and Web API without wrapper functions. – David Pfeffer Dec 16 '14 at 00:42
2

If I understood correctly what you're trying to do... You should build your own Authorize attribute, that will put the custom principal into a special Owin var, then it will be accessible in Context.User inside a hub.

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
    {
        //put our custom user-principal into a magic "server.User" Owin variable
        request.Environment["server.User"] = new MyCustomPrincipal(); //<!-THIS!

        return base.AuthorizeHubConnection(hubDescriptor, request);
    }
}

And then apply this attribute to your Hub.

If you want more info on this, I blogged about this here with more code samples

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
0

I was trying to solve the same problem and I found solution to set the identity of the user.

My application is saml protected and client application sends "SAML" token as part of header. We have written Asp.net module to verify the token and prepare identity of the user and add value to the response Headers.

I have created OwinStartup class and I have added my own request processor by using below code. I have tested this piece of code for Longpolling and working fine. I am not sure how it works in "WebScoket".

 public void Configuration(IAppBuilder app)
    {
        // Any connection or hub wire up and configuration should go here           
        try
        {
            app.Use(SetMyPrincipalObject);
        }
    }

  private Task SetMyPrincipalObject(IOwinContext arg1, Func<Task> arg2)
    {
        //var p = "Process response";//Process Response Header here and //create identity
        //arg1.Request.User = p;
        //return arg2.Invoke();
    }
Meenesh Jain
  • 2,532
  • 2
  • 19
  • 29
Balu
  • 23
  • 6