Thursday, August 4, 2011

Validate User Credentials on Active Directory (LDAP) Using C#

Objectives:-
  • AD account locked out
  • AD account password expired
  • AD account username/password correct
  • AD account disabled
I am using msDS-User-Account-Control-Computed in my DirectorySearcher. This method will return Boolean value true or false.


// This method is Authenticate Active Directory User.

public bool AuthenticateActiveDirectoryUser(string userName, string password)
{
bool isUserAuthenticated = false;
const int UF_DISABLED = 0x0002;
const int UF_LOCKED = 0x0010;
const int UF_EXPIRED = 0x800000;
try
{

DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://myserver.domain.com", userName, password,
AuthenticationTypes.Secure);
DirectorySearcher oSearcher = new DirectorySearcher(directoryEntry, "SAMAccountName=" + userName,
new string[]
{
"userAccountControl",
"msDS-User-Account-Control-Computed"
},
SearchScope.Subtree);
SearchResult result = oSearcher.FindOne();
if (result == null)
{
//"User not identified in AD";
}
else if (Convert.ToBoolean(Convert.ToInt32(result.Properties["userAccountControl"][0]) & UF_DISABLED))
{
//"Account has been disabled. Please contact administrator for more details";
}
else if (result.Properties.Contains("msDS-User-Account-Control-Computed") &&
Convert.ToBoolean(Convert.ToInt32(result.Properties["msDS-User-Account-Control-Computed"][0]) &
UF_LOCKED))
{
//"Account locked-out. Please contact administrator for more details";
}
else if (Convert.ToBoolean(Convert.ToInt32(result.Properties["userAccountControl"][0]) & UF_EXPIRED))
{
//"Password has expired. Please change your password before attempting to login again.";
}
else
{
//Number of days left based on user last changed password.
numberOfDaysLeft = CalculateNumberOfDaysLeftForPasswordExpiry(result, directoryEntry, userName);
isUserAuthenticated = true;
}

return isUserAuthenticated;
}
catch
{
//User validation returned exception. Now check for Password expired or Account locked out.
//Use the admin account (any account has LDAP query rights) to check for the above condition.

DirectoryEntry directoryEntryWithAdmin = new DirectoryEntry("LDAP://myserver.domain.com", Utility.GetAdminUser(), Utility.GetAdminPassword());
DirectorySearcher directorySearch = new DirectorySearcher(directoryEntryWithAdmin, "SAMAccountName=" + userName,
new string[]
{
"userAccountControl",
"msDS-User-Account-Control-Computed"
}
, SearchScope.Subtree);
SearchResult searchResult = directorySearch.FindOne();

if (searchResult == null)
{
//"User not identified in AD";
}
else if (Convert.ToBoolean(Convert.ToInt32(searchResult.Properties["userAccountControl"][0]) & UF_DISABLED))
{
//"Account has been disabled. Please contact administrator for more details";
}
else if (searchResult.Properties.Contains("msDS-User-Account-Control-Computed") &&
Convert.ToBoolean(Convert.ToInt32(searchResult.Properties["msDS-User-Account-Control-Computed"][0]) &
UF_LOCKED))
{
//"Account locked-out. Please contact administrator for more details";
}
else if (Convert.ToBoolean(Convert.ToInt32(searchResult.Properties["msDS-User-Account-Control-Computed"][0]) & UF_EXPIRED))
{
//"Password has expired. Please change your password before attempting to login again.";
}
else
{
//"Username and/or Password incorrect"
}
return false;
}
}







// This Method will return days left for password expiration.
private int? CalculateNumberOfDaysLeftForPasswordExpiry(SearchResult result, DirectoryEntry directoryEntry, string userName)
{
TimeSpan timeSpan;
int? nofDays = null;

if (result != null)
{
DirectorySearcher oSearcher = new DirectorySearcher(directoryEntry);

oSearcher.Filter = "(SAMAccountName=" + userName + ")";
oSearcher.PropertiesToLoad.Add("sn");
oSearcher.PropertiesToLoad.Add("pwdLastSet");

SearchResult searchResult = oSearcher.FindOne();

searchResult.GetDirectoryEntry();

if (searchResult.Properties["pwdLastSet"].Count > 0)
{
Int64 acctPwdChange = 0;

acctPwdChange = (Int64)searchResult.Properties["pwdLastSet"][0];
DateTime dtNow = DateTime.Now;
DateTime dtAcctPwdChange = DateTime.FromFileTime(acctPwdChange).AddDays(passwordExpirationDays);

timeSpan = dtAcctPwdChange - dtNow;
nofDays = timeSpan.Days;
}
}

return nofDays;
}