.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); } }
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.
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.
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 ();
I researched this a little bit (finally!) today. I don’t have a specific code example that I have put together, but there is one here from Novell that details creating a new DirectoryEntry. It should be a similar process for the .NET Core port.
https://www.novell.com/documentation/developer/ldapcsharp/?page=/documentation/developer/ldapcsharp/cnet/data/bovumfi.html
How would you do this that you attached earlier with the book of Novel?
Any news on if this is supported in 2.0 core ? I need to write a small app to unlock locked out users in ldap
The Novell.Ldap port should work in 2.0 Core. I haven’t tried it, but I see no reason that it wouldn’t work.
Hello, I’m using this nuget trying to change user password in an Active Directory, my user has permissions for change password.
if I use “System.DirectoryServices
System.DirectoryServices.AccountManagement
System.DirectoryServices.Protcols”
I can change password without problem. Using novell ldap I got this error:
“{LdapException: Insufficient Access Rights (50) Insufficient Access Rights
LdapException: Server Message: 00002098: SecErr: DSID-03150F93, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
”
with this user I can change other properties but not password using novell ldap. any suggestion? I tryed everithing that I found arround the web.
I hope anyone can help me.
Thanks and cheers.
How are you attempting to change the password?
I think the typical form is like this, but haven’t had cause to attempt changing a user’s password:
I used the following code to create a new user in active directory. From this, the new user is created in active directory without any error. But, I could not work with that new user using its password, here i am set the password using “userPassword” attribute.
Is this correct way to set password for user using “userPassword” attribute or please guide me the correct workflow to achieve this?
LdapAttributeSet attributeSet = new LdapAttributeSet();
attributeSet.Add(new LdapAttribute(“objectclass”, “user”));
attributeSet.Add(new LdapAttribute(“sAMAccountName”, “myuser”));
attributeSet.Add(new LdapAttribute(“userPRincipalName”, “myuser”));
attributeSet.Add(new LdapAttribute(“userAccountControl”, (66080).ToString()));
attributeSet.Add(new LdapAttribute(“userPassword”, “mypassword”));
string dn = “CN=myuser,CN=Users,DC=mydomain,DC=com”;
LdapEntry newEntry = new LdapEntry(dn, attributeSet);
LdapConnection ldapConn = new LdapConnection();
ldapConn.Connect(ldapHost, 369);
ldapConn.Bind(loginDN, password);
ldapConn.Add(newEntry);
I recently wrote an application that does this very thing, but it’s using the older legacy .NET (4.6.x) LDAP mechanisms (DirectoryEntry, mostly). I’ll see if I can convert it over to the Ldap library and provide a working code snippet.
Thanks. Please give working code?
See my comment above regarding setting a password. I think it illustrates the proper way to set the password.