5

Is there anyway to access the current principal and before the request gets to the controller using Simple Injector? I am using OWIN and Asp.net identity.

I have a DbContext that I inject into my controllers, but this context will get it's connection string based off the authenticated user. This is what I have so far,

container.RegisterWebApiRequest<TenantDbContext>();
container.RegisterWebApiRequest<ITenantConnectionStringProvider>(() => new TenantConnectionStringProvider(container));

Then in my TenantConnectionStringProvider I have this,

var request = container.GetCurrentHttpRequestMessage();
var principal = request.GetRequestContext().Principal as ClaimsPrincipal;

But the principal has no claims. I realized the claims are only available after the controller has been created. Does this mean it's just not possible because this step comes before the controller is created?

Edit: This is basically what the rest of the code does:

WebApi Controller

    public CampaignsController(TenantDbContext context, ILog log)
    {
        this.campaignService = campaignService;
        this.log = log;
    }

Tenant context(just inherits from DbContext from EF):

    public TenantDbContext(ITenantConnectionStringProvider provider)
        : base(provider.GetConnectionString())
    {
    }

After messing around a bit, I was able to do this, but it feels very hacky.. I added an OWIN middleware that happens after authentication. I'm not sure why but I have all the authenticated users information here, but when it goes to the TenantConnectionStringProvider, none of this info is available on the HttpRequestMessage.

        app.Use(async (context, next) =>
        {
            using (container.BeginExecutionContextScope())
            {
                CallContext.LogicalSetData("Claims", context.Authentication.User.Claims);
                var request = (OwinRequest)context.Request;
                await next();
            }
        });

Then in my TenantConnectionStringProvider I just did this,

    public string GetConnectionString()
    {
        var context = (IEnumerable<Claim>)CallContext.LogicalGetData("Claims");
        return "test";//get claim from context to get the connection string
    }
smoyer
  • 7,932
  • 3
  • 17
  • 26

2 Answers2

5

You can register a Func<ClaimsPrincipal> (factory) and inject it to your TenantConnectionStringProvider class :

public class TenantConnectionStringProvider : ITenantConnectionStringProvider
{
    private readonly Func<ClaimsPrincipal> _claimsPrincipalFactory;
    public TenantConnectionStringProvider(Func<ClaimsPrincipal> claimsPrincipalFactory)
    {
        _claimsPrincipalFactory = claimsPrincipalFactory;            
    }

    public void TestMethod()
    {
        // Access the current principal
        var principal = _claimsPrincipalFactory();
    }
}

Registrations should look like that (not sure...):

// Register your types, for instance using the scoped lifestyle:
container.RegisterSingleton<Func<ClaimsPrincipal>>(() =>
{
    // Not sure of which one to use.
    //return (ClaimsPrincipal)HttpContext.Current.User;
    //return (ClaimsPrincipal)Thread.CurrentPrincipal;
    return (ClaimsPrincipal)Context.User;
});
container.RegisterWebApiRequest<ITenantConnectionStringProvider, TenantConnectionStringProvider>();
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • I simplified your registration a bit by making the factory a singleton; since there's no need in creating a new delegate on each request. Note that you should never call the factory inside an injection constructor, as I explained in the comment on Erik's answer. In your case it even yields invalid results, because the principal might not be available during object graph construction. In other words, while a factory is meant to delay object construction, you don't delay anything, because the delegate is called inside the ctor. – Steven Feb 02 '16 at 02:19
  • Thanks @Steven. For the call of the factory in the constructor, it was just to give a example on how to get the principal. I will update my answer. – Thomas Feb 02 '16 at 02:23
  • Upvoted. Note that the TenantConnectionStringProvider can become a singleton as well. – Steven Feb 02 '16 at 02:26
  • I prefer the Lazy class, otherwise each time the `Func` is used it's possible to get different results (generally speaking). For instance if someone decides to change the user, you get a different result. Same reason Microsoft made the mistake of making `DateTime.Now` a [property and not a method](http://stackoverflow.com/a/5438039/209259), as methods are generally designed to return different results, while properties are generally static. – Erik Philips Feb 02 '16 at 04:58
  • I think it's [Context.Authentication.User](https://msdn.microsoft.com/en-us/library/microsoft.owin.iowincontext.authentication(v=vs.113).aspx#P:Microsoft.Owin.IOwinContext.Authentication) btw :) – Erik Philips Feb 02 '16 at 05:03
  • @ErikPhilips, Seems interesting ^^, I'll have a look at Context.Authentication.User. – Thomas Feb 02 '16 at 08:47
  • I would argue against using `Lazy`, as @ErikPhilips suggests, since this is a leaky abstraction, as discussed [here](https://stackoverflow.com/a/21724609/264697). – Steven Feb 03 '16 at 09:12
  • @Steven that's a really good point. Fundamentally it appears the link still uses lazy, it just hides that from the consumer (both of which seem like a really good idea). I would assume that also makes `Func` a leaky abstraction. – Erik Philips Feb 03 '16 at 15:15
  • 1
    @ErikPhilips As a matter of fact: yes, Func is a bad idea, but usually not because it leaks, but because it complicates things for the consumer, while we shpuld strive to make things simpler for the consumer. – Steven Feb 03 '16 at 15:21
3

Does this mean it's just not possible because this step comes before the controller is created?

Definitely the way you've created it. I'm not completely familar with the but I bet using Lazy<> might be of benefit:

var request = container.GetCurrentHttpRequestMessage();
var principal = new Lazy<ClaimsPrincipal>(() => 
  {
    return request.GetRequestContext().Principal as ClaimsPrincipal;
  });

Not tested, but when you actually need the principal value (i'm assume sometime later, in a different method in the same class) you can use principal.Value and it would then run and retrieve your ClaimsPrincipal. Granted these are huge assumptions because there is no code to see how everything is wired up. If you can provide how you get your connectionstring for the dbcontext (how that is all wired up) I might be able to give you a complete solution.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • I don't think Lazy will help here, I need to access the claims immediately during injection. I will edit my post with what is going on. – smoyer Feb 02 '16 at 01:53
  • @SSteveadoo you should not need the claim inside the injection constructor; this is bad practice as Mark Seemann explains [here](http://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/) and since the principal is runtime data, [this advice](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99) holds as well. – Steven Feb 02 '16 at 02:13