Web API Basic Authentication

15:48

Introduction

In this article I want to show how to use Basic Authentication in Web API, how it working and hosting in IIS.

What Is Authentication?

Authentication is the identity of an end user. It is validating the identity of a user who is accessing our system. We use Basic Authentication technique to understand that the user able in WebAPI.

What Is Authorization?

Authorization is the technique which is come after Authentication. Authorization means what all permissions the authenticated user has to access web resources. Is allowed which part the user will access in the web site. This could be achieved by setting roles and permissions for an end user who is authenticated, or can be access through providing a secure token.

What Is Basic Authentication?

Basic authentication is a mechanism, where an end user gets authenticated through our Web API service i.e. RESTful service with the help of plain credentials such as user name and password. An end user makes a request to the service for authentication with user name and password. Service receives the request and checks if the credentials are valid or not, and returns the response accordingly. In case of invalid credentials, service responds with 401 error code i.e. unauthorized. The actual credentials is happend through the database or any config file like web.config or in the code itself. Here I use credentials in the code.

Advantages Of Basic Authentication

1. It supported all the major browsers.
2. Relatively simple protocol.

Disadvantages Of Basic Authentication

1. There have no way to log out, except by ending the browser session.
2. Credentials are sent as plaintext.
3. Credentials are sent with every request.
4. Cross-site request forgery (CSRF) attacks. Requires Anti-Forgery Tokens.

What Is CSRF and Anti-Forgery Tokens?

CSRF is Cross-Site Request Forgery. Suppose you login into a website that url is www.webproject.com and its uses Form authentication. The server authenticate your credentials and send a response with authentication cookie. Now you visits a malicious web site. The malicious site HTML like this:
        
<h1>You Are Winner Of $50000!</h1>
<form action="http://webproject.com/api/account" method="post">
    <input type="hidden" name="Transaction" value="withdraw" />
    <input type="hidden" name="Amount" value="5000000" />
    <input type="submit" value="Click Here"/>
</form>
So you see that the form action posts to the vulnerable site, not to the malicious site. This is the "cross-site" part of CSRF. When you click the button the request runs on the "www.webproject.com" server with your authentication context and can do anything that you can do after authenticate. Because the browser includes the authentication cookie with the request. This is Cross-site request forgery (CSRF) attacks.
To prevent Cross-site request forgery (CSRF) attacks ASP.NET MVC uses anti-forgery tokens, also called request verification tokens.

Table

   
CREATE TABLE Employee(
 [Id] [int] primary key IDENTITY(1,1) NOT NULL,
 [Name] [nvarchar](50) NOT NULL,
 [Address] [nvarchar](500) NOT NULL,
 [Country] [nvarchar](50) NOT NULL,
 [City] [nvarchar](50) NOT NULL,
 [Mobile] [nvarchar](10) NOT NULL
)

Stored Procedure

CREATE PROCEDURE [dbo].[sp_InsUpdDelEmployee]
@id int,
@name nvarchar(50),
@address nvarchar(500),
@country nvarchar(50),
@city nvarchar(50),
@mobile nvarchar(50),
@type varchar(10)
AS
Begin
 if(@type = 'Ins')
 Begin
  insert into Employee
  values(@name,@address,@country,@city,@mobile)
 End
 else if(@type = 'Upd')
 Begin
  update Employee
  set Name = @name,
      [Address] = @address,
   Country = @country,
   City = @city,
   Mobile = @mobile
   where Id = @id
 End
 else if(@type = 'Del')
 Begin
  delete from Employee
  where Id = @id
 End 
 else if(@type = 'GetById')
 Begin
  select * from Employee
  where Id = @id
 End
    select * from Employee
End

Step:1

Create Web API Solutions
























Step:2

Build the application

Step:3

Modified web.config in the "system.web" section.
<system.web>
    <authentication mode="Windows" />
</system.web>
Also add the bellow code in the web.config
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="BasicAuthHttpModule" type="Web_API_Basic_Authentication.Modules.BasicAuthHttpModule, Web_API_IIS_Hosting" />
    </modules>
</system.webServer>

Step:4

Create a new class name "BasicAuthHttpModule" in the "Modules" folder.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web;

namespace Web_API_Basic_Authentication.Modules
{
    public class BasicAuthHttpModule : IHttpModule
    {
        public static string Realm = "WebAPIBasicAuthentication";

        public void Init(HttpApplication context)
        {
            context.AuthenticateRequest += OnApplicationAuthenticateRequest;
            context.EndRequest += OnApplicationEndRequest;
        }
        
        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

        private static bool AuthenticateUser(string credentials)
        {
            var encoding = Encoding.GetEncoding("iso-8859-1");
            credentials = encoding.GetString(Convert.FromBase64String(credentials));
            var credentialsArray = credentials.Split(':');
            var username = credentialsArray[0];
            var password = credentialsArray[1];

            if (username == "" || password == "")
            {
                Realm = "Please enter the value properly!";
                return false;
            }
            if (!(username == "surajit" && password == "coder007"))
            {
                Realm = "Username or Password Doesn't Matched!";
                return false;
            }
            var identity = new GenericIdentity(username);
            SetPrincipal(new GenericPrincipal(identity, null));
            return true;
        }

        private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            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)
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                }
            }
        }

        private static void OnApplicationEndRequest(object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            if (response.StatusCode == 401)
            {
                response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm));
            }
        }

        public void Dispose()
        {
        }
    }
}

Step:5

Add Code In API Controller
Now we add "[Authorize]" attribute in the action or controller that we want to apply basic authentication. Here we apply "[Authorize]" attribute in the controller. So all the actions in the controller will apply basic authentication.
using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Web_API_IIS_Hosting_Services.Models;
using System.Web.Http.Cors;
using System.Web.Cors;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Http.Headers;

namespace Web_API_IIS_Hosting_Services.Controllers
{
    [Authorize]
    public class TestAPIController : ApiController
    {
        // Get All The Employee
        public List Get()
        {
            List emplist = new List();
            using (dbEntities db = new dbEntities())
            {
                var results = db.sp_InsUpdDelEmployee(0, "", "", "", "", "", "Get").ToList();
                foreach (var result in results)
                {
                    var employee = new Employee()
                    {
                        Id = result.Id,
                        Name = result.Name,
                        Address = result.Address,
                        Country = result.Country,
                        City = result.City,
                        Mobile = result.Mobile
                    };
                    emplist.Add(employee);
                }
                return emplist;
            }
        }

        // Get Employee By Id
        public Employee Get(int id)
        {
            using (dbEntities db = new dbEntities())
            {
                Employee employee = db.Employees.Find(id);
                if (employee == null)
                {
                    throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
                }
                return employee;
            }
        }

        // Insert Employee
        public HttpResponseMessage Post(Employee employee)
        {
            if (ModelState.IsValid)
            {
                using (dbEntities db = new dbEntities())
                {
                    var emplist = db.sp_InsUpdDelEmployee(0, employee.Name, employee.Address, employee.Country, employee.City, employee.Mobile, "Ins").ToList();
                    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, emplist);
                    return response;
                }
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }

        // Update Employee
        public HttpResponseMessage Put(Employee employee)
        {
            List emplist = new List();
            HttpResponseMessage response = null;
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            using (dbEntities db = new dbEntities())
            {
                try
                {
                    emplist = db.sp_InsUpdDelEmployee(employee.Id, employee.Name, employee.Address, employee.Country, employee.City, employee.Mobile, "Upd").ToList();
                    response = Request.CreateResponse(HttpStatusCode.OK, emplist);
                    return response;
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
                }
            }
        }

        // Delete employee By Id
        public HttpResponseMessage Delete(int id)
        {
            List emplist = new List();
            HttpResponseMessage response = null;
            using (dbEntities db = new dbEntities())
            {
                var results = db.sp_InsUpdDelEmployee(id, "", "", "", "", "", "GetById").ToList();
                if (results.Count == 0)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }
                try
                {
                    emplist = db.sp_InsUpdDelEmployee(id, "", "", "", "", "", "Del").ToList();
                    response = Request.CreateResponse(HttpStatusCode.OK, emplist);
                    return response;
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
                }
            }
        }

        public HttpResponseMessage Options()
        {
            var response = new HttpResponseMessage();
            response.StatusCode = HttpStatusCode.OK;
            return response;
        }

        // Prevent Memory Leak
        protected override void Dispose(bool disposing)
        {
            using (dbEntities db = new dbEntities())
                db.Dispose();
            base.Dispose(disposing);
        }
    }
}
WebApiConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Cors;

namespace Web_API_Basic_Authentication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

Step:6

Our basic authentication web api service is ready. Now run the application. You see in the browser like this:


We need to provide User Name and Password to authenticate. After provide user Name "surajit" and Password "coder007" we can see the results in the browser.


Hosting in IIS

Windows + R >> Open Command Prompt >> Type "inetmgr" >> Open IIS >> Follow the below step




















Download

You can download Client application zip file here - 7.8 MB

Conclusion

Hei guys, I hope this will be very helpful to you. If you getting any problem, please send me a message.

You Might Also Like

0 comments