Implement Active Directory Authentication in Asp.Net MVC

Implement Active Directory Authentication in ASP.NET MVC 5

You can secure your MVC web application on an Active Directory network by authenticating users directly against their domain credentials.

STEP 1: ACCOUNTCONTROLLER.CS

Replace yourAccountController.cs file with the following:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using Microsoft.AspNet.Identity;

using Microsoft.AspNet.Identity.Owin;

using Microsoft.Owin.Security;

using System.Threading.Tasks;

using TEP.Models.Security;

using TEP.Models.Extensions;

namespace TEP.Controllers

{

public class AccountController : BaseController

{

privateApplicationSignInManager _signInManager;

privateApplicationUserManager _userManager;

//private ApplicationRoleManager _appRoleManager = null;

ApplicationSignInManager SignInManager

{

get

{

return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();

}

}

 

ApplicationUserManager UserManager

{

get

{

return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();

}

}

IAuthenticationManager AuthenticationManager

{

get

{

return HttpContext.GetOwinContext().Authentication;

}

}

public AccountController()

{

}

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)//, ApplicationRoleManager roleManager)

{

this._userManager = userManager;

this._signInManager = signInManager;

//this._appRoleManager = roleManager;

}

[AllowAnonymous]

publicActionResult Login(string returnUrl)

{

if (Request.IsAuthenticated && User != null && User.Identity != null && User.Identity.IsAuthenticated)

{

return RedirectToAction(“Index”, “Home”);

}

ViewBag.ReturnUrl = returnUrl;

return View();

}

[HttpPost]

[AllowAnonymous]

[ValidateAntiForgeryToken]

publicasyncTask<ActionResult> Login(LoginViewModel model, string returnUrl)

{

if (!ModelState.IsValid)

{

return View(model);

}

// This doesn’t count login failures towards account lockout

// To enable password failures to trigger account lockout, change to shouldLockout: true

var result = await SignInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, shouldLockout: false);

switch (result)

{

caseSignInStatus.Success:

var _user = await UserManager.FindByNameAsync(model.Username);

(new Data.DataRepository()).UpdateUser(_user.UserName, _user.DisplayName);

return RedirectToLocal(returnUrl);

caseSignInStatus.LockedOut:

return View(“Lockout”);

caseSignInStatus.RequiresVerification:

return RedirectToAction(“SendCode”, new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });

caseSignInStatus.Failure:

default:

ModelState.AddModelError(“”, “Invalid login attempt.”);

return View(model);

}

}

[HttpPost]

[ValidateAntiForgeryToken]

publicActionResult LogOff()

{

AuthenticationManager.SignOut();

return RedirectToAction(“Index”, “Home”);

}

}

}

STEP 2: LOGINVIEWMODEL.CS

Update your LoginViewModel.cs (or whatever your Account model class is named) to contain only this LoginModel class:

using System;

using System.Collections.Generic;

using System.ComponentModel.DataAnnotations;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace TEP.Models.Security

{

publicclassLoginViewModel

{

[Required]

[Display(Name = “Username”)]

[DataType(DataType.Text)]

public string Username { get; set; }

 

[Required]

[DataType(DataType.Password)]

[Display(Name = “Password”)]

public string Password { get; set; }

 

[Display(Name = “Remember me?”)]

public bool RememberMe { get; set; }

}

}


STEP 3: WEB.CONFIG

Now, update your Web.config file to include these elements.

<applicationSettings>

<TEP.Properties.Settings>

<settingname=LDAPDomainNameserializeAs=String>

<value>pf.net</value>

</setting>

<settingname=LDAPContainerNameserializeAs=String>

<value>DC=pf,DC=net</value>

</setting>

<settingname=LDAPUsernameserializeAs=String>

<value>XXXXXXXXXXX</value>

</setting>

<settingname=LDAPPasswordserializeAs=String>

<value>XXXXXXXXXXX</value>

</setting>

</TEP.Properties.Settings>

</applicationSettings>

STEP 4: Add a Startup.cs File in root folder of the project

It will initialize the LDAP credentials to fetch and check for all the users in AD.

using System;

using System.Threading.Tasks;

using Microsoft.Owin;

using Owin;

[assembly: OwinStartup(typeof(TEP.Startup))]

namespace TEP

{

public partial class Startup

{

publicvoid Configuration(IAppBuilder app)

{

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888

ConfigureAuth(app);

}

}

}

STEP 5: Add a Startup.Auth.cs File in project

In order to Configure user authentication app we need this class which implements ConfigureAuth method :

using Microsoft.AspNet.Identity;

using Microsoft.AspNet.Identity.Owin;

using Microsoft.Owin;

using Microsoft.Owin.Security.Cookies;

using Owin;

using System;

using System.Collections.Generic;

using System.DirectoryServices.AccountManagement;

using System.Linq;

using System.Web;

using TEP.Models.Security;

namespace TEP

{

publicpartialclassStartup

{

// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864

publicvoid ConfigureAuth(IAppBuilder app)

{

//// Configure the db context, user manager and signin manager to use a single instance per request

//app.CreatePerOwinContext(ApplicationDbContext.Create);

app.CreatePerOwinContext(() => newPrincipalContext(ContextType.Domain, Properties.Settings.Default.LDAPDomainName, Properties.Settings.Default.LDAPContainerName, ContextOptions.SimpleBind, Properties.Settings.Default.LDAPUsername, Properties.Settings.Default.LDAPPassword));

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

 

// Configure the sign in cookie

app.UseCookieAuthentication(newCookieAuthenticationOptions

{

AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,

LoginPath = newPathString(“/Account/Login”),

Provider = newCookieAuthenticationProvider

{

// Enables the application to validate the security stamp when the user logs in.

// This is a security feature which is used when you change a password or add an external login to your account.

OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(

validateInterval: TimeSpan.FromMinutes(30),

regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))

}

});

app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

 

// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.

app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));

app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

 

// Uncomment the following lines to enable logging in with third party login providers

//app.UseMicrosoftAccountAuthentication(

// clientId: “”,

// clientSecret: “”);

 

//app.UseTwitterAuthentication(

// consumerKey: “”,

// consumerSecret: “”);

 

//app.UseFacebookAuthentication(

// appId: “”,

// appSecret: “”);

 

//app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()

//{

// ClientId = “”,

// ClientSecret = “”

//});

}

}

}

 

STEP 6: IdentityConfig.cs Changes in App_Start Folder

using Microsoft.AspNet.Identity;

using Microsoft.AspNet.Identity.EntityFramework;

using Microsoft.AspNet.Identity.Owin;

using Microsoft.Owin;

using Microsoft.Owin.Security;

using System;

using System.Collections.Generic;

using System.DirectoryServices.AccountManagement;

using System.Linq;

using System.Security.Claims;

using System.Threading.Tasks;

using TEP.Models.Security;

using System.Net.Mail;

using System.Net;

using System.IO;

using TEP.Core;

namespace TEP

{

publicclassEmailService : IIdentityMessageService

{

publicTask SendAsync(IdentityMessage message)

{

// Plug in your email service here to send an email.

returnTask.FromResult(0);

}

 

}

 

publicclassSmsService : IIdentityMessageService

{

publicTask SendAsync(IdentityMessage message)

{

// Plug in your SMS service here to send a text message.

returnTask.FromResult(0);

}

}

 

// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.

publicclassApplicationUserManager : UserManager<ApplicationUser>

{

privatereadonlyPrincipalContext _context;

 

public ApplicationUserManager(IUserStore<ApplicationUser> store, PrincipalContext context)

: base(store)

{

this._context = context;

}

 

publicoverrideasyncTask<ApplicationUser> FindByNameAsync(string userName)

{

var _user = awaitTask.FromResult<UserPrincipal>(UserPrincipal.FindByIdentity(_context, IdentityType.SamAccountName, userName));

if (_user == null)

{

returnawaitTask.FromResult<ApplicationUser>(null);

}

returnawaitTask.FromResult<ApplicationUser>(newApplicationUser

{

UserName = _user.SamAccountName,

DisplayName = GetDisplaynameFromCommaSeperatedName(_user.DisplayName),

Id = _user.Sid.Value,

});

}

 

publicoverrideasyncTask<ApplicationUser> FindByIdAsync(string userId)

{

var _user = awaitTask.FromResult<UserPrincipal>(UserPrincipal.FindByIdentity(_context, IdentityType.Sid, userId));

if (_user == null)

{

returnawaitTask.FromResult<ApplicationUser>(null);

}

returnawaitTask.FromResult<ApplicationUser>(newApplicationUser

{

UserName = _user.UserPrincipalName,

DisplayName = GetDisplaynameFromCommaSeperatedName(_user.DisplayName),

Id = _user.Sid.Value,

SecurityStamp = Guid.NewGuid().ToString()

});

}

 

publicoverrideasyncTask<IList<Claim>> GetClaimsAsync(string userId)

{

var _user = awaitTask.FromResult<UserPrincipal>(UserPrincipal.FindByIdentity(_context, IdentityType.Sid, userId));

if (_user == null)

{

returnawaitTask.FromResult<IList<Claim>>(newList<Claim>());

}

returnawaitTask.FromResult<IList<Claim>>(_user.GetGroups()

.Select(result => result asGroupPrincipal)

.Where(gR => gR != null && gR.Name != null && (gR.IsSecurityGroup.HasValue) && (gR.IsSecurityGroup.Value))

.Select(gR => newClaim(ClaimTypes.Role, gR.Name)).ToList());

}

 

publicoverrideasyncTask<IList<string>> GetRolesAsync(string userId)

{

var _user = awaitTask.FromResult<UserPrincipal>(UserPrincipal.FindByIdentity(_context, IdentityType.Sid, userId));

if (_user == null)

{

returnawaitTask.FromResult<IList<string>>(newList<string>());

}

returnawaitTask.FromResult<IList<string>>(_user.GetGroups()

.Select(result => result asGroupPrincipal)

.Where(group => (group != null) && (group.IsSecurityGroup.HasValue) && (group.IsSecurityGroup.Value))

.Select(gR => gR.Name).ToList());

}

 

publicoverrideasyncTask<bool> CheckPasswordAsync(ApplicationUser user, string password)

{

//return await Task.FromResult<bool>(true);

returnawaitTask.FromResult(_context.ValidateCredentials(user.UserName, password, ContextOptions.Negotiate));

}

 

publicoverrideTask<bool> IsInRoleAsync(string userId, string role)

{

 

returnbase.IsInRoleAsync(userId, role);

}

 

#region Not Implemented (throws exception)

publicoverrideTask<IList<UserLoginInfo>> GetLoginsAsync(string userId)

{

thrownewNotImplementedException();

//return base.GetLoginsAsync(userId);

}

 

publicoverrideTask<ApplicationUser> FindAsync(string userName, string password)

{

thrownewNotImplementedException();

//return base.FindAsync(userName, password);

}

 

publicoverrideTask<ApplicationUser> FindAsync(UserLoginInfo login)

{

thrownewNotImplementedException();

//return base.FindAsync(login);

}

 

protectedoverrideTask<bool> VerifyPasswordAsync(IUserPasswordStore<ApplicationUser, string> store, ApplicationUser user, string password)

{

thrownewNotImplementedException();

//return base.VerifyPasswordAsync(store, user, password);

}

#endregion

 

publicasyncTask<IList<ApplicationUser>> GetAllEvaluatorAdministrators()

{

using (var grp = GroupPrincipal.FindByIdentity(_context, IdentityType.SamAccountName, “_SG Transcript Evaluator Administrators”))

{

if (grp == null)

{

returnawaitTask.FromResult<IList<ApplicationUser>>(newList<ApplicationUser>());

}

returnawaitTask.FromResult<IList<ApplicationUser>>(grp.GetMembers(false).Select(pL => newApplicationUser

{

UserName = pL.UserPrincipalName,

DisplayName = GetDisplaynameFromCommaSeperatedName(pL.DisplayName),

Id = pL.Sid.Value,

}).ToList());

}

}

 

publicasyncTask<IList<ApplicationUser>> GetAllEvaluators()

{

using (var grp = GroupPrincipal.FindByIdentity(_context, IdentityType.SamAccountName, “_SG Transcript Evaluator”))

{

if (grp == null)

{

returnawaitTask.FromResult<IList<ApplicationUser>>(newList<ApplicationUser>());

}

returnawaitTask.FromResult<IList<ApplicationUser>>(grp.GetMembers(false).Select(pL => newApplicationUser

{

UserName = pL.SamAccountName,// pL.UserPrincipalName, As it is displaying user email address

DisplayName = GetDisplaynameFromCommaSeperatedName(pL.DisplayName),

Id = pL.Sid.Value,

}).ToList());

}

}

 

publicasyncTask<IList<ApplicationUser>> GetAllB2BEntryOperator()

{

using (var grp = GroupPrincipal.FindByIdentity(_context, IdentityType.SamAccountName, “_SG B2B Order Entry”))

{

if (grp == null)

{

returnawaitTask.FromResult<IList<ApplicationUser>>(newList<ApplicationUser>());

}

returnawaitTask.FromResult<IList<ApplicationUser>>(grp.GetMembers(false).Select(pL => newApplicationUser

{

UserName = pL.UserPrincipalName,

DisplayName = GetDisplaynameFromCommaSeperatedName(pL.DisplayName),

Id = pL.Sid.Value,

}).ToList());

}

}

 

publicstaticApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)

{

var manager = newApplicationUserManager(newUserStore<ApplicationUser>(), context.Get<PrincipalContext>());

// Configure validation logic for usernames

manager.UserValidator = newUserValidator<ApplicationUser>(manager)

{

AllowOnlyAlphanumericUserNames = false,

RequireUniqueEmail = false

};

 

// Configure validation logic for passwords

manager.PasswordValidator = newPasswordValidator

{

RequiredLength = 6,

RequireNonLetterOrDigit = true,

RequireDigit = true,

RequireLowercase = true,

RequireUppercase = true,

};

 

// Configure user lockout defaults

manager.UserLockoutEnabledByDefault = false;

 

var dataProtectionProvider = options.DataProtectionProvider;

if (dataProtectionProvider != null)

{

manager.UserTokenProvider =

newDataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create(“ASP.NET Identity”));

}

return manager;

}

 

string GetDisplaynameFromCommaSeperatedName(string ADDisplayName)

{

if (!ADDisplayName.Contains(“,”))

return ADDisplayName.Trim();

returnstring.Join(” “, ADDisplayName.Split(‘,’).Reverse()).Trim();

}

}

 

// Configure the application sign-in manager which is used in this application.

publicclassApplicationSignInManager : SignInManager<ApplicationUser, string>

{

public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)

: base(userManager, authenticationManager)

{

}

 

publicoverrideTask<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)

{

return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);

}

 

publicstaticApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)

{

returnnewApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);

}

}

}

 

STEP 7: Add Customized methods in BaseController.cs

using System;

using System.Collections.Generic;

using System.DirectoryServices.AccountManagement;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using TEP.Models.Security;

using Microsoft.AspNet.Identity.Owin;

using System.Threading.Tasks;

using TEP.Models.Extensions;

 

namespace TEP.Controllers

{

publicclassBaseController : Controller

{

protectedasyncTask<string> GetUserDisplayName(string userName)

{

var _appUser = await HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindByNameAsync(userName);

if (_appUser != null)

{

return _appUser.DisplayName;

}

returnstring.Empty;

}

 

}

}

 

STEP 8: Add IdentityModel.cs File to extend the functionality of IdentityUser in our own class.

using Microsoft.AspNet.Identity;

using Microsoft.AspNet.Identity.EntityFramework;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Security.Claims;

using System.Text;

using System.Threading.Tasks;

 

namespace TEP.Models.Security

{

publicclassApplicationUser : IdentityUser

{

publicstring DisplayName { get; set; }

 

publicasyncTask<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)

{

var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

// Add custom user claims here

userIdentity.AddClaim(newClaim(ClaimTypes.GivenName, DisplayName));

return userIdentity;

}

}

}

 

STEP 9: Add IdentityExtensions.cs extension class to get customized details easily.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Security.Claims;

using System.Security.Principal;

using Microsoft.Owin.Security;

using System.Text;

using System.Threading.Tasks;

using System.Web;

 

namespace TEP.Models.Extensions

{

publicstaticclassIdentityExtensions

{

publicstaticstring GetGivenName(thisIIdentity identity)

{

if (identity == null)

returnnull;

 

return (identity asClaimsIdentity).FirstOrNull(ClaimTypes.GivenName);

}

 

internalstaticstring FirstOrNull(thisClaimsIdentity identity, string claimType)

{

var val = identity.FindFirst(claimType);

return val == null ? identity.Name : val.Value;

}

 

publicstaticvoid UpdateClaim(thisIIdentity identity, string newRole)

{

var cIdentity = identity asClaimsIdentity;

if (cIdentity == null)

return;

// check for existing claim and remove it

var roles = cIdentity.FindAll(ClaimTypes.Role);

foreach (var claim in roles)

{

if (claim != null)

cIdentity.RemoveClaim(claim);

}

 

// add new claim

var AuthenticationManager = HttpContext.Current.GetOwinContext().Authentication;

cIdentity.AddClaim(newClaim(ClaimTypes.Role, newRole));

AuthenticationManager.AuthenticationResponseGrant = newAuthenticationResponseGrant(

newClaimsPrincipal(cIdentity),

newAuthenticationProperties { IsPersistent = true }

);

}

}

}

Hence, after doing all the above changes your project should work for LDAP authentication with no issue. Hope, it will help you understand how to implement the Active Directory Authentication in MVC.

 

About the Author

Ranjan Jha

Ranjan Jha

Related Posts

X