Authenticate / Authorize a user using local AD

Authentication and authorization might sound similar but there is a very subtle difference between these two terms.

Authentication is just confirmation of user identity. Such as we know about this user (based on user name and password)

Authorization is when we determine if the user has permissions (access rights) to do what he needs to do.

authenticate and authorize

A lot of times we have to host back-office applications or WebApis in our local on-premises data center. we also need to authenticate Web Api user using local AD (Active directory) and not Azure AD.

In Web API it is very simple, you can create a Custom authentication attribute for user authentication. This custom authentication attribute is responsible to connect with AD and validates username and password.

First of all you need to install following NuGet packages in your project

  • DirectoryServices
  • DirectoryServices.AccountManagement

Authentication using custom authorize attribute

There is a minimum of two methods of authorizing attribute that we need to override.

  • IsAuthorized – Returns boolean, depends if the request is authenticated.
  • HandleUnauthorizedRequest – Sends appropriate message when the request is not authenticated.
using System.Diagnostics;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace WebApi.Business
{
    public class AdAuth : AuthorizeAttribute
    {
        protected override bool IsAuthorized(HttpActionContext actionContext)
        {
            var user = UserManager.GetUserFromContext();
            var isValidUser = UserManager.IsUserValid(user.UserName, user.Password);
            return isValidUser;
        }

        protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
        {
            Debug.WriteLine("user is not authorized.");
            base.HandleUnauthorizedRequest(actionContext);
        }
    }
}

User Manager

if you notice code I have used custom UserManager class to get context and check if the user is valid based on username and password.

This class is just a helper class and I have used it to get UserContext and Tokens (groups) so evaluate user access rights.

using System;
using System.DirectoryServices.AccountManagement;
using System.Text;
using System.Web;

namespace WebApi.Helpers
{
    public static class UserManager
    {
        public static bool IsUserValid(string userName, string password)
        {
            try
            {
                using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "-your-ad-domain"))
                {
                    var valid = pc.ValidateCredentials(userName, password);
                    return valid;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static User GetUserFromContext()
        {
            var user = new User();
            HttpContext httpContext = HttpContext.Current;
            string authHeader = httpContext.Request.Headers["Authorization"];

            if (authHeader != null && authHeader.StartsWith("Basic"))
            {
                string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
                Encoding encoding = Encoding.GetEncoding("iso-8859-1");
                string usernamePassword = encoding.GetString(Convert.FromBase64String(UserToken()));

                int seperatorIndex = usernamePassword.IndexOf(':');

                var username = usernamePassword.Substring(0, seperatorIndex);
                var password = usernamePassword.Substring(seperatorIndex + 1);

                user.UserName = username;
                user.Password = password;
            }

            return user;
        }

        public static string UserToken()
        {
            HttpContext httpContext = HttpContext.Current;
            string authHeader = httpContext.Request.Headers["Authorization"];
            if (authHeader != null && authHeader.StartsWith("Basic"))
            {
                string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
                return encodedUsernamePassword;
            }

            return string.Empty;
        }

       
    }
}

Authorization based on User groups

In authorization, we will determine if a user is in the right groups to access the required data. Every project has a different way to implement it. For example, you might not want to let the user access certain API based on which user group they belong to.

I have created a separate user group controller. That will give you a list of user groups and you can add your logic based on these user groups.

using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Web.Http;

namespace WebApi.Controllers
{
    [AdAuth]
    public class UserGroupsController : ApiController
    {
        public IEnumerable<string> Get()
        {

            var userGrps = new List<string>();
            var user = UserManager.GetUserFromContext();
            var isValidUser = UserManager.IsUserValid(user.UserName, user.Password);

            if (!isValidUser) return userGrps;

            var userToken = UserManager.UserToken();
            userGrps.Add($"Token:{userToken}");
            UserPrincipal userPrinciple = UserPrincipal.FindByIdentity(
                new PrincipalContext(ContextType.Domain, "--your-ad-domain--"), IdentityType.SamAccountName, user.UserName);
            if (userPrinciple != null)
            {
                userGrps.AddRange(from GroupPrincipal @group in userPrinciple.GetGroups() select @group.Name);
            }

            return userGrps;
        }
    }
}

About the author

Naveed Ul-Haq

I am a UK based technical architect. I love working with .NET based CMS, eCommerce solutions, .NET Core, DevOps, and Cloud computing. I am a Certified Episerver CMS developer, MCSD (Microsoft Certified Solution Developer) and MCP in Azure application development. I spend my free time with my family and reading books. You can contact me on [email protected]

View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *