Create new AD user with unique username - c#

I have a web view that takes a person's first name and last name, and tries to creates a new user in active directory using the naming context of first letter of first name + last name. This works great, however when creating multiple users with the same last name and first name that start with the same character (ie. Andy Gordan => agordan | Alex Gordan => agordan), errors are thrown because a user with the same username already exist.
How do I add an if/else statement below that checks with active directory to see if the username already exists, and if so add a middle initial after the first name (Alex M Gordan => agordan , next user entered: Andy M Gordan => amgordan).
[HttpPost]
public ActionResult Index(CreateUser model)
{
//Domain name
var domainName = "XXX";
//Fully distinguished name of OU to create user in
var location = model.Location;
var userOU = "OU=" + location + ",OU=XXX,DC=XXX,DC=com";
using (var pc = new PrincipalContext(ContextType.Domain, domainName, userOU))
{
using (var up = new UserPrincipal(pc))
{
//Creates username and display name from firstname and lastname
**var userName = model.FirstName[0].ToString().ToLower() + model.LastName.ToString().ToLower();**
var displayName = model.FirstName + " " + model.LastName;
var password = "XXX";
up.Name = displayName;
up.DisplayName = displayName;
up.GivenName = model.FirstName;
up.MiddleName = model.MiddleI;
up.Surname = model.LastName;
up.SamAccountName = userName;
up.EmailAddress = userName + "#XXX.com";
up.UserPrincipalName = userName + "#XXX.com";
up.SetPassword(password);
up.Enabled = true;
up.ExpirePasswordNow();
try
{
//Attempt to save the account to AD
up.Save();
}
catch (Exception e)
{
ModelState.AddModelError("", "Exception creating user object. " + e);
return View(model);
}
//Set department to add
DirectoryEntry entry = up.GetUnderlyingObject() as DirectoryEntry;
//DirectoryEntry group = entry.Children.Add("CN="+ )
entry.Properties["department"].Value = model.Department;
//entry.Properties["member"].Add(up);
try
{
//try and commit the changes
entry.CommitChanges();
}
catch(Exception e)
{
ModelState.AddModelError("", "Exception adding department. " + e);
return View(model);
}
}
}
//Redirect to completed page if successful
return RedirectToAction("Completed");
}//POST Index

Related

How to authenticate in LDAP in C#?

I am new to LDAP related coding and today I am asked to develop a code to check the users authentication against LDAP.
The tutorials I have found online are so simple but our company's Directory is so complicated that I don't know how to write a code for that. Here is the info of the LDAP . I have changed the company name to hide the name.
string domain = "ou=People,dc=my,dc=com";
string LDAP_Path= "dc01.my.com;
string LDAPconnect= "LDAP://dc01.my.com/";
Here is a code I have developed but it gives me error when run " LdapResult = LdapSearcher.FindOne();":
string domain = "ou=People,dc=my,dc=com";
string password = "";
string userName = "";
// define your connection
LdapConnection ldapConnection = new LdapConnection(LDAP_Path);
try
{
// authenticate the username and password
using (ldapConnection)
{
// pass in the network creds, and the domain.
var networkCredential = new NetworkCredential(userName, password, domain);
// if we're using unsecured port 389, set to false. If using port 636, set this to true.
ldapConnection.SessionOptions.SecureSocketLayer = false;
// since this is an internal application, just accept the certificate either way
ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
// to force NTLM\Kerberos use AuthType.Negotiate, for non-TLS and unsecured, just use AuthType.Basic
ldapConnection.AuthType = AuthType.Basic;
// authenticate the user
ldapConnection.Bind(networkCredential);
Response.Write( "connect ldap success");
}
}
catch (LdapException ldapException)
{
Response.Write(ldapException + " <p>Ad connect failed</p>");
//Authentication failed, exception will dictate why
}
string strTmp0 = LDAPconnect + domain;
string user = "memberId";
string pwd = "memberPwd";
System.DirectoryServices.DirectoryEntry LdapEntry = new System.DirectoryServices.DirectoryEntry(strTmp0, "cn=" + user, pwd, AuthenticationTypes.None);
DirectorySearcher LdapSearcher = new DirectorySearcher(LdapEntry);
LdapSearcher.Filter = "(cn=" + user + ")";
string value = string.Empty;
SearchResult LdapResult=null;
try
{
LdapResult = LdapSearcher.FindOne();
}
catch (Exception ex)
{
Response.Write(ex.Message.ToString());
// .............get Error msg : username an password uncorrect
}
if ((LdapResult != null))
{
Response.Write("ldapresult not null");
}
Could anybody help plz?
In ldap connection setting , OP should use own configuration.
// Ldap connection setting. this should setup according to organization ldap configuration
int portnumber = 12345;
LdapConnection ldapConnection = new LdapConnection(new LdapDirectoryIdentifier("ldap.testxxxx.com", portnumber));
ldapConnection.AuthType = AuthType.Anonymous;
ldapConnection.Bind();
SearchRequest Srchrequest = null;
SearchResponse SrchResponse = null;
SearchResultEntryCollection SearchCollection = null;
Hashtable UserDetails = new Hashtable();
Srchrequest = new SearchRequest("distniguishged name e.g. o=testxxx.com", string.Format(CultureInfo.InvariantCulture, "preferredmail=test#testxxxx.com"), System.DirectoryServices.Protocols.SearchScope.Subtree);
SrchResponse = (SearchResponse)ldapConnection.SendRequest(Srchrequest);
SearchCollection = SrchResponse.Entries;
foreach (SearchResultEntry entry in SearchCollection)
{
foreach (DictionaryEntry att in entry.Attributes)
{
if (((DirectoryAttribute)(att.Value)).Count > 0)
{
UserDetails.Add(att.Key.ToString(), ((DirectoryAttribute)(att.Value))[0].ToString());
}
else
{
UserDetails.Add(att.Key.ToString(), string.Empty);
}
}
}
if (UserDetails.Count > 1)
{
Console.WriteLine("User exists");
}
else
{
Console.WriteLine("User does not exist");
}
You can use the DirectoryInfo conrstructor that has user and password arguments. That way, you don't need to do a query to the LDAP, you can simplify your code.
string username = "frederic";
string password = "myFanciPassword99";
string domain = "ou=People,dc=my,dc=com";
string LDAPconnect= "LDAP://dc01.my.com/";
string connectionString = LDAPconnect + domain;
bool userValid = false;
// Note: DirectoryEntry(domain, username, password) would also work
DirectoryEntry entry = new DirectoryEntry(connectionString, username, password);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
userValid = true;
}
catch (Exception ex)
{
}

how to change a username and password stored in a text file only for the correct user

i am currently making a application for my a level computing coursework. for my coursework i am required to make a login and registration system which requires me to store the user details in a text file this is only for my coursework so security isent important. my registration and login system works fine but i am also required to have a change account details screen in which the user can change their username and password.
my problem is that my code that i have currently changes the password for every user with the same password ie if 2 users have password123 as a password both their passwordds gets changed to the new password
private void btnUpdatePassword_Click(object sender, EventArgs e)
{
string oldusername = txtBoxOldUsername.Text;
string newusername = txtBoxNewUsername.Text;
string oldpassword = txtBoxOldPassword.Text;
string newpassword = txtBoxNewPassword.Text;
string text = File.ReadAllText("users.txt");
text = text.Replace(oldpassword, newpassword).Replace(oldusername, newusername);
File.WriteAllText("users.txt", text);
}
my problem is that i dont know how to change the password for only the correct user. it would be great if anyone could help thanks. also i HAVE to use a text file to do this meaning i cant use jason on xml etc
this is what my text file looks like
first user ~username~password
second user ~username123~password
third user ~username1234~password
and this is the code i use to write to the text file
FileStream fileStream = new FileStream("users.txt", FileMode.Append, FileAccess.Write);
StreamWriter streamWriter = new StreamWriter(fileStream);
try
{
streamWriter.WriteLine(fullname + "~" + username + "~" + password + "~" + lastlogin);
MessageBox.Show("User registered successfully", "Registration Successful");
this.Hide();
var homeForm = new HomeForm();
homeForm.Closed += (s, args) => this.Close();
homeForm.Show();
}
catch (Exception)
{
MessageBox.Show("Error registering the user", "Please try again");
}
finally
{
streamWriter.Close();
fileStream.Close();
}
Here is an idea on how to implement it. My first suggestion is to add a comma deliminator to your text file so your values in users.txt will be in the following form
second user~username123~password,
third user~username1234~password,
first user~username~smelly,
Import all the users from users.txt at once and split them by our deliminator ','
var users = File.ReadAllText(#"C:\users.txt").Split(',').ToList().Where(x=> !String.IsNullOrWhiteSpace(x));
Note this clause .Where(x=> !String.IsNullOrWhiteSpace(x) will be needed because when I rewrite the file , for simplicity sake I add a comma to each entry. As last entry will have a comma we end up with an extra empty object. This clause will rectify it.
Create a class which will contains all the user properties:
private class User
{
public string Name { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string PrepareForFile()
{
return Name + "~" + UserName + "~" + Password + ",";
}
}
Loop through all the retrieved users information from file and build a list of user:
List<User> myUsers = new List<User>();
foreach (var user in users)
{
var information = user.Split('~');
User temp = new User();
temp.Name = information[0].Trim();
temp.UserName = information[1].Trim();
temp.Password = information[2].Trim();
myUsers.Add(temp);
}
Now you have a manageable structure and you can perform all the desired operations. Once finished use the method PrepareForFile() to create a string like second user~username123~password to be written into file.
Putting it all together(this is a console app):
static class Program
{
private class User
{
public string Name { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string PrepareForFile()
{
return Name + "~" + UserName + "~" + Password + ",";
}
}
static void Main(string[] args)
{
var users = File.ReadAllText(#"C:\users.txt").Split(',').ToList().Where(x=> !String.IsNullOrWhiteSpace(x));
List<User> myUsers = new List<User>();
foreach (var user in users)
{
var information = user.Split('~');
User temp = new User();
temp.Name = information[0].Trim();
temp.UserName = information[1].Trim();
temp.Password = information[2].Trim();
myUsers.Add(temp);
}
var selectedUser = myUsers.Where(x => x.UserName == "username").SingleOrDefault();
myUsers.Remove(selectedUser);
selectedUser.Password = "Leo";
myUsers.Add(selectedUser);
List<string> formatForFile = new List<string>();
foreach(var item in myUsers)
{
formatForFile.Add(item.PrepareForFile());
}
File.WriteAllLines(#"C:\users.txt", formatForFile.ToArray());
}
}
Changing username1234 password from "password" to "AlexLeo":
Before
After
You can store the username with the password when saving the password and delete the username when it is extracted from the password and add the username when adding the password.
for example:
private void btnUpdatePassword_Click(object sender, EventArgs e)
{
string oldusername = txtBoxOldUsername.Text;
string newusername = txtBoxNewUsername.Text;
string oldpassword = txtBoxOldPassword.Text;
string newpassword = txtBoxNewPassword.Text;
string text = File.ReadAllText("users.txt");
text = text.Replace(oldpassword + oldusername, newpassword + newusername).Replace(oldusername, newusername);
File.WriteAllText("users.txt", text);
}
Based on your updated OP
string str = System.IO.File.ReadAllText(fileName);
var users = str.Split(new []{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries)
.Select(x=>
{
var strArray = x.Split(new []{"~"},StringSplitOptions.RemoveEmptyEntries);
return new
{
FirstName = strArray[0],
User = strArray[1],
Password = strArray[2]
};
}
);
var usernameToUpdate = "username123";
var newPassword = "Thisisnewpassword";
var updatedList = users.Select(x => x.User.Equals(usernameToUpdate) ?
$"{x.FirstName} ~{x.User}~{newPassword}"
: $"{x.FirstName} ~{x.User}~{x.Password}").ToList();
var newFileData = String.Join(Environment.NewLine,
updatedList);
File.WriteAllText(fileName, newFileData);

UserSearcher/UserPrinciple: Users have been deleted already

I am trying to use PrincipalSearcher to search for any users with a specific DisplayName and delete them.
If there are no users with a matching DisplayName, the code operates fine. If one is found though, an exception is raised stating:
System.InvalidOperationException: Can't delete an already deleted
object
at System.DirectoryServices.AccountManagement.Principal.CheckDisposedOrDeleted()
at System.DirectoryServices.AccountManagement.Principal.get_Name()}
I have placed a breakpint on user.delete() and can confirm that there is a user present. As soon as the Delete call is made though, the exception is raised.
I can't see where the object has been deleted. Any help would be appreciated.
public string DeleteUsers()
{
using (var principalContext = new PrincipalContext(
ContextType.Machine, null
))
{
using (var userPrincipal = new UserPrincipal(principalContext))
{
// All users will have the same DisplayName
userPrincipal.DisplayName = UserDisplayName;
//
// Search for all users with the above displayName
//
using (var principalSearcher = new PrincipalSearcher(
userPrincipal
))
{
var users = principalSearcher.FindAll();
string userString = "";
// Loop through each of them and delete them
foreach (var user in users)
{
var username = user.Name;
try
{
user.Delete();
}
catch (Exception e)
{
return $"Error: Could not delete user: {username}. " +
$"{e.Message}";
}
if (!String.IsNullOrEmpty(userString))
{
userString += ", ";
}
userString += username;
}
if (String.IsNullOrEmpty(userString))
{
return "No users deleted.";
}
return "Deleted the following users: " + userString;
}
}
}
}

Retrieve user information from Active Directory on login

I build one page ASP.Net required to login with Active Directory. The login is successful. But how to retrieve current user information from AD such as Full Name and display in my mainpage.aspx (C#)
I have try this on my code
using System.DirectoryServices;
using (DirectoryEntry de = new DirectoryEntry("LDAP://SUTRA"))
{
using (DirectorySearcher adSearch = new DirectorySearcher(de))
{
string username = HttpContext.Current.Request.ServerVariables["AUTH_USER"];
adSearch.Filter = "(sAMAccountName=someuser)";
SearchResult adSearchResult = adSearch.FindOne();
}
}
The following code will return User's FirstName and LastName from AD
public string GetUserDetails(string UserID)
{
try
{
DirectorySearcher search = default(DirectorySearcher);
DirectoryEntry entry = default(DirectoryEntry);
SearchResult sr = default(SearchResult);
System.DirectoryServices.PropertyCollection propertycol = default(System.DirectoryServices.PropertyCollection);
entry = new DirectoryEntry("LDAP://DomainName.com");
propertycol = entry.Properties;
search = new DirectorySearcher(entry);
search.Filter = "(sAMAccountName=" + UserID + ")";
sr = search.FindOne();
string fname = "";
string lname = "";
if ((sr != null))
{
if (sr.Properties.Count > 1)
{
fname = Convert.ToString(sr.GetDirectoryEntry().Properties["givenName"].Value);
lname = Convert.ToString(sr.GetDirectoryEntry().Properties["sn"].Value);
}
return fname + "\n" + lname ;
}
return "User Id not found";
}
catch (Exception ex)
{
return "Error:" + ex.Message;
}
}

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;
}
}

Categories