.NET Core LDAP

Home / .NET Core LDAP

.NET Core doesn’t have built-in support for LDAP (Active Directory). This can be a show-stopper for a lot of projects. It was a bit of a show-stopper for me earlier as well.

So, references to these libraries won’t be available:

System.DirectoryServices
System.DirectoryServices.AccountManagement
System.DirectoryServices.Protcols

But, there are alternatives to mitigate the problem.


Reading through the Microsoft Github issues, some of these libs may be added in .NET Core 2.0, but I have no idea what the implementation will look like.

In the meantime, here are two ports of Novell’s LDAP libraries that target .NET Core.

https://github.com/VQComms/CsharpLDAP/tree/coreclrPort
https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard

The latter is available in Nuget:

https://www.nuget.org/packages/Novell.Directory.Ldap.NETStandard/

I’ve written some LDAP queries using this library and it works well. The basic flow isn’t much different from using the DirectoryServices DirectoryEntry and search functionality. The only downside I could see is that the binding (authentication) does not take advantage of the currently logged in Windows user. A username/password must be specified. Below are my samples that will search for groups (and their children) and then find any user within those group(s).

private static ILdapConnection _conn;

void Main()
{
	var groups = SearchForGroup("MyAdGroup");
	SearchForUser("MyCompany", groups);
}

static ILdapConnection GetConnection()
{
	LdapConnection ldapConn = _conn as LdapConnection;

	if (ldapConn == null)
	{
		// Creating an LdapConnection instance 
		ldapConn = new LdapConnection() { SecureSocketLayer = true };

		//Connect function will create a socket connection to the server - Port 389 for insecure and 3269 for secure	
		ldapConn.Connect("ADServrName", 3269);

		//Bind function with null user dn and password value will perform anonymous bind to LDAP server 
		ldapConn.Bind(@"domain\username", "password");
	}

	return ldapConn;
}

HashSet<string> SearchForGroup(string groupName)
{
	var ldapConn = GetConnection();
	var groups = new HashSet<string>();

	var searchBase = string.Empty;
	var filter = $"(&(objectClass=group)(cn={groupName}))";
	var search = ldapConn.Search(searchBase, LdapConnection.SCOPE_SUB, filter, null, false);
	while (search.hasMore())
	{
		var nextEntry = search.next();
		groups.Add(nextEntry.DN);
		var childGroups = GetChildren(string.Empty, nextEntry.DN);
		foreach (var child in childGroups)
		{
			groups.Add(child);
		}
	}

	return groups;
}

static HashSet<string> GetChildren(string searchBase, string groupDn, string objectClass = "group")
{
	var ldapConn = GetConnection();
	var listNames = new HashSet<string>();

	var filter = $"(&(objectClass={objectClass})(memberOf={groupDn}))";
	var search = ldapConn.Search(searchBase, LdapConnection.SCOPE_SUB, filter, null, false);

	while (search.hasMore())
	{
		var nextEntry = search.next();
		listNames.Add(nextEntry.DN);
		var children = GetChildren(string.Empty, nextEntry.DN);
		foreach (var child in children)
		{
			listNames.Add(child);
		}
	}

	return listNames;
}

void SearchForUser(string company, HashSet<string> groups = null)
{
	var ldapConn = GetConnection();
	var users = new HashSet<string>();

	string groupFilter = (groups?.Count ?? 0) > 0 ?
		$"(|{string.Join("", groups.Select(x => $"(memberOf={x})").ToList())})" :
		string.Empty;
	var searchBase = string.Empty;
	string filter = $"(&(objectClass=user)(objectCategory=person)(company={company}){groupFilter})";
	var search = ldapConn.Search(searchBase, LdapConnection.SCOPE_SUB, filter, null, false);

	while (search.hasMore())
	{
		var nextEntry = search.next();
		nextEntry.getAttributeSet();
		users.Add(nextEntry.DN);
	}
}

4 thoughts on “.NET Core LDAP”

  1. Good how about.

    First congratulate you on your blog, which is fine.

    Second I wanted to ask you, I am trying to create mailboxes in Ldp from Asp.Net core using this library and I do not see anywhere the method that had the DirectoryEntry class to add a group and commit.

    You could give me a hand saying in this library where that method is or an example of how to call it.
    Thanks in advance.

    1. I’ll play around with it some today. I do have another project using DIrectoryServices in which I’m creating users, but not mailboxes. I think the code I have for creating users can be ported relatively easily. Howevery, for Mailboxes (if you’re using Exchange), my thought was to use the Automation namespaces and Powershell cmdlets in an attempt to create Exchange mailboxes.

      1. Good afternoon
        Thanks for replying to me, I think they are Outlook mailboxes not exchange anyway then I enclose a code of how we created the mailboxes earlier with the DirectoryEntry Class:

        DirectoryEntry new_UsersGroup = objUSERSAD_UsersGroups.Add (“CN =” + des_group_name, “group”);
        New_UsersGroup.Properties [“cn”]. Value = des_group_name;
        New_UsersGroup.Properties [“sAMAccountName”]. Value = des_group_name.Replace (“”, “”);
        New_UsersGroup.Properties [“managedby”] Value = dn_responsable;
        New_UsersGroup.Properties [“displayName”]. Value = des_group_name;
        New_UsersGroup.Properties [“legacyExchangeDN”]. Value = FactoriaServices. ServiceParametrizacion.ObtenerConfiguracion (“legacyExchangeDN”) + des_mail;
        New_UsersGroup.Properties [“mail”]. Value = des_mail;
        New_UsersGroup.Properties [“mailNickName”]. Value = des_group_name.Replace (“”, “.”);
        New_UsersGroup.Properties [“msExchPoliciesIncluded”]. Value = FactoriaServices.ServicioParametrizacion.ObtenerConfiguracion (“msExchPoliciesIncluded”);
        New_UsersGroup.Properties [“msExchRecipientDisplayType”]. Value = FactoriaServices.ServicioParametrizacion.ObtenerConfiguracion (“msExchRecipientDisplayType”);
        New_UsersGroup.Properties [“msExchRequireAuthToSendTo”]. Value = FactoriaServices.ServiceParametrizacion.ObtenerConfiguracion (“msExchRequireAuthToSendTo”);
        New_UsersGroup.Properties [“msExchVersion”]. Value = FactoriaServices.ServicioParametrizacion.ObtenerConfiguration (“msExchVersion”);
        New_UsersGroup.Properties [“internetEncoding”]. Value = FactoriaServices. ServiceParametrizacion.ObtenerConfiguration (“internetEncoding”);
        New_UsersGroup.Properties [“proxyAddresses”]. Value = “SMTP:” + new_UsersGroup.Properties [“mail”].
        New_UsersGroup.Properties [“proxyAddresses”]. Add (“smtp:” + des_group_name.Replace (“”, “.”) + “@ Everis.exch”);
        New_UsersGroup.Properties [“reportToOriginator”]. Value = FactoriaServices. ServiceParametrizacion.ObtenerConfiguracion (“reportToOriginator”);
        New_UsersGroup.Properties [“showInAddressBook”]. Value = showInAddressBook1;
        New_UsersGroup.Properties [“showInAddressBook”]. Add (showInAddressBook2);
        New_UsersGroup.Properties [“groupType”]. Value = FactoriaServicios.ServicioParametrizacion.ObtenerConfiguracion (“groupType”);
        String textHTML = FactoriaServicios.ServicioParametrizacion.ObtenerConfiguracion (“descriptionCreado”);
        String descriptionCreated = Server.HtmlDecode (textHTML);
        New_UsersGroup.Properties [“description”]. Value = descriptionCreated + “” + System.DateTime.Now.ToShortDateString ();
        New_UsersGroup.CommitChanges ();

Leave a Reply