Why is Thread.CurrentPrincipal.Identity.IsAuthenticated false when creating an instance using Simple Injector
Asked Answered
M

0

5

Basically I am trying to get the current set of claims for an authenticated user (via bearer token) currently accessing a Web Api; by injecting the current principal into a helper class, which is then injected into class that is injected into an ApiController.

However, the principal returned is never the one I want, as it is not authenticated and contains no claims. If I step through to the constructor of the ApiController after it is created the local ApiController.User principal value is set correctly.

Here is some of the code from a sample solution I have created and linked to below...

Container registration:

namespace PrincipalInjector
{
    using System.Security.Principal;
    using System.Threading;
    using System.Web;
    using System.Web.Http;

    using SimpleInjector;
    using SimpleInjector.Integration.WebApi;

    public static class ContainerConfig
    {
        public static void Register(HttpConfiguration config)
        {
            Container container = new Container();
            InitializeContainer(container);
            container.RegisterWebApiControllers(config);
            container.Verify();
            config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
        }

        private static void InitializeContainer(Container container)
        {
            container.RegisterWebApiRequest<IPrincipal>(() => 
                HttpContext.Current.User != null ? HttpContext.Current.User : Thread.CurrentPrincipal);
        }
    }
}

Sample controller:

namespace PrincipalInjector.Controllers
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Security.Principal;
    using System.Web.Http;

    public class DefaultController : ApiController
    {
        private readonly IPrincipal principal;

        public DefaultController(IPrincipal principal)
        {
            this.principal = principal;
        }

        // GET api/default
        public IEnumerable<string> Get()
        {
            IList<string> roles = new List<string>();
            ClaimsIdentity claimsIdentity = null;

            if (this.principal.Identity.IsAuthenticated)
            {
                claimsIdentity = (ClaimsIdentity)this.principal.Identity;
                roles.Add("From injected principal");
            }
            else
            {
                claimsIdentity = (ClaimsIdentity)this.User.Identity;
                roles.Add("From ApiController.User");
            }

            if (claimsIdentity.Claims.Where(c => c.Type == ClaimTypes.Role.ToString()).Count() > 0)
            {
                roles = roles.Union(claimsIdentity.Claims.Where(c => c.Type == ClaimTypes.Role.ToString()).Select(c => c.Value)).ToList();                
            }
            else
            {
                roles.Add("No roles found");
            }

            return roles;
        }
    }
}

The sample controller shows that the injected principal is not authenticated but the local ApiController.User principal is and contains the user roles. And in the above example the roles are always returned from the path "From ApiController.User".

Does anybody know why the claims are not available when getting the Thread.CurrentPrincipal from simple injector?

Cheers

Edit: Added contrived sample solution here that shows IPrincipal not being injected with Role details but local ApiController user principal does: http://www.filedropper.com/principalinjector

Further Edit: Updated sample code inline

Further info:

If I modify the container to use lazy loading I can get the principal from the injector...

Container change:

 container.RegisterWebApiRequest<Lazy<IPrincipal>>(() => new Lazy<IPrincipal>(() => Thread.CurrentPrincipal));

Controller change:

        private readonly Lazy<IPrincipal> principal;

        public DefaultController(Lazy<IPrincipal> principal)
        {
            this.principal = principal;
        }

        ...

        if (this.principal.Value.Identity.IsAuthenticated)
        {
            claimsIdentity = (ClaimsIdentity)this.principal.Value.Identity;
            roles.Add("From injected principal");
        }

        ...
Microstructure answered 22/9, 2014 at 21:40 Comment(10)
The ApiController.User is set at the beginning of the request and this information comes from the request itself, instead of from the thread. I think you should use HttpContext.Current.User instead.Adkins
Not sure I'm 100% reading the code correctly, but it looks like you're trying to get the current user during Setup. What you probably want to do is get the user of the request, which will only be available when a request is being processed in the pipeline (via OwinContext). To get a per-request object you probably want to use "app.CreatePerOwinContext<ICurrentClaim>(() => new CurrentClaims(...));"Seattle
Hi Steven, thanks for feedback, unfortunately that's not working in this case either. I have added a link to a contrived sample project in case you have time to look at that. It shows the difference in injected and local API IPrincipal.Microstructure
Additionally, once you're in the request pipeline and have an IOwinContext, then you can use IOwinContext.Authentication.User to get the current claims principal.Seattle
Hi jaytre, thanks for response, I will take a look into that and see if it helps. I have updated sample code inline to hopefully make it clearer what is happening.Microstructure
I'm not certain about DependencyResolvers. I've never used them in the past, but if you're looking to get the current principal in the request I would suggest using 'Request.GetOwinContext().Authentication.User' instead of piping the Thread.CurrentUser or HttpContext.CurrentUser (IIRC, I don't think Owin uses these properties).Seattle
Hi jaytre, unfortunately no luck with that either I replaced: container.RegisterWebApiRequest<IPrincipal>(() => HttpContext.Current.User != null ? HttpContext.Current.User : Thread.CurrentPrincipal); with container.RegisterWebApiRequest<IPrincipal>(() => HttpContext.Current.User != null ? HttpContext.Current.GetOwinContext().Authentication.User : Thread.CurrentPrincipal); but the result is the same...as far as I can tell they refer to the same thing. I guess I don't understand why ApiController.User is set ok, but creating its injected properties is not (edit formatting/comment)Microstructure
What happens if you replace 'if (this.principal.Identity.IsAuthenticated)' with 'if(Request.GetOwinContext().Authentication.User.Identity.IsAuthenticated)'? I don't think HttpContext.Current is used for authentication in OwinSeattle
Unfortunately that doesn't resolve either, so far I have found the only way to access the property is to defer loading of the Principal until it is required: container.RegisterWebApiRequest<Lazy<IPrincipal>>(() => new Lazy<IPrincipal>(() => Thread.CurrentPrincipal)); Which appears to work, nothing I do will populate the user claims until after the dependency resolver has resolved all dependencies. Feel free to download the very basic sample app referenced above to have a play.Microstructure
Let us continue this discussion in chat.Microstructure

© 2022 - 2024 — McMap. All rights reserved.