Form Authenticaiton with AD Backend

I’ve seen quite a few questions in forums about how to use Forms Authentication with an Active Directory back end.
While the authentication piece is fairly straight forward using active directory groups as the role management system for your application is a little trickier.
The basic authentication mechanism is an Active Directory helper class that can take a user name and password and validate that against AD.

....///


public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + @"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
try
{
// Bind to the Active Directory Object
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
// Update the new path to the user in the directory
_path = result.Path;
_filterAttribute = (string)result.Properties["cn"][0];

}
catch (Exception ex)
{

throw new Exception("Invalid username or password." + ex.Message.ToString());
}
return true;
}
///…

Call that from something like this.

if (true == ADAuth.IsAuthenticated(this.DomainName, userName, password))
{
status = true;
// Retrieve the user's groups
string groups = GetGroups(userName, password, true);

// Retrieve the user's first and last name;
string fname = ADAuth.GetFirstName(this.DomainName, userName, password);
string lname = ADAuth.GetLastName(this.DomainName, userName, password);


HttpContext.Current.Session["fname"] = fname;
HttpContext.Current.Session["lname"] = lname;
HttpContext.Current.Session["username"] = userName;
// Create the authetication ticket
// This is where we add a key to the authentication ticket so that we can get the groups out of the cache on the server.

FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(20), false, userName + "Roles");

// Now encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

// Create a cookie and add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);

// Add the cookie to the outgoing cookies collection.
HttpContext.Current.Response.Cookies.Add(authCookie);
}
}
catch (Exception ex)
{
//Should do some logging here.
throw new Exception(ex.Message);
}
return status;
}

Now in your Global.asax file, you need to generate a new idenity for the user so that we can use the AD groups to secure our application:


protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{

// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];

if (null == authCookie)
{
// There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
// Log exception details (omitted for simplicity)
throw new Exception("Error Reading cookie");
}

if (null == authTicket)
{
// Cookie failed to decrypt.
return;
}
// When the ticket was created, the UserData property was assigned a
// pipe delimited string of group names.

String cacheGroups;
String[] groups = null;
if (Context.Cache.Get(authTicket.UserData) != null)
{
cacheGroups = (String)Context.Cache.Get(authTicket.UserData);
groups = cacheGroups.Split(new char[] { '' });
// Create an Identity object
GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");

// This principal will flow throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, groups);

// Attach the new principal object to the current HttpContext object
Context.User = principal;

}
else
{
// Response.Redirect(FormsAuthentication.LoginUrl);
}


}


Now you can set your Authenticaiton in web.config to Forms Authentication. You can also use the since your user has an identity with the roles from AD.

0 comments: