Reputation: 2206
Background
I've been experimenting with active directory access in C# to find out how to connect/validate credentials in various ways. At the bottom of this answer I've included some code snippets to give an idea of what I've done, maybe this can be built upon to fulfill my aim.
Main Aim
If I have valid credentials for connecting to an Active Directory, can I take an string representing a username/email address (assuming it exists in the userPrincipalName
or similar field), and get back the objectGUID
?
Or do I need to take other things into account like: the permissions those credentials have to search other users; knowledge of the structure of different ADs; if userPrincipalName
is the correct field to search?
Code Snippets (experimental beginnings, not fully functional for my aim)
var credentials = new NetworkCredential(username, password, hostname);
var serverId = new LdapDirectoryIdentifier(hostname);
var connection = new LdapConnection(serverId, credentials);
try
{
connection.Bind();
}
catch (Exception e)
{
//error
Console.WriteLine(e);
connection.Dispose();
return;
}
//success
var dirEntry = new DirectoryEntry(string.Format("LDAP://{0}/{1}", hostname, baseDn), username, password);
var searcher = new DirectorySearcher(dirEntry)
{
Filter = "(&(&(objectClass=user)(objectClass=person)))"
};
var resultCollection = searcher.FindAll();
searcher.Dispose();
Upvotes: 1
Views: 818
Reputation: 40938
You're on the right track with DirectorySeacher
. You just need a proper query, and a few other tweaks.
Modify the Filter
so you find what you're looking for.
a. If you have the email address:
(&(objectClass=user)(objectClass=person)([email protected]))
(&(objectClass=user)(objectClass=person)(proxyAddresses=smtp:[email protected]))
(this will match against secondary email addresses too)b. If you have a username, it depends which username you have.
(&(objectClass=user)(objectClass=person)([email protected]))
(&(objectClass=user)(objectClass=person)(sAMAccountName=myusername))
Use DirectorySeacher.PropertiesToLoad
. If you don't, it will retrieve every attribute that has a value, which is just wasted network traffic.
You don't need to dispose the DirectorySearcher
, but you do need to dispose resultCollection
since the documentation says you can end up with a memory leak if you leave it up to garbage collection.
So, assuming you have the userPrincipalName
, you would have something like this:
var userToLookFor = "[email protected]";
var dirEntry = new DirectoryEntry(string.Format("LDAP://{0}/{1}", hostname, baseDn), username, password);
var searcher = new DirectorySearcher(dirEntry)
{
Filter = $"(&(objectClass=user)(objectClass=person)(userPrincipalName={userToLookFor}))",
SizeLimit = 1 //we're only looking for one account
};
searcher.PropertiesToLoad.Add("objectGuid");
using (var resultCollection = searcher.FindAll())
{
if (resultCollection.Count == 1)
{
var userGuid = new Guid((byte[]) resultCollection[0].Properties["objectGuid"][0]);
}
else
{
//the account was not found - do something else
}
}
Upvotes: 1