ASP.NET WebAPI Basic Authentication always fails as 401/Unauthorized

16,445

Solution 1

Don't set the Principal on the Thread.CurrentPrinicipal any more. Use the Principal on the HttpRequestContext.

Solution 2

In my case, following Darrels approach, I commented out the below and used his approach. It work great!... saving me hours

// Thread.CurrentPrincipal = PrincipalProvider
//     .CreatePrincipal(parsedCredentials.Username, parsedCredentials.Password);


   request.GetRequestContext().Principal = PrincipalProvider
       .CreatePrincipal(parsedCredentials.Username, parsedCredentials.Password);
Share:
16,445
theGeekster
Author by

theGeekster

Software Engineer having interest in Software Architecture and Design with experience in: SOA Ruby on Rails PostgreSQL Heroku Github ASP.NET C#, VB.NET Jquery / JavaScript / CoffeeScript JSON REST/SOAP APIs CORS WCF, Web-Services SQL Database (MS SQL Server) No-SQL Database (MongoDB, Radis, etc.) Distributed Databases Dedicated Servers IP-CCTV-Cameras Video Management System SSH-Tunneling Wowza Media Server Streaming/Communication over HTTP/RTSP TDD, Unit Testing Amazon EC2, S3, SES, etc. Microsoft Azure Cloud Services Cloud Servers Setup, RAID Configuration

Updated on June 17, 2022

Comments

  • theGeekster
    theGeekster almost 2 years

    Trying to secure my ASP.NET Web API-2 using Basic Authentication but it is always ending up with error:

    401/Unauthorized
    Authorization has been denied for this request.
    

    Below are my controller and ajax request code snippet alongside the request and response headers.

    BasicAuthenticationHandler.SendAsync always runs successfully up-till:

    return base.SendAsync(request, cancellationToken);
    

    Q: Then WHY it ends up as 401/unauthorized ?

    If I remove [Authorize] from the controller action then it works but without any security.

    Note: Because this is a cross-domain request so I have enabled CORS on server side.

    My Authentication Handler

    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var principal = Thread.CurrentPrincipal;
        if (principal.Identity.IsAuthenticated)
        {
            return base.SendAsync(request, cancellationToken);
        }
    
        var encryptedTicket = ExtractToken(request.Headers.Authorization); // simply returns a string
        if (encryptedTicket != null)
        {
            var ticket = FormsAuthentication.Decrypt(encryptedTicket);
            var serializer = new JavaScriptSerializer();
            var user = serializer.Deserialize<UserInfoModel>(ticket.UserData);
    
            if (user != null)
            {
                var identity = new GenericIdentity(user.UserName, "Basic");
                Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[0]);
            }
        }
    
        // Code reaches here always successfully but after this line errors Unauthorized
        return base.SendAsync(request, cancellationToken);
    }
    

    My Controller

    public class ProductController : ApiController
    {
    
    Product[] products = new Product[] 
    { 
        new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 } 
    };
    
    [Authorize]
    [Route("test/products")]
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public IEnumerable<Product> GetAllProducts()
    {
        return products;
    }
    }
    

    My AJAX Request

    $.ajax({
        type: "GET",
        url: "http://webapi.server.com/test/products",
        crossDomain: true,
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        headers: { Authorization: "Basic 1234567890" },
        success: function (data) {
                alert(data);
        },
        error: function (err) {
                alert(err);
        }
    });
    

    Request Headers

    Accept  application/json, text/javascript, */*; q=0.01
    Accept-Encoding gzip, deflate
    Accept-Language en-US,en;q=0.5
    Authorization   Basic 1234567890
    Content-Type    application/json; charset=utf-8
    Host    webapi.server.com
    Origin  local-pc
    Referer local-pc/Index.aspx
    User-Agent  Mozilla/5.0 (Windows NT 6.2; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0
    

    Response Headers

    Access-Control-Allow-Orig...    *
    Cache-Control   no-cache
    Content-Length  61
    Content-Type    application/json; charset=utf-8
    Date    Thu, 07 Nov 2013 11:48:11 GMT
    Expires -1
    Pragma  no-cache
    Server  Microsoft-IIS/8.0
    X-AspNet-Version    4.0.30319
    X-Powered-By    ASP.NET
    
  • theGeekster
    theGeekster over 10 years
    Thanks a lot Darrel. You have made my day :) (thumbs up). Fixed the problem by changing this to. request.GetRequestContext().Principal = new GenericPrincipal(identity, new string[0]);
  • Rune
    Rune about 10 years
    Thanks, you saved my day :)
  • Leandro Bardelli
    Leandro Bardelli about 9 years
    Sir, you won the internet. I fought 1 week in order to solve this. Really thanks a lot, really
  • Hakan Fıstık
    Hakan Fıstık over 8 years
    @Darrel Please can you update your answer to include the code which fix the problem