PrincipalSearcher Wrong Username Or Password error - c#

I'm trying to get user data from the active directory. Authentication process is true.
var context = new PrincipalContext(ContextType.Domain, "localhost-ad.local", "OU=LocalOu,DC=localhost-ad,DC=local", ContextOptions.Negotiate);
var login = context.ValidateCredentials("user.name", "password", ContextOptions.Negotiate);
But PrincipalSearcher returns a wrong username or password.
var user = new UserPrincipal(context);
var searcher = new PrincipalSearcher(user);
var searchResults = searcher.FindAll();
List<UserPrincipal> results = new List<UserPrincipal>();
foreach (Principal p in searchResults)
{
results.Add(p as UserPrincipal);
}
return results;
How can I solve this problem?

I think your problem may stem from a misunderstanding of what PrincipalContext.ValidateCredentials does.
It does not authenticate the context on the domain or allow access to the domain in any way, all it does is check if the username and password are correct and return True or False.
Instead you can authenticate with the domain as so:
var context = new PrincipalContext(ContextType.Domain, "localhost-ad.local",
"OU=LocalOu,DC=localhost-ad,DC=local", "user.name", "password");

Related

Active Directory - Getting "The Server could not be contacted" Error

I'm trying to create a DLL that gets all the users from a certain OU group in Active Directory, but I'm getting this two errors:
System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. and
System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
My code is currently this:
public static void GetAllADUsers(string output, string filter, int mode) {
List<string> allUsers = new List<string>();
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "LDAP://mydomain.COM", filter);
UserPrincipal qbeUser = new UserPrincipal(ctx);
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
foreach (var found in srch.FindAll()) {
allUsers.Add(found.DisplayName);
}
if(mode == 1)
File.WriteAllText(output, allUsers.ToString());
else
File.AppendAllText(output, allUsers.ToString());
}
My input parameters are:
PCControl.PCC:GetAllADUsers("C:\temp\users.csv", "OU=Users,OU=...,OU=...,DC=mydomain,DC=com", 1).
I don't know if this helps, but I'm able to use this function into my DLL:
(That's where I got the PrincipalContext)
new DirectorySearcher(new DirectoryEntry("LDAP://mydomain.COM", user, password) {
AuthenticationType = AuthenticationTypes.Secure,
Username = user,
Password = password
}) {
Filter = "(objectclass=user)"
}.FindOne().Properties["displayname"][0].ToString();
Any sugestions on how I can fix this?

use raw query in LDAP with c#

I need to do query raw on the LDAP server with c# 3.5. I use this code, but I can't find how I do for insert a raw query.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, host, username, password);
UserPrincipal u = new UserPrincipal(ctx);
PrincipalSearcher search = new PrincipalSearcher(u);
foreach (UserPrincipal result in search.FindAll())
{
var s = result.UserPrincipalName;
}

How to create new user account without password

I would like to programmatically add new local user to a computer. I found the code here.
But I would like that the user could login without password. I saw that there is an option UserPrincipal.PasswordNotRequired=true but if I don't use SetPassword() it throws me an exception:
The password does not meet the password policy requirements...
Is it possible to make a new user with no password?
EDIT: the current code, which adds a new user successfully, but I have to provide some password.It is a complete copy from the link provided:
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
oUserPrincipal.Name = sUserName;
oUserPrincipal.SetPassword(sPassword);
oUserPrincipal.DisplayName = windowsUsername.Text;
oUserPrincipal.PasswordNeverExpires = true;
oUserPrincipal.PasswordNotRequired = true;
oUserPrincipal.Save();
GroupPrincipal usersGroup = GroupPrincipal.FindByIdentity(oPrincipalContext, "Users");
usersGroup.Members.Add(oUserPrincipal);
usersGroup.Save();
There are two potential reasons why your code isnt working.
Youre not running as admin
Your machine is on a domain with a group policy preventing what you want to do.
The code below has been tested on my machine and is working.
void Main()
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
oUserPrincipal.Name = "TestUser";
oUserPrincipal.SetPassword("");
oUserPrincipal.DisplayName = "TestUser";
oUserPrincipal.PasswordNeverExpires = true;
oUserPrincipal.PasswordNotRequired = true;
oUserPrincipal.Save();
GroupPrincipal usersGroup = GroupPrincipal.FindByIdentity(oPrincipalContext, "Users");
usersGroup.Members.Add(oUserPrincipal);
usersGroup.Save();
}
PrincipalContext GetPrincipalContext()
{
var dc = new PrincipalContext(ContextType.Machine);
return dc;
}
Things for you to try,
1. Try it on a machine that is not on your domain.
2. Try it on a machine that does not have any group policies applied.
3. Run your app as admin on the machine that you're having the issue with

Trying to read login name from Active Directory returning null

DirectoryEntry DirEntry = new DirectoryEntry("LDAP://" + domain, null, null, AuthenticationTypes.None);
DirectorySearcher search = new DirectorySearcher(DirEntry);
search.Filter = String.Format("(SAMAccountName={0})", "my_login_name");
search.PropertiesToLoad.Add("cn");
SearchResult result1 = search.FindOne();
myDataTable Users = new myDataTable();
DataRow User;
foreach (SearchResult i in search.FindAll())
{
DirectoryEntry CurrentDirEntry;
User = Users.NewUserRow();
CurrentDirEntry = i.GetDirectoryEntry();
User.FirstName = (string)CurrentDirEntry.Properties["givenname"].Value;
User.LastName = (string)CurrentDirEntry.Properties["sn"].Value;
User.UserName = (string)CurrentDirEntry.Properties["sAMAccountName"].Value;
User.Email = (string)CurrentDirEntry.Properties["mail"].Value;
Users.AddUserRow(User);
}
I'm trying to read some properties from active directory but the value for
sAMAccountName
is always returned as null, i'm wondering why this is so since its being matched in the search filter. Could it be related to access privileges?
I want to return the FirstName, LastName, Email and login Name. I'm getting other properties except login name.
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, my_login_name);
if(user != null)
{
// do something here....
string samAccountName = user.SamAccountName;
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
Update: if you need to search by fields that aren't handled by the .FindByIdentity() call, then you need to use the PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// define a "query-by-example" principal - here, we search for a UserPrincipal
// and with the first name (GivenName) of "Bruce" and a last name (Surname) of "Miller"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.GivenName = "Bruce";
qbeUser.Surname = "Miller";
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
}
Could it be the spacing in ["sAMAccountName "] of :
User.UserName = (string)CurrentDirEntry.Properties["sAMAccountName "].Value;
Try this one , I used it before
VB
Dim myDe As New DirectoryEntry("LDAP://DOMAIN.LOCAL")
Dim deSearcher As New DirectorySearcher(myDe)
Dim userDE As DirectoryEntry
Dim email As String = ""
Try
deSearcher.Filter = "(&(sAMAccountName=" & UserName & "))"
userDE = deSearcher.FindOne().GetDirectoryEntry()
email = userDE.Properties("mail").Value
Catch ex As Exception
End Try
C#
DirectoryEntry myDe = new DirectoryEntry("LDAP://DOMAIN.LOCAL");
DirectorySearcher deSearcher = new DirectorySearcher(myDe);
DirectoryEntry userDE = default(DirectoryEntry);
string email = "";
try {
deSearcher.Filter = "(&(sAMAccountName=" + UserName + "))";
userDE = deSearcher.FindOne().GetDirectoryEntry();
email = userDE.Properties("mail").Value;
} catch (Exception ex) {}
I'm not sure how C# handles it but I've seen LDAP-libs returning attribute names all in lower case. So it might help to simply call for samaccountname instead of sAMAccountName.

c# Log In click event using authentication against Active Directory through LDAP

I am quite new to c# and LDAP, I'm doing this project so that I could learn about them in a more hands on approach.
What I'm trying to create is a Log in form that has a log in click event that would authenticate the username and password after the user enters them through the active directory using LDAP.
I have read Managing Directory Security Principals in the .NET Framework 3.5 to be able to understand this subject better and I have also gone through similar topics here this one dealing with the validation in itself (c# - Validate a username and password against Active Directory?) and this one authenticating a username (c# against Active Directory over LDAP)
From the first linked topic I had learned that the following code should do the trick in authenticating a username and password:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "LDAP://example.string.com/OU=Users, Dc=example, Dc= string, DC=com"))
{
bool isValid = pc.ValidateCredentials(User, Password);
}
So my approach to incorporate this to a click event was as follows:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "LDAP://example.string.com/OU=Users, Dc=example, Dc= string, DC=com"))
bool isValid = pc.ValidateCredentials(User, Password);
if(isValid)
{
Main m = new Main();
this.Close();
m.Show();
}
else
{
MessageBox.Show("Invalid Username and/or Password","Error!");
textBox1.Clear();
textBox2.Clear();
textBox1.Focus();
}
Which is giving me a bool error of Embedded Statement.
I tried the other approach I had read from the second post which was to use this code which authenticates only Username:
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "LDAP://example.com/OU=Computers,OU=Users,dc=example,dc=com");
UserPrincipal user = UserPrincipal.FindByIdentity(pc, "username");
bool userExists = (user != null);
But I found that I wont be able to authenticate a password using this method as UserPrincipal.FindByPassword does not exist.
I have also tried it this way but again .Password does not exist:
PrincipalContext pc = new PrincipalContext(ContextType.Domain,"LDAP://....");
UserPrincipal qbeUser = new UserPrincipal(pc);
qbeUser.EmployeeId = User;
//.Password does not exist
UserPrincipal qbePassword = new UserPrincipal(pc);
qbePassword.Password = Password;
// create your principal searcher passing in the QBE principal
PrincipalSearcher srchUser = new PrincipalSearcher(qbeUser);
PrincipalSearcher srchPass = new PrincipalSearcher(qbePassword);
// try to find that user and password
UserPrincipal founduser = srchUser.FindOne() as UserPrincipal;
UserPrincipal foundpass = srchPass.FindOne() as UserPrincipal;
if (founduser != null)
{
if (foundpass != null)
{
Main m = new Main();
this.Close();
m.Show();
}
else
{
MessageBox.Show("Password Not Valid.");
textBox2.Clear();
textBox2.Focus();
}
}
else
{
MessageBox.Show("Username Not Valid.");
textBox1.Clear();
textBox1.Focus();
}
Can someone kindly please instruct me as how one should correctly approach this.
Thank you in advance.
I have done this but not with PrincipalContext. Instead I have found many people struggling using that object.
My implemenatation was a winforms form and the submit button calls a method executing the 4 las lines of the code below.
I tested against this magnificent free to test LDAP server
var path = "LDAP://ldap.forumsys.com:389/dc=example,dc=com";
var user = $#"uid={username},dc=example,dc=com";
var pass = "password";
var directoryEntry = new DirectoryEntry(path, user, pass, AuthenticationTypes.None);
var searcher = new DirectorySearcher(directoryEntry);
searcher.PropertiesToLoad.Add("*");
var searchResult = searcher.FindOne();
I donĀ“t understand exactly what all of this lines does.
Important tips
On the path the "LDAP://" string should be on block mayus.
In the user, according to the test server you use "cn=username-admin" for validating admins, be sure to also set Authentication type to ServerBind.

Categories

Resources