Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ActiveDirectoryMembershipProvider with ASP.Net Identity?

I am trying to learn how to use ASP.Net Identity. My scenario is that I have to authenticate against Active Directory. For that purpose I am trying to use ActiveDirecotoryMembershipProvider. What I have to do is -

  1. Authenticate user/password against Active Directory.
  2. Check whether user is present in my own database.

The way I did it is I configured in my web.config to use ActiveDirectoryMembershipProvider as default membership provider. Then I override PasswordSignInAsync method in my ApplicationSignInManager class (which inherits SignInManager) as follows -

public override Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
{
    var adok = Membership.Provider.ValidateUser(userName, password);
    if (adok)
    {
        var user = UserManager.FindByName(userName);
        if (user == null)
            return Task.FromResult<SignInStatus>(SignInStatus.Failure);
        else
        {
            base.SignInAsync(user, isPersistent, shouldLockout);
            return Task.FromResult<SignInStatus>(SignInStatus.Success);
        }
    }
    else
        return Task.FromResult<SignInStatus>(SignInStatus.Failure);
}

This seems to work. But I think it's not the right way to do it. Can anyone suggest any better way to achieve this?

UPDATE

Here is how I called the above mentioned

var result = await SignInManager.PasswordSignInAsync(username, password, isPersistent: false, shouldLockout: false);
switch (result)
{
    case SignInStatus.Success:
        return RedirectToAction("Index", "Home");
    case SignInStatus.LockedOut:
        return View("Lockout");
    case SignInStatus.Failure:
    default:
        ModelState.AddModelError("", "Invalid login attempt.");
        return View();
}

According to the answers I got, I should not call Membership Validate method inside PasswordSignInAsync. I agree with that. In fact, I think overriding the method is wrong as well.

It was also suggested that I use UserLogins where I would give my AD an provider ID. But the only way I can think of using this is as follows -

IList<UserLoginInfo> loginInfos = await SignInManager.UserManager.GetLoginsAsync(username);
var valid = false;
foreach(var info in loginInfos)
{
    valid = Membership.Providers[info.ProviderKey].ValidateUser(username, password);
    if (valid) break;
}

So, if I want to authenticate an user against multiple Providers I can create provider key for each of them and assign those provider keys to the users. And this code will validate the user against them. But where should I put this code? What convention should I follow?

I am not keen on coding the AD validation myself because I think ActiveDirectoryMembershipProvider can do a better job than my own code. Also for both cases I have to add reference to System.DirectoryServices anyway.

like image 321
th1rdey3 Avatar asked Apr 27 '15 06:04

th1rdey3


1 Answers

You don't want to mix MembershipProviders with identity. What you most likely want to do, is treat logging into ActiveDirectory similar to how identity treats other external logins (like google/facebook).

This basically boils down to storing the AD username as a login:

userManager.AddLogin(<userId>, new UserLoginInfo("ActiveDirectory", "<ADUserName>")

If you only login via AD, then you could indeed override PasswordSignIn to explicitly validate against AD

Otherwise, you'd want this in only the specific login flow for AD, preserving the existing local password/social login functionality.

like image 99
Hao Kung Avatar answered Sep 19 '22 14:09

Hao Kung