Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Api 2 Basic Auth Generic Principal Not Set

I have the following code to set a Generic Principal.

public class AuthenticationHandler: DelegatingHandler
{
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                                                  CancellationToken cancellationToken)
    {
        var accessToken = request.Headers.Authorization;
        if (accessToken == null)
            return base.SendAsync(request, cancellationToken);

        // Catch an error with regards to the accessToken being invalid
        try
        {
            var formsAuthenticationTicket = FormsAuthentication.Decrypt(accessToken.Parameter);

            if (formsAuthenticationTicket == null)
                return base.SendAsync(request, cancellationToken);

            var data = formsAuthenticationTicket.UserData;
            var userData = JsonConvert.DeserializeObject<LoginRoleViewModel>(data);

            var identity = new GenericIdentity(userData.Id.ToString(), "Basic");

            var userRole = userData.Roles.ToArray();
            var principal = new GenericPrincipal(identity, userRole);
            Thread.CurrentPrincipal = principal;
            HttpContext.Current.User = principal;

        }
        catch (Exception ex)
        {
            var responseMessage = request.CreateResponse(HttpStatusCode.BadRequest, new { ex.Message }); // return ex for full stacktrace
            return Task<HttpResponseMessage>.Factory.StartNew(() => responseMessage);
        }

        return base.SendAsync(request, cancellationToken);
    }

}

Below is an example of a controller

[Authorize(Roles = "Administrator, Customers")]
[HttpGet("customers/{id}")]
public CustomerViewModel GetCustomer(string id)
{
    var param = AuthService.CheckPermission(Request, User, id);
    var customer = Db.Customers.Find(param);
    return Mapper.Map<CustomerViewModel>(customer);
}

And this is where I check if the user roles

public int CheckPermission(HttpRequestMessage request, IPrincipal user, string param)
{
    if (user.IsInRole("Customers") || user.IsInRole("Dealerships"))
    {
        if (param == null || param != "me")
            throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.Forbidden, "unauthorized request"));
        param = user.Identity.Name;
    }

    return Convert.ToInt32(param);
}

This was working perfectly before upgrading to Web Api 2 and MVC 5? Now the User has no roles or identity, has something changed that I am unaware of?

like image 504
TYRONEMICHAEL Avatar asked Oct 18 '13 08:10

TYRONEMICHAEL


2 Answers

Not sure why it doesn't work anymore, but in Web API 2, there is a new class HttpRequestContext with a Principal property, and that is what you should be setting to update the Principal. You can access the context object from the request.

like image 192
Darrel Miller Avatar answered Oct 11 '22 23:10

Darrel Miller


Really uncertain as to why this functionality has changed after years of stability.

We found the following works

request.GetRequestContext().Principal = new GenericIdentity(userData.Id.ToString(), "Basic");

This also works and IMO is more aesthetically pleasing as you're not setting members of a function

HttpContext.Current.User = new GenericIdentity(userData.Id.ToString(), "Basic");
like image 32
JConstantine Avatar answered Oct 12 '22 00:10

JConstantine