Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic authentication in web api

I started working on Web Api and just want to create a simple basic authentication. I want to know how to do that?

I tried with the given MSDN link but no step wise tutorial is given on MSDN. http://www.asp.net/web-api/overview/security/basic-authentication

like image 859
Utsav Avatar asked Apr 09 '13 10:04

Utsav


3 Answers

The link you gave provides much of the detail you need, I hope this fills in the blanks.

Note: If using Web.API 2, Microsoft are suggesting a different approach using authentication filters.

Set up https on your server

This is quite important if you need real security otherwise passwords can be gleaned by snooping parties. How you do this depends a entirely on your setup, which you don't detail, but if you're working on an Azure WebRole there's a pretty good step-by-step guide to setting up SSL from Microsoft.

This isn’t required for the next steps, but should be done before you release your code. I mention it first because this part usually involves getting other people involved (sysadmin for server config, finance to purchase the certificate, etc) and it’s good to give them lots of warning.

Write (or steal) a custom IHttpModule to do your authentication

This is the big block of C# code in your link - it parses the values sent by the browser and sets HttpContext.Current.User to the authenticated user. Just copy and paste the meat into a class in your own application and we’ll come back to it later. You’ll need the following using statements in your code.

using System; using System.Net.Http.Headers; using System.Security.Principal;
using System.Text; using System.Threading; using System.Web;

Associate that module with your application

Add a new module to your web.config file (note system.webServer probably already exists)

<system.webServer>
  <modules>
    <add name="BasicAuth" type="Full.ClassName.Path.BasicAuth, Assembly.Name"/>
  </modules>
</system.webServer>

Restrict access to the relevant parts of your site

You can block specific actions by adding the [Authorize] attribute before the action definition. Block a whole controller by adding it before your controller class.

[Authorize] // Restricts access to whole controller    
public class StockController : ApiController {
    [Authorize] // Restricts access to this action - not necessary if whole controller restricted.
    public IEnumerable<StockLevel> Get() {

Or in your App_Start\WebApiConfig.cs file you can add config.Filters.Add(new AuthorizeAttribute()); and it will lock everything down.

Something to watch out for - there’s also a System.Web.Mvc.AuthorizeAttribute so if you have that namespace included you can get confusing results.

At this point you can try it out - user: "user", pass: "password".

Customize your user validation

Go back to the class we stole from the link and you'll see the following block of code:

// TODO: Here is where you would validate the username and password.
private static bool CheckPassword(string username, string password)

Alter this to return true if the username and password are valid. If you're rolling your own you may want to investigate bcrypt (do you trust the implementation you downloaded off the net?), PBKDF2 or the Crypto class (simple but not terribly secure) but there's probably something better from Microsoft as there are lot of concerns around storing passwords properly.

like image 122
Rob Church Avatar answered Oct 19 '22 18:10

Rob Church


I had to add a few lines of code to the MSDN example to get it to work. Specifically, in OnApplicationAuthenticateRequest(), I set the response status code to 401 if the user could not be validated:

private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            bool validated = false;
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic",
                                                StringComparison.OrdinalIgnoreCase) &&
                    authHeaderVal.Parameter != null)
                {
                    validated = AuthenticateUser(authHeaderVal.Parameter);
                }
            }

            if (!validated)
            {
                HttpContext.Current.Response.StatusCode = 401;
            }
        }

Once I did that, it worked fine. There's probably better ways to structure the logic, but this is about the smallest change from the example that does the job.

like image 37
Eric Pohl Avatar answered Oct 19 '22 17:10

Eric Pohl


To selectively enable basic authentication on a per-controller or per-method basis, you can derive from AuthorizeAttribute as described in this question.

like image 30
Edward Brey Avatar answered Oct 19 '22 17:10

Edward Brey