A lot of people posted about this but could not get anything to work. I am trying to get the user's username and password on an Asp.net form (the same username and password which the user uses to login to their computer on a domain).
I am using the PrincipalContext to validate the user.
Although I provide valid username and password, but pc.ValidateCredentials always returns false.
This is the first time I am doing User Authentication through Active Directory and have no idea what else do I require to successfully validate a user from Active Directory.
Do I need to provide information in the Container and Name properties on the PrincipalContext Object as it appears to be null.
Currently I am running this code from local machine which is on domain.
Do you have the correct domain? Maybe it is called different than 'DOMAIN', try this one:
private bool Authenticate(string user, string password)
{
using ( var context = new PrincipalContext(ContextType.Domain, Environment.UserDomainName) ) {
return context.ValidateCredentials(user.Trim(), password.Trim());
}
}
Please use below function
private bool AuthenticateAD(string userName, string password, string domain, out string message)
{
message = "";
DirectoryEntry entry = new
DirectoryEntry("LDAP://" + domain, userName, password);
try
{
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;
}
}
catch (Exception ex)
{
message = ex.Message;
return false;
//throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
Related
I want to find if the user belongs to an AD group. Can you advise how I can add that functionality using the following code?
I ask the user to enter their username and password (through a form), so not using the windows credentials. With the below code I am able to validate the user, by passing the username, and password. How can I build on the code to check if user exists in the AD Group. Is there another way to do this? Please advice
DirectoryEntry adsEntry = new DirectoryEntry("domain", userid, password);
DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry);
try {
SearchResult adsSearchResult = adsSearcher.FindOne();
context.Session.Timeout = 2;
context.Session["ValidatedLoginID"] = userid;
user.Verified = true;
adsEntry.Close();
} catch ( Exception ex ) {
// Failed to authenticate. Most likely it is caused by unknown user
// id or bad strPassword.
user.error = ex.Message;
adsEntry.Close();
}
You can use the below code:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "DOMAINNAME");
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");
if(user != null)
{
// check if user is member of that group
if (user.IsMemberOf(group))
{
// do something.....
}
}
Also look at: How to check if a user belongs to an AD group?
Here is how I solved this :
DirectoryEntry adsEntry = new DirectoryEntry("domain", userid, password);
DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry);
adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person)(sAMAccountName=" + userid + "))";
try
{
SearchResult adsSearchResult = adsSearcher.FindOne();
string propertyName = "memberOf";
ResultPropertyValueCollection rpvcResult = adsSearchResult.Properties[propertyName];
foreach (Object PropertyValue in rpvcResult)
{
if (PropertyValue.ToString() == "Group Name")
{
user.Verified = true;
user.FullName = GetFullName(userid);
adsEntry.Close();
} else
{
user.Verified = false;
user.error = "You do not belong to the Group so you cannot do this function";
}
}
} catch (Exception ex)
{
user.error = "Please check your username and password credentials";
adsEntry.Close();
}
I am working on some code that creates an AD user programmatically (to be pulled into a MS DYnamics CRM 2013 environment), and the code works with one weird quirk. I have a list of UPN's created on our AD structure, but for some reason my AD users aren't resolving to them.
So, I have a list of UPN suffix's that include example.com. I set the username to be first.last#example.com, and it's not letting me use this to sign in to CRM. When I check the AD entry, I can see that it kind of correctly assigned the logon name to first.last#example.com, but #example.com appears in the list twice, the entry that was actually created and this new one. So it's not recognizing that #example.com is a pre-existing UPN suffix, and I can't use the first.last#example.com to sign in to CRM with, I have to use the example.local\first.last. I hope this made sense. Thank you very much.
So how do I tell then AD record when it signs in to use the pre-existing UPN and not... do whatever it's doing? Here's my code:
try
{
string connectionPrefix = "LDAP://" + ldapPath;// ldapPart;// ldapPath
var adminUsername = ConfigurationHelper.GetConfigSettingByName(orgservice,
"ADPasswordReset.AdminUsername", unsecureConfig, secureConfig);
var adminPassword = ConfigurationHelper.GetConfigSettingByName(orgservice,
"ADPasswordReset.AdminPassword", unsecureConfig, secureConfig);
if (CheckIfUserExists(getSAMNameFromUserName(userName), trace) == true)
{
throw new Exception("A User with that name already exists.");
}
DirectoryEntry dirEntry = new DirectoryEntry(connectionPrefix, adminUsername, adminPassword, AuthenticationTypes.Secure);
DirectoryEntry newUser;
string cn = firstName + " " + lastName;
newUser = dirEntry.Children.Add("CN=" + cn, "user"); //display name - This is the "Display" name that shows up on the AD list.
newUser.Properties["displayName"].Value = cn;
newUser.Properties["samAccountName"].Value = getSAMNameFromUserName(userName);//userName;
newUser.Properties["userPrincipalName"].Value = checkUserName(userName);
newUser.Properties["givenName"].Value = firstName; //Firstname
newUser.Properties["sn"].Value = lastName; //Lastname? -Surname
newUser.Properties["LockOutTime"].Value = 0; //unlock account. Set this to 0 to unlock the account.
newUser.CommitChanges();
oGUID = newUser.Guid.ToString();
//Must be handled after the previous stuff. Unsure why.
newUser.Invoke("SetPassword", new object[] { userPassword });
newUser.CommitChanges();
//For some reason, can't be handled before the password is set?
newUser.Properties["userAccountControl"].Value = 0x0200; //0x0200
newUser.CommitChanges();
dirEntry.Close();
newUser.Close();
}
public static string checkUserName(string userName)
{
if (!userName.Contains("#"))
{
return userName + "#example.local";
}
return userName;
}
public static string getSAMNameFromUserName(string domainUserName)
{
int stop;
string s = domainUserName;
if (s.Contains("#"))
{
stop = s.IndexOf("#");
return (stop > -1) ? s.Substring(0, stop) : string.Empty;
}
return domainUserName;// string.Empty;
}
In your code you set the UPN to example.local not example.com:
public static string checkUserName(string userName)
{
if (!userName.Contains("#"))
{
return userName + "#example.local";
}
return userName;
}
A user can only have one UPN even if the domain has multiple possible suffixes configured. If you want username#example.com to resolve, the user must have example.com set as it's suffix.
Thank you all who took the time to help.
Whitespace. Grrr, whitespace.
For anybody who comes across this thread in the future, the problem was that something during the AD creation was appending whitespace to my username and domain. So instead of "example.com" it was saving the domain as "example.com " (notice the whitespace at the end?). I .Trim()'d everything and it appears to be working just fine. :)
My new code becomes:
public static string checkUserName(string userName)
{
if (!userName.Contains("#"))
{
return userName.Trim() + "#domain.local".Trim();
}
return userName.Trim();
}
try
{
string connectionPrefix = "LDAP://" + ldapPath;// ldapPart;// ldapPath
var adminUserName = GetAdminUserName(orgservice, unsecureConfig, secureConfig);
var adminPassword = GetAdminPassword(orgservice, unsecureConfig, secureConfig);
if (CheckIfUserExists(getSAMNameFromUserName(userName), trace) == true)
{
trace.Trace("About to handle success. A User already exists: " + getSAMNameFromUserName(userName));
trace.HandleSuccess();
throw new Exception("User " + getSAMNameFromUserName(userName) + " already exists.");
}
DirectoryEntry dirEntry = new DirectoryEntry(connectionPrefix, adminUserName, adminPassword, AuthenticationTypes.Secure);
DirectoryEntry newUser;
string cn = firstName.Trim() + " " + lastName.Trim();
newUser = dirEntry.Children.Add("CN=" + cn, "user"); //display name - This is the "Display" name that shows up on the AD list.
newUser.Properties["displayName"].Value = cn;
newUser.Properties["samAccountName"].Value = getSAMNameFromUserName(userName).Trim();
newUser.Properties["userPrincipalName"].Value = checkUserName(userName).Trim();
newUser.Properties["givenName"].Value = firstName.Trim(); //Firstname
newUser.Properties["sn"].Value = lastName.Trim(); //Lastname? -Surname
//newUser.Properties["LockOutTime"].Value = 0; //unlock account. Set this to 0 to unlock the account.
newUser.CommitChanges();
oGUID = newUser.Guid.ToString();
//Must be handled after the previous stuff. Unsure why.
newUser.Invoke("SetPassword", new object[] { userPassword });
newUser.CommitChanges();
//For some reason, can't be handled before the password is set?
newUser.Properties["userAccountControl"].Value = 0x10200; //0x0200
newUser.CommitChanges();
//http://stackoverflow.com/questions/20710535/is-there-a-way-to-set-a-new-users-domain-suffix-through-the-userprincipal-class
newUser.Close();
dirEntry.Close();
//newUser.Close(); //Close user first, then dirEntry because of the heirarchy call?
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
System.DirectoryServices.DirectoryServicesCOMException newE = new System.DirectoryServices.DirectoryServicesCOMException(E.Message);
//DoSomethingwith --> E.Message.ToString();
throw newE;
}
I'm getting stuck with creating Active Directory User with C#
this is my code use to create a new user:
public bool CreateUser(string userName, string password)
{
try
{
DirectoryEntry entry = new DirectoryEntry(lDAPConnectionString, aDConnectionUserName, aDConnectionPassword, AuthenticationTypes.Secure);
// Use the Add method to add a user to an organizational unit.
DirectoryEntry user = entry.Children.Add("CN=" + userName, "user");
// Set the samAccountName, then commit changes to the directory.
user.Properties["samAccountName"].Value = userName;
user.Properties["userPrincipalName"].Value = userName + Constants.ADProperties.ADUPNLogonSuffix;
user.CommitChanges();
// Set password never expire
int NON_EXPIRE_FLAG = 0x10000;
int val = (int)user.Properties["userAccountControl"].Value;
user.Properties["userAccountControl"].Value = val | NON_EXPIRE_FLAG;
user.CommitChanges();
// Enable User
val = (int)user.Properties["userAccountControl"].Value;
user.Properties["userAccountControl"].Value = val & ~(int)Constants.ADS_USER_FLAG_ENUM.ADS_UF_ACCOUNTDISABLE;
user.CommitChanges();
user.RefreshCache();
// Set password
user.UsePropertyCache = true;
user.Invoke("SetOption", new object[] { Constants.ADS_USER_FLAG_ENUM.ADS_OPTION_PASSWORD_PORTNUMBER, Constants.ADProperties.ADPort });
user.Invoke("SetOption", new object[] { Constants.ADS_USER_FLAG_ENUM.ADS_OPTION_PASSWORD_METHOD, Constants.ADS_USER_FLAG_ENUM.ADS_PASSWORD_ENCODE_CLEAR });
user.Properties["LockOutTime"].Value = 0;
user.Invoke("SetPassword", new object[] { password });
user.CommitChanges();
return true;
}
catch (Exception)
{
}
return false;
}
And when I use it, it throw an exception : "The server is unwilling to process the request. (Exception from HRESULT: 0x80072035)"
at line : "user.Invoke("SetPassword", new object[] { password });"
I tried many way but I cannot solve this problem.
Any help would be appricated.
Thanks
Error 0x80072035 usually returns due to a password policy. This can be length, special characters, password history (password was used before). It would help to handle those errors to prrovide feedback to the user. A guide to handle these errors can be found here:
http://www.ozkary.com/2015/03/active-directory-setpassword-or.html
We have a program running on different computers in our network, and this program needs to login with an specific administrator account to execute some tasks.
Our supplier wrote the below code to check whether the user is a local admin or not.
The question is:
If the admin user has logged in the computer before, will the credentials be saved in the cache so the below code would work even without a network connection?
If so, how can we force those credentials to be saved?
Else, is there any alternative so we can login with the credentials from the cache?
static bool UserExists(string domain, string username, string password)
{
if (System.Environment.GetEnvironmentVariable("UserDomain") != null)
{
if (string.Compare(System.Environment.GetEnvironmentVariable("UserDomain"), domain, true) != 0)
{
return false;
}
}
string filter = string.Format("(&(ObjectClass={0})(sAMAccountName={1}))", "person", username);
string[] properties = new string[] { "fullname" };
using (DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + domain, null, null, AuthenticationTypes.Secure))
using (DirectorySearcher searcher = new DirectorySearcher(adRoot))
{
adRoot.Username = username;
adRoot.Password = password;
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.PropertiesToLoad.AddRange(properties);
searcher.Filter = filter;
if (searcher.FindOne() != null)
{
// If you want to see the user details: searcher.FindOne().GetDirectoryEntry();
return true;
}
}
return false;
}
Thanks in advance
I have a code that I use to check if the user is member of the AD, worked perfectly,
now I want to add the possibility to check if the user also a member of a group!
what do I need to modify to achieve that, I did some work, but it fails!
so here is my code:
//Authenticate a User Against the Directory
private bool Authenticate(string userName,string password, string domain)
{
if (userName == "" || password == "")
{
return false;
}
bool authentic = false;
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain,userName, password);
object nativeObject = entry.NativeObject;
authentic = true;
}
catch (DirectoryServicesCOMException) { }
return authentic;
}
I want to make it like this:
private bool Authenticate(string userName,string password, string domain, string group)
This is not available on Windows XP or earlier.
Anyway, in order to check for group membership, you can use this code:
bool IsInGroup(string user, string group)
{
using (var identity = new WindowsIdentity(user))
{
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(group);
}
}
In ASP.Net you will use Page.User.IsInRole("RoleName") or in Windows you can use System.Threading.Thread.CurrentPrincipal.IsInRole("RoleName")
I solve it with this code
public bool AuthenticateGroup(string userName, string password, string domain, string group)
{
if (userName == "" || password == "")
{
return false;
}
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, userName, password);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(|(cn=" + userName + ")(sAMAccountName=" + userName + ")))";
SearchResult result = mySearcher.FindOne();
foreach (string GroupPath in result.Properties["memberOf"])
{
if (GroupPath.Contains(group))
{
return true;
}
}
}
catch (DirectoryServicesCOMException)
{
}
return false;
}
it works fine for me, and it can be use with a machine not part of the Domain Controller / Active Directory
Thank you all for the help