Geesh_SO
Geesh_SO

Reputation: 2206

With access to Active Directory, can I get an object GUID for a user from an username/email address alone?

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

Answers (1)

Gabriel Luci
Gabriel Luci

Reputation: 40938

You're on the right track with DirectorySeacher. You just need a proper query, and a few other tweaks.

  1. Modify the Filter so you find what you're looking for.

    a. If you have the email address:

    • (&(objectClass=user)(objectClass=person)([email protected]))
    • Or, (&(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.

    • User Principal Name: (&(objectClass=user)(objectClass=person)([email protected]))
    • What is normally called the "username", which is often formatted like DOMAIN\username: (&(objectClass=user)(objectClass=person)(sAMAccountName=myusername))
  2. Use DirectorySeacher.PropertiesToLoad. If you don't, it will retrieve every attribute that has a value, which is just wasted network traffic.

  3. 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

Related Questions