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");
}
...
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 useHttpContext.Current.User
instead. – Adkinscontainer.RegisterWebApiRequest<IPrincipal>(() => HttpContext.Current.User != null ? HttpContext.Current.User : Thread.CurrentPrincipal);
withcontainer.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) – Microstructurecontainer.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