How to call and count variable from one method to another? - c#

Hi I would like to get and count all the invalid accounts from the method valSAM using my other method GetSAM.
I've managed to use the count property to get the total number of accounts in the database from the GetSAM method. (lines 7- 23, GetSAM) The problem is, I do not know how to replicate that and call/ count the total number of invalid accounts from the valSAM method. (lines 20- 39, valSAM)
I have a hunch that I have to somehow call the invalid accounts to the GetSAM method before I am able to call them as well but I do not know how to implement it. Can anyone please advise me on this?
GetSAM method:
//Get SAMAccount
private static string GetSAM(string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
string ldapFilter = "(&(objectclass=user)(objectcategory=person))";
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
string readOutput;
List<string> list = new List<string>();
StringBuilder builder = new StringBuilder();
using (DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry))
{
string samAccountName;
directorySearcher.Filter = ldapFilter;
directorySearcher.SearchScope = SearchScope.Subtree;
directorySearcher.PageSize = 1000;
using (SearchResultCollection searchResultCollection = directorySearcher.FindAll())
{
foreach (SearchResult result in searchResultCollection)
{
samAccountName = result.Properties["sAMAccountName"][0].ToString();
valSAM(samAccountName, ldapAddress, serviceAccountUserName, serviceAccountPassword);
list.Add(samAccountName);
} //end of foreach
// Count all accounts
int totalAccounts = list.Count;
Console.WriteLine("Found " + totalAccounts + " accounts. Query in " + ldapAddress + " has finished.\n");
Console.WriteLine("Press [enter] to continue.\n");
readOutput = Console.ReadLine();
}//SearchResultCollection will be disposed here
}
return readOutput;
}
valSAM method:
//Validate SAMAccount
private static string valSAM(string samAccountName, string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
StringBuilder builder = new StringBuilder();
//create instance fo the directory searcher
DirectorySearcher desearch = new DirectorySearcher(directoryEntry);
//set the search filter
desearch.Filter = "(&(sAMAccountName=" + samAccountName + ")(objectcategory=user))";
//find the first instance
SearchResult results = desearch.FindOne();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldapAddress))
{
//if users are present in database
if (results != null)
{
//Check if account is activated
bool isAccountActived = IsActive(results.GetDirectoryEntry());
//Check if account is expired or locked
bool isAccountLocked = IsAccountLockOrExpired(results.GetDirectoryEntry());
//account is invalid
if ((isAccountActived != true) || (isAccountLocked))
{
builder.Append("User account " + samAccountName + " is invalid. ");
if ((isAccountActived != true) && (isAccountLocked))
{
builder.Append("Account is inactive and locked or expired.").Append('\n'); ;
} else if (isAccountActived != true)
{
builder.Append("Account is inactive.").Append('\n'); ;
}
else if (isAccountLocked)
{
builder.Append("Account is locked or has expired.").Append('\n'); ;
}
else
{
builder.Append("Unknown reason for status. Contact admin for help.").Append('\n'); ;
}
}
//account is valid
if ((isAccountActived) && (isAccountLocked != true))
{
builder.Append("User account " + samAccountName + " is valid.").Append('\n');
}
}
else Console.WriteLine("Nothing found.");
Console.WriteLine(builder);
}
return builder.ToString();
}
Updated valSAM:
//Validate SAMAccount
private static bool valSAM(string samAccountName, string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
StringBuilder builder = new StringBuilder();
bool accountValidation = true;
//create instance fo the directory searcher
DirectorySearcher desearch = new DirectorySearcher(directoryEntry);
//set the search filter
desearch.Filter = "(&(sAMAccountName=" + samAccountName + ")(objectcategory=user))";
//find the first instance
SearchResult results = desearch.FindOne();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldapAddress))
{
//if users are present in database
if (results != null)
{
//Check if account is activated
bool isAccountActived = IsActive(results.GetDirectoryEntry());
//Check if account is expired or locked
bool isAccountLocked = IsAccountLockOrExpired(results.GetDirectoryEntry());
accountValidation = ((isAccountActived != true) || (isAccountLocked));
//account is invalid
if (accountValidation)
{
builder.Append("User account " + samAccountName + " is invalid. ");
if ((isAccountActived != true) && (isAccountLocked))
{
builder.Append("Account is inactive and locked or expired.").Append('\n'); ;
} else if (isAccountActived != true)
{
builder.Append("Account is inactive.").Append('\n'); ;
}
else if (isAccountLocked)
{
builder.Append("Account is locked or has expired.").Append('\n'); ;
}
else
{
builder.Append("Unknown reason for status. Contact admin for help.").Append('\n'); ;
}
return false;
}
//account is valid
if ((isAccountActived) && (isAccountLocked != true))
{
builder.Append("User account " + samAccountName + " is valid.").Append('\n');
return true;
}
}
else Console.WriteLine("Nothing found.");
Console.WriteLine(builder);
Console.ReadLine();
}//end of using
return accountValidation;
}
Thanks a million :)
Update: Now I have a new problem after updating my valSAM- I am unable to print out the accounts when I return the boolean accountValidation instead of builder.ToString().

You are returning the call before you do Console.WriteLine, do something like this:
private static bool valSAM(string samAccountName, string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
StringBuilder builder = new StringBuilder();
bool accountValidation = true;
//create instance fo the directory searcher
DirectorySearcher desearch = new DirectorySearcher(directoryEntry);
//set the search filter
desearch.Filter = "(&(sAMAccountName=" + samAccountName + ")(objectcategory=user))";
//find the first instance
SearchResult results = desearch.FindOne();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldapAddress))
{
//if users are present in database
if (results != null)
{
//Check if account is activated
bool isAccountActived = IsActive(results.GetDirectoryEntry());
//Check if account is expired or locked
bool isAccountLocked = IsAccountLockOrExpired(results.GetDirectoryEntry());
accountValidation = ((isAccountActived != true) || (isAccountLocked));
//account is invalid
if (accountValidation)
{
builder.Append("User account " + samAccountName + " is invalid. ");
if ((isAccountActived != true) && (isAccountLocked))
{
builder.Append("Account is inactive and locked or expired.").Append('\n'); ;
} else if (isAccountActived != true)
{
builder.Append("Account is inactive.").Append('\n'); ;
}
else if (isAccountLocked)
{
builder.Append("Account is locked or has expired.").Append('\n'); ;
}
else
{
builder.Append("Unknown reason for status. Contact admin for help.").Append('\n'); ;
}
accountValidation = false;
}
//account is valid
if ((isAccountActived) && (isAccountLocked != true))
{
builder.Append("User account " + samAccountName + " is valid.").Append('\n');
accountValidation = true;
}
}
else Console.WriteLine("Nothing found.");
Console.WriteLine(builder);
Console.ReadLine();
}//end of using
return accountValidation;
}
So now, you can assign the value and have one return point and can also print the names. As for keeping track of counts in main function you can place valSAM call in
if(valSAM(samAccountName, ldapAddress, serviceAccountUserName, serviceAccountPassword))
{
invalidAccountCount++;
}
And needless to say, you have to initialize invalidAccountCount outside the loop.

Related

How to get the GUID of the current user?

I want to get the Guid of the current user.
Here is my code:
System.Security.Principal.IPrincipal User = System.Web.HttpContext.Current.User;
String username = User.Identity.Name.ToString();
System.IO.File.AppendAllText(Server.MapPath("~/logtext.txt"), "username " + username + Environment.NewLine);
if (username != "")
{
if (User.Identity.IsAuthenticated)
{
MembershipUser user = Membership.GetUser(User.Identity.Name);
if (user != null)
{
//get the GUID
Guid guid = (Guid)user.ProviderUserKey;
System.IO.File.AppendAllText(Server.MapPath("~/logtext.txt"), "Authenticated: " + User.Identity.Name + Environment.NewLine);
}
}
}
The MembershipUser return null although the user is authenticated.
I also tried to use:
DirectoryEntry entry = new DirectoryEntry();
//entry.Username = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
entry.Username = User.Identity.Name.ToString();
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(objectclass=user)";
But it does not work without entry.Password (I don't have it).

Can't remove items from List with remove()

Hi I would like to remove account names by using a foreach in method readInput that sends the accounts to method DisableADUser that would disable the accounts and remove the name from the global List invalidAccounts (whole code line 7) if the operation is successful.
I have tried using the Remove method and placing it in both the if and else condition in the DisableADUser method but it does not work. How should I go about resolving this? Thanks in advance. :)
readInput method (lines 1- 13)
//Read user input
private static string readInput(string Input)
{
string input = string.Empty;
switch (Input)
{
case "disable":
invalidAccount.ForEach(delegate(String samAccountName)
{
Console.WriteLine('\n' + samAccountName);
//disable inactive accounts
DisableADUser(samAccountName);
});
//count number of invalid accounts
int invalidAccounts = invalidAccount.Count;
Console.WriteLine("\nExecution has completed. ");
invalidAccount.Clear();
Console.WriteLine("Press [enter] to continue.\n");
input = Console.ReadLine();
break;
case "query":
Console.WriteLine("\nQuery for expiry has finished.\n");
Console.WriteLine("Press [enter] to continue.\n");
input = Console.ReadLine();
break;
case "exit":
//leave console
Environment.Exit(2);
break;
default:
throw new Exception("Invalid command entered.");
}
return input;
}
disableADUser (lines 1- 15)
//disable invalid accounts
private static void DisableADUser(string samAccountName)
{
try
{
PrincipalContext principalContext = new PrincipalContext(ContextType.Domain);
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity
(principalContext, samAccountName);
userPrincipal.Enabled = false;
userPrincipal.Save();
if (userPrincipal.Enabled != true)
{
Console.WriteLine("Account has been disabled successfully");
//remove from list invalidAccounts
invalidAccount.Remove(samAccountName);
}
else
{
Console.Write("Unable to disable account");
//invalidAccount.Remove(samAccountName);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
If needed, I've included my entire code as well.
namespace ConsoleApplication2
{
class Program
{
const int UF_LOCKOUT = 0x0010;
const int UF_PASSWORD_EXPIRED = 0x800000;
private static List<string> invalidAccount = new List<string>();
static void Main(string[] args)
{
string line;
Console.WriteLine("Welcome to account validator V1.1.\n");
do
{
Console.WriteLine("Please enter service account username, password \nand desired ldap address to proceed.\n\n");
//pass username to GetInput method
String serviceAccountUserName = GetInput("Username");
//pass password to GetInput method
String serviceAccountPassword = GetInput("Password");
//pass ldap address to GetInput method
String ldapAddress = GetInput("Ldap address");
try
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldapAddress))
{
bool isValid = false;
// validate the credentials
isValid = pc.ValidateCredentials(serviceAccountUserName, serviceAccountPassword);
if (isValid)
{
Console.WriteLine("\nQuerying for users from domain " + ldapAddress + " now.\n\n");
//pass login details to GetSAM method
GetSAM(ldapAddress, serviceAccountUserName, serviceAccountPassword);
Console.WriteLine("\nEnter exit to leave.\n");
Console.WriteLine("Enter disable to disable the invalid accounts.\n");
Console.WriteLine("Enter query to find the expiry date of valid accounts.\n");
string Input = Console.ReadLine();
//pass input to readInput method
readInput(Input);
Console.WriteLine("\nEnter exit to leave.");
Console.WriteLine("Press [enter] to query database.");
}//end of if statement for validate credentials
else
{
Console.WriteLine("\nInvalid login credentials.\n");
Console.WriteLine("Press [enter] and enter exit to leave.");
Console.WriteLine("\nPress [enter] [enter] to try again.\n");
Console.ReadLine();
}//end of else statement for validate credentials
}//end of using
}//end of try
catch (Exception e)
{
Console.WriteLine("\nlogin attempt has failed. See exception for more information. ");
throw new Exception("Log in attempt has failed." + " Exception caught:\n\n" + e.ToString());
}//end of catch
}//end of do
while ((line = Console.ReadLine()) != "exit");
//Thread.Sleep(60000);
} //end of main
//Read user input
private static string readInput(string Input)
{
string input = string.Empty;
switch (Input)
{
case "disable":
invalidAccount.ForEach(delegate(String samAccountName)
{
Console.WriteLine('\n' + samAccountName);
//disable inactive accounts
DisableADUser(samAccountName);
});
//count number of invalid accounts
int invalidAccounts = invalidAccount.Count;
Console.WriteLine("\nExecution has completed. " + invalidAccounts + " invalid accounts have been disabled.");
invalidAccount.Clear();
Console.WriteLine("Press [enter] to continue.\n");
input = Console.ReadLine();
break;
case "query":
Console.WriteLine("\nQuery for expiry has finished.\n");
Console.WriteLine("Press [enter] to continue.\n");
input = Console.ReadLine();
break;
case "exit":
//leave console
Environment.Exit(2);
break;
default:
throw new Exception("Invalid command entered. Please enter command again.");
}
return input;
}
// find password expiry date
//Get SAMAccount
private static string GetSAM(string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string readOutput;
int countAll = 0;
string ldapPath = "LDAP://" + ldapAddress;
string ldapFilter = "(&(objectclass=user)(objectcategory=person))";
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
using (DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry))
{
string samAccountName;
directorySearcher.Filter = ldapFilter;
directorySearcher.SearchScope = SearchScope.Subtree;
directorySearcher.PageSize = 1000;
using (SearchResultCollection searchResultCollection = directorySearcher.FindAll())
{
foreach (SearchResult result in searchResultCollection)
{
samAccountName = result.Properties["sAMAccountName"][0].ToString();
//validate accounts by passing details into valSAM method
if (valSAM(samAccountName, ldapAddress, serviceAccountUserName, serviceAccountPassword) != true)
{
//add invalid account to list invalidAccount
invalidAccount.Add(samAccountName);
}
//count all accounts
countAll++;
} //end of foreach
// Count all invalid accounts
int invalidAccounts = invalidAccount.Count;
Console.WriteLine("\nFound " + invalidAccounts + " invalid accounts out of " + countAll + " user accounts.\n");
Console.WriteLine("Query in " + ldapAddress + " has finished.");
Console.WriteLine("Press [enter] to continue.\n");
readOutput = Console.ReadLine();
}//SearchResultCollection will be disposed here
}
return readOutput;
}
//Validate SAMAccount
private static bool valSAM(string samAccountName, string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
StringBuilder builder = new StringBuilder();
bool accountValidation = false;
//create instance fo the directory searcher
DirectorySearcher desearch = new DirectorySearcher(directoryEntry);
//set the search filter
desearch.Filter = "(&(sAMAccountName=" + samAccountName + ")(objectcategory=user))";
//find the first instance
SearchResult results = desearch.FindOne();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldapAddress))
{
//if users are present in database
if (results != null)
{
//Check if account is activated
bool isAccountActived = IsActive(results.GetDirectoryEntry());
//Check if account is expired or locked
bool isAccountLocked = IsAccountLockOrExpired(results.GetDirectoryEntry());
accountValidation = ((isAccountActived != true) || (isAccountLocked));
//account is invalid
if (accountValidation)
{
builder.Append("User account " + samAccountName + " is invalid. ");
if ((isAccountActived != true) && (isAccountLocked))
{
builder.AppendLine("Account is inactive and locked or expired.");
} else if (isAccountActived != true)
{
builder.AppendLine("Account is inactive.");
}
else if (isAccountLocked)
{
builder.AppendLine("Account is locked or has expired.") ;
}
else
{
builder.AppendLine("Unknown reason. Contact admin for help.");
}
accountValidation = false;
}
//account is valid
if ((isAccountActived) && (isAccountLocked != true))
{
builder.AppendLine("User account " + samAccountName + " is valid.");
accountValidation = true;
}
}
else Console.WriteLine("No users found.");
//print only invalid accounts
if (!accountValidation)
{
//prevent printing of empty lines
if (builder.Length > 0)
{
Console.WriteLine(builder);
}
}
}//end of using
return accountValidation;
}
//Prevent empty user input
private static string GetInput(string Prompt)
{
string Result = string.Empty;
do
{
Console.Write(Prompt + ": ");
Result = Console.ReadLine();
if (string.IsNullOrEmpty(Result)) Console.WriteLine("Empty input, please try again.\n");
}
while (!(!string.IsNullOrEmpty(Result)));
return Result;
}
//check if account is active
static private bool IsActive(DirectoryEntry de)
{
if (de.NativeGuid == null) return false;
int flags = (int)de.Properties["userAccountControl"].Value;
return !Convert.ToBoolean(flags & 0x0002);
}
//check if account is locked or expired
static private bool IsAccountLockOrExpired(DirectoryEntry de)
{
string attribName = "msDS-User-Account-Control-Computed";
de.RefreshCache(new string[] { attribName });
int userFlags = (int)de.Properties[attribName].Value;
return userFlags == UF_LOCKOUT || userFlags == UF_PASSWORD_EXPIRED;
}
//disable invalid accounts
private static void DisableADUser(string samAccountName)
{
try
{
PrincipalContext principalContext = new PrincipalContext(ContextType.Domain);
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity
(principalContext, samAccountName);
userPrincipal.Enabled = false;
userPrincipal.Save();
if (userPrincipal.Enabled != true)
{
Console.WriteLine("User " + samAccountName + "'s account has been disabled successfully");
//remove from list invalidAccounts
invalidAccount.Remove(samAccountName);
}
else
{
Console.Write("Unable to disable account");
//invalidAccount.Remove(samAccountName);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
You can't Remove items from the list you are iterating. It messes with the enumerator to delete things out from under it. You need to copy the items you want to keep to another list instead, and then copy it back if necessary; or create a list of items you want to remove, and remove them all at once at the end.
This has a discussion of various methods: Intelligent way of removing items from a List<T> while enumerating in C#

LDAP authentication on server

I need to authenticate LDAP user in c# with input username and password.
DirectoryEntry entry =
new DirectoryEntry("LDAP://" + ServerName + "/OU=managed users,OU=KK”, + LDAPDomain, AdminUsername, Adminpassword);
DirectorySearcher search = new DirectorySearcher(entry);
search.SearchScope = SearchScope.Subtree;
search.Filter = "(|(&(objectCategory=person)(objectClass=user)(name=" + inputUsername + ")))";
search.PropertiesToLoad.Add("cn");
var searchresult = search.FindAll();
And here I get the required record (could see the details)
However when I try to authenticate it using below code, it always said authentication failure
if (searchresult != null)
{
foreach (SearchResult sr in searchresult)
{
DirectoryEntry myuser = sr.GetDirectoryEntry();
myuser.Password = inputPassword;
try
{
object nativeObject = myuser.NativeObject;
if (nativeObject != null)
isValid = true;
}
catch(excecption ex)
{
isValid = false;
//Error message
}
}
}
It always result in catch block with error message
Logon failure: unknown user name or bad password. failure: unknown user name or bad password.
I'm sure that the given password is correct.
Please suggest.
As suggest by Saad,
I changed by code
public static bool IsAuthenticated()
{
var isValid = false;
string adServer = ConfigurationManager.AppSettings["Server"];
string adDomain = ConfigurationManager.AppSettings["Domain"];
string adminUsername = ConfigurationManager.AppSettings["AdminUsername"];
string adminpassword = ConfigurationManager.AppSettings["Password"];
string username = ConfigurationManager.AppSettings["Username"];
string selection = ConfigurationManager.AppSettings["Selection"];
string[] dc = adDomain.Split('.');
string dcAdDomain = string.Empty;
foreach (string item in dc)
{
if (dc[dc.Length - 1].Equals(item))
dcAdDomain = dcAdDomain + "DC=" + item;
else
dcAdDomain = dcAdDomain + "DC=" + item + ",";
}
string domainAndUsername = dcAdDomain + #"\" + adminUsername;
DirectoryEntry entry = new DirectoryEntry("LDAP://" + adServer, domainAndUsername, adminpassword);
try
{
//Bind to the native AdsObject to force authentication.
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
Console.WriteLine("And here is the result = " + result);
if (null == result)
{
isValid = false;
}
//Update the new path to the user in the directory.
var _path1 = result.Path;
var _filterAttribute = (string)result.Properties["cn"][0];
Console.WriteLine("And here is the _path1 = " + _path1);
Console.WriteLine("And here is the _filterAttribute = " + _filterAttribute);
isValid = true;
}
catch (Exception ex1)
{// your catch here
Console.WriteLine("Exception occurred " + ex1.Message + ex1.StackTrace);
}
return isValid;
}
Still it is giving error
Exception occurred Logon failure: unknown user name or bad passwor
d.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_NativeObject()
at Portal.LdapTest.Program.IsAuthenticated()
I think I am confused with which parameter to give where.
I have
LDAP server address something like 123.123.12.123
Domain Name like abc.com
Admin username and password and
Username and password which is needs be authenticated. (which is in OU=new users,OU=KK )
I am creating directory entry using servername, domain, admin username and password
How do I validate the username with given password?
This code works for me,try it and let me know (modify the filters and properties to suit your needs):
public bool IsAuthenticated(string domain, string username, string pwd){
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
try
{
//Bind to the native AdsObject to force authentication.
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 e){// your catch here
}
}
public bool AuthenticateUser(string EmailAddress, string password,out string msg)
{
msg = string.Empty;
if (password == null || password == string.Empty || EmailAddress == null || EmailAddress == string.Empty)
{
msg = "Email and/or password can't be empty!";
return false;
}
try
{
ADUserInfo userInfo = GetUserAttributes(EmailAddress);
if (userInfo == null)
{
msg = "Error: Couldn't fetch user information!";
return false;
}
DirectoryEntry directoryEntry = new DirectoryEntry(LocalGCUri, userInfo.Upn, password);
directoryEntry.AuthenticationType = AuthenticationTypes.None;
string localFilter = string.Format(ADSearchFilter, EmailAddress);
DirectorySearcher localSearcher = new DirectorySearcher(directoryEntry);
localSearcher.PropertiesToLoad.Add("mail");
localSearcher.Filter = localFilter;
SearchResult result = localSearcher.FindOne();
if (result != null)
{
msg = "You have logged in successfully!";
return true;
}
else
{
msg = "Login failed, please try again.";
return false;
}
}catch (Exception ex)
{
//System.ArgumentException argEx = new System.ArgumentException("Logon failure: unknown user name or bad password");
//throw argEx;
msg = "Wrong Email and/or Password!";
return false;
}
}

Improving performance of System.DirectoryServices.AccountManagement

I have a program that will let me manage users on our terminal server that we use to demo our software. I have been trying to improve the performace of adding users to the system (It adds the main account then it adds sub accounts if needed, for example if I had a user of Demo1 and 3 sub users it would create Demo1, Demo1a, Demo1b, and Demo1c.)
private void AddUsers(UserInfo userInfo, InfinityInfo infinityInfo, int subUserStart)
{
using (GroupPrincipal r = GroupPrincipal.FindByIdentity(context, "Remote Desktop Users"))
using (GroupPrincipal u = GroupPrincipal.FindByIdentity(context, "Users"))
for(int i = subUserStart; i < userInfo.SubUsers; ++i)
{
string username = userInfo.Username;
if (i >= 0)
{
username += (char)('a' + i);
}
UserPrincipal user = null;
try
{
if (userInfo.NewPassword == null)
throw new ArgumentNullException("userInfo.NewPassword", "userInfo.NewPassword was null");
if (userInfo.NewPassword == "")
throw new ArgumentOutOfRangeException("userInfo.NewPassword", "userInfo.NewPassword was empty");
user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username);
if (user == null)
{
user = new UserPrincipal(context, username, userInfo.NewPassword, true);
user.UserCannotChangePassword = true;
user.PasswordNeverExpires = true;
user.Save();
r.Members.Add(user);
u.Members.Add(user);
}
else
{
user.Enabled = true;
user.SetPassword(userInfo.NewPassword);
}
IADsTSUserEx iad = (IADsTSUserEx)((DirectoryEntry)user.GetUnderlyingObject()).NativeObject;
iad.TerminalServicesInitialProgram = GenerateProgramString(infinityInfo);
iad.TerminalServicesWorkDirectory = Service.Properties.Settings.Default.StartInPath;
iad.ConnectClientDrivesAtLogon = 0;
user.Save();
r.Save();
u.Save();
OperationContext.Current.GetCallbackChannel<IRemoteUserManagerCallback>().FinishedChangingUser(username);
}
catch (Exception e)
{
string errorString = String.Format("Could not Add User:{0} Sub user:{1}", userInfo.Username, i);
try
{
if (user != null)
errorString += "\nSam Name: " + user.SamAccountName;
}
catch { }
OperationContext.Current.GetCallbackChannel<IRemoteUserManagerCallback>().UserException(errorString, e);
}
finally
{
if (user != null)
user.Dispose();
}
}
}
Stepping through the code I have found that user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); is the expensive call, taking 5-10 seconds per loop.
I found I was having another 5-10 second hit on every GroupPrincipal.FindByIdentity() call too so I moved it out of the loop, the Save() is not expensive. Do you have any other recommendations to help speed this up?
Edit --
The normal case would be the user will exist but it is likely that the sub-user does not exist, but it can exist.
I found a soulution
private void AddUsers(UserInfo userInfo, InfinityInfo infinityInfo, int subUserStart)
{
var userSerach = new UserPrincipal(context);
userSerach.SamAccountName = userInfo.Username + '*';
var ps = new PrincipalSearcher(userSerach);
var pr = ps.FindAll().ToList().Where(a =>
Regex.IsMatch(a.SamAccountName, String.Format(#"{0}\D", userInfo.Username))).ToDictionary(a => a.SamAccountName); // removes results like conversons12 from the search conversions1*
pr.Add(userInfo.Username, Principal.FindByIdentity(context, IdentityType.SamAccountName, userInfo.Username));
using (GroupPrincipal r = GroupPrincipal.FindByIdentity(context, "Remote Desktop Users"))
using (GroupPrincipal u = GroupPrincipal.FindByIdentity(context, "Users"))
for(int i = subUserStart; i < userInfo.SubUsers; ++i)
{
string username = userInfo.Username;
if (i >= 0)
{
username += (char)('a' + i);
}
UserPrincipal user = null;
try
{
if (userInfo.NewPassword == null)
throw new ArgumentNullException("userInfo.NewPassword", "userInfo.NewPassword was null");
if (userInfo.NewPassword == "")
throw new ArgumentOutOfRangeException("userInfo.NewPassword", "userInfo.NewPassword was empty");
if (pr.ContainsKey(username))
{
user = (UserPrincipal)pr[username];
user.Enabled = true;
user.SetPassword(userInfo.NewPassword);
}
else
{
user = new UserPrincipal(context, username, userInfo.NewPassword, true);
user.UserCannotChangePassword = true;
user.PasswordNeverExpires = true;
user.Save();
r.Members.Add(user);
u.Members.Add(user);
r.Save();
u.Save();
}
IADsTSUserEx iad = (IADsTSUserEx)((DirectoryEntry)user.GetUnderlyingObject()).NativeObject;
iad.TerminalServicesInitialProgram = GenerateProgramString(infinityInfo);
iad.TerminalServicesWorkDirectory = Service.Properties.Settings.Default.StartInPath;
iad.ConnectClientDrivesAtLogon = 0;
user.Save();
OperationContext.Current.GetCallbackChannel<IRemoteUserManagerCallback>().FinishedChangingUser(username);
}
finally
{
if (user != null)
{
user.Dispose();
}
}
}
}
It adds a few more seconds on the first user but now its about .5 seconds per user after that. The odd calling of the ps.FindAll().ToList().Where(a =>Regex.IsMatch(...))).ToDictionary(a => a.SamAccountName); is because a principle searcher does not cache results. See my question from a few days ago.

How to programmatically change Active Directory password

I have a set of test accounts that are going to be created but the accounts will be setup to require password change on the first login. I want to write a program in C# to go through the test accounts and change the passwords.
You can use the UserPrincipal class' SetPassword method, provided you have enough privileges, once you've found the correct UserPrincipal object. Use FindByIdentity to look up the principal object in question.
using (var context = new PrincipalContext( ContextType.Domain ))
{
using (var user = UserPrincipal.FindByIdentity( context, IdentityType.SamAccountName, userName ))
{
user.SetPassword( "newpassword" );
// or
user.ChangePassword( "oldPassword", "newpassword" );
user.Save();
}
}
Here's a great Active Directory programming quick reference:
Howto: (Almost) Everything In Active Directory via C#
See the password reset code near the end.
public void ResetPassword(string userDn, string password)
{
DirectoryEntry uEntry = new DirectoryEntry(userDn);
uEntry.Invoke("SetPassword", new object[] { password });
uEntry.Properties["LockOutTime"].Value = 0; //unlock account
uEntry.Close();
}
Try this code. It works for me,
public void ChangeMyPassword(string domainName, string userName, string currentPassword, string newPassword)
{
try
{
string ldapPath = "LDAP://192.168.1.xx";
DirectoryEntry directionEntry = new DirectoryEntry(ldapPath, domainName + "\\" + userName, currentPassword);
if (directionEntry != null)
{
DirectorySearcher search = new DirectorySearcher(directionEntry);
search.Filter = "(SAMAccountName=" + userName + ")";
SearchResult result = search.FindOne();
if (result != null)
{
DirectoryEntry userEntry = result.GetDirectoryEntry();
if (userEntry != null)
{
userEntry.Invoke("ChangePassword", new object[] { currentPassword, newPassword });
userEntry.CommitChanges();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
Here is the solution:
string newPassword = Membership.GeneratePassword(12, 4);
string quotePwd = String.Format(#"""{0}""", newPassword);
byte[] pwdBin = System.Text.Encoding.Unicode.GetBytes(quotePwd);
UserEntry.Properties["unicodePwd"].Value = pwdBin;
UserEntry.CommitChanges();
It is possible to set a new password to a domain account, by using .NET Framework 2.0.
See working code bellow:
string domainfqdn="mydomain.test.gov" //fqdn of the domain
string ldapPath =GetObjectDistinguishedName (objectClass.user,returnType.distinguishedName, args[0].ToString(),domainfqdn);
ldapPath="LDAP://" + domainfqdn + :389/"+ldapPath;
DirectoryEntry uEntry = new DirectoryEntry(ldapPath,null,null,AuthenticationTypes.Secure);
uEntry.CommitChanges();
Console.WriteLine(ldapPath);
string password="myS3cr3tPass"
uEntry.Invoke("SetPassword", new object[] { password });
uEntry.Properties["LockOutTime"].Value = 0; //unlock account
uEntry.CommitChanges();
uEntry.Close();
it is very importan to check the parameters at uEntry, the code will run under the current thread security context, unless the null values are specified
public void ResetPassword(string userName, string Password, string newPassword)
{
try
{
DirectoryEntry directoryEntry = new DirectoryEntry(Path, userName, Password);
if (directoryEntry != null)
{
DirectorySearcher searchEntry = new DirectorySearcher(directoryEntry);
searchEntry.Filter = "(samaccountname=" + userName + ")";
SearchResult result = searchEntry.FindOne();
if (result != null)
{
DirectoryEntry userEntry = result.GetDirectoryEntry();
if (userEntry != null)
{
userEntry.Invoke("SetPassword", new object[] { newPassword });
userEntry.Properties["lockouttime"].Value = 0;
}
}
}
}
catch (Exception ex)
{
Log.Error("Password Can't Change:" + ex.InnerException.Message);
}
}

Categories