3
votes

I am using the standard Simple Membership model for login via forms in my application. I would like to provide the possibility to login via AD as an alternative.

When logging in via AD, the process should be as follows:

  1. Check that AD authenticates the user, but do not use the information for the principal.
  2. Check if any local user exists with the provided Active Directory username (I have a property on my UserProfile model named ActiveDirectoryID).
  3. If it exists, perform a local login using the local username for this UserProfile.

The problem: I cannot retrieve the local password, so in order to login locally after AD authentication, I need to be able to force the login without the password.

I've considered the following strategies:

  • Create an extension method for Websecurity to allow Websecurity.Login(string username)
  • Somehow set the logged in user manually, without implicating Websecurity.

Is this doable / feasible? Is it possible for the framework to create the necessary auth cookie without the plaintext password? And how would I do this?

SOLUTION:

This ended being the correct solution:

    public ActionResult ActiveDirectoryLogin(LoginModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            try
            {
                DirectoryEntry entry = new DirectoryEntry("LDAP://DC=MyIntranet,DC=MyCompany,DC=com", model.UserName, model.Password);
                object NativeObject = entry.NativeObject;

                var internalUser = db.UserProfiles.Where(x => x.ActiveDirectoryID == model.UserName).SingleOrDefault();

                if (internalUser != null)
                {
                    FormsAuthentication.SetAuthCookie(internalUser.UserName, model.RememberMe);
                    return RedirectToLocal(returnUrl);
                }
            }
            catch (DirectoryServicesCOMException)
            {
                // No user existed with the given credentials
            }
            catch (InvalidOperationException)
            {
                // Multiple users existed with the same ActiveDirectoryID in the database. This should never happen!
            }
        }

        return RedirectToAction("Login");
    }
1

1 Answers

2
votes

This is all that the Websecurity.Login method does:

public static bool Login(string userName, string password, bool persistCookie = false)
{
    WebSecurity.VerifyProvider();
    bool flag = Membership.ValidateUser(userName, password);
    if (flag)
    {
        FormsAuthentication.SetAuthCookie(userName, persistCookie);
    }
    return flag;
}

You can write your own method that authenticates against AD and then looks up the user name and the does sets the auth cookie something like:

public static bool MyLogin(string userName, string password, bool persistCookie = false)
{
    bool flag = CheckADUser(userName, password);

    if (flag)
    {
        string mappedUsername = GetMappedUser(userName);
        if(mappedUsername != "")
        {
            FormsAuthentication.SetAuthCookie(userName, persistCookie);
        }
        else
        {
            flag = false;
        }
    }
    return flag;
}

Hope this helps.