└── LDAPClient ├── .vs └── LDAPClient │ └── v14 │ └── .suo ├── LDAPClient.sln └── LDAPClient ├── App.config ├── Client.cs ├── LDAPClient.csproj ├── LDAPClient.csproj.user ├── Program.cs ├── Properties └── AssemblyInfo.cs └── UserModel.cs /LDAPClient/.vs/LDAPClient/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-blog/blog-ldap-csharp-example/2896e13da738e1867dd6dabe6a509d5aa1c3a852/LDAPClient/.vs/LDAPClient/v14/.suo -------------------------------------------------------------------------------- /LDAPClient/LDAPClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LDAPClient", "LDAPClient\LDAPClient.csproj", "{05169A47-7FF3-4D3F-BF8A-5ED71CAE30BE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {05169A47-7FF3-4D3F-BF8A-5ED71CAE30BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {05169A47-7FF3-4D3F-BF8A-5ED71CAE30BE}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {05169A47-7FF3-4D3F-BF8A-5ED71CAE30BE}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {05169A47-7FF3-4D3F-BF8A-5ED71CAE30BE}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/Client.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.DirectoryServices.Protocols; 7 | using System.Net; 8 | using System.Security.Cryptography; 9 | 10 | namespace LDAPClient 11 | { 12 | /// 13 | /// A sample LDAP client. For simplicity reasons, this clients only uses synchronous requests. 14 | /// 15 | public class Client 16 | { 17 | public Client(string username, string domain, string password, string url) 18 | { 19 | var credentials = new NetworkCredential(username, password, domain); 20 | var serverId = new LdapDirectoryIdentifier(url); 21 | 22 | connection = new LdapConnection(serverId, credentials); 23 | connection.Bind(); 24 | } 25 | 26 | /// 27 | /// Performs a search in the LDAP server. This method is generic in its return value to show the power 28 | /// of searches. A less generic search method could be implemented to only search for users, for instance. 29 | /// 30 | /// The distinguished name of the base node at which to start the search 31 | /// An LDAP filter as defined by RFC4515 32 | /// A flat list of dictionaries which in turn include attributes and the distinguished name (DN) 33 | public List> search(string baseDn, string ldapFilter) 34 | { 35 | var request = new SearchRequest(baseDn, ldapFilter, SearchScope.Subtree, null); 36 | var response = (SearchResponse)connection.SendRequest(request); 37 | 38 | var result = new List>(); 39 | 40 | foreach(SearchResultEntry entry in response.Entries) 41 | { 42 | var dic = new Dictionary(); 43 | dic["DN"] = entry.DistinguishedName; 44 | 45 | foreach (string attrName in entry.Attributes.AttributeNames) 46 | { 47 | //For simplicity, we ignore multi-value attributes 48 | dic[attrName] = string.Join(",", entry.Attributes[attrName].GetValues(typeof(string))); 49 | } 50 | 51 | result.Add(dic); 52 | } 53 | 54 | return result; 55 | } 56 | 57 | /// 58 | /// Adds a user to the LDAP server database. This method is intentionally less generic than the search one to 59 | /// make it easier to add meaningful information to the database. 60 | /// 61 | /// The user to add 62 | public void addUser(UserModel user) 63 | { 64 | var sha1 = new SHA1Managed(); 65 | var digest = Convert.ToBase64String(sha1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(user.UserPassword))); 66 | 67 | var request = new AddRequest(user.DN, new DirectoryAttribute[] { 68 | new DirectoryAttribute("uid", user.UID), 69 | new DirectoryAttribute("ou", user.OU), 70 | new DirectoryAttribute("userPassword", "{SHA}" + digest), 71 | new DirectoryAttribute("objectClass", new string[] { "top", "account", "simpleSecurityObject" }) 72 | }); 73 | 74 | connection.SendRequest(request); 75 | } 76 | 77 | /// 78 | /// This method shows how to modify an attribute. 79 | /// 80 | /// Old user UID 81 | /// New user UID 82 | public void changeUserUid(string oldUid, string newUid) 83 | { 84 | var oldDn = string.Format("uid={0},ou=users,dc=example,dc=com", oldUid); 85 | var newDn = string.Format("uid={0},ou=users,dc=example,dc=com", newUid); 86 | 87 | DirectoryRequest request = new ModifyDNRequest(oldDn, "ou=users,dc=example,dc=com", "uid=" + newUid); 88 | connection.SendRequest(request); 89 | 90 | request = new ModifyRequest(newDn, DirectoryAttributeOperation.Replace, "uid", new string[] { newUid }); 91 | connection.SendRequest(request); 92 | } 93 | 94 | /// 95 | /// This method shows how to delete anything by its distinguised name (DN). 96 | /// 97 | /// Distinguished name of the entry to delete 98 | public void delete(string dn) 99 | { 100 | var request = new DeleteRequest(dn); 101 | connection.SendRequest(request); 102 | } 103 | 104 | /// 105 | /// Searches for a user and compares the password. 106 | /// We assume all users are at base DN ou=users,dc=example,dc=com and that passwords are 107 | /// hashed using SHA1 (no salt) in OpenLDAP format. 108 | /// 109 | /// Username 110 | /// Password 111 | /// true if the credentials are valid, false otherwise 112 | public bool validateUser(string username, string password) 113 | { 114 | var sha1 = new SHA1Managed(); 115 | var digest = Convert.ToBase64String(sha1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password))); 116 | var request = new CompareRequest(string.Format("uid={0},ou=users,dc=example,dc=com", username), 117 | "userPassword", "{SHA}" + digest); 118 | var response = (CompareResponse)connection.SendRequest(request); 119 | return response.ResultCode == ResultCode.CompareTrue; 120 | } 121 | 122 | /// 123 | /// Another way of validating a user is by performing a bind. In this case the server 124 | /// queries its own database to validate the credentials. It is defined by the server 125 | /// how a user is mapped to its directory. 126 | /// 127 | /// Username 128 | /// Password 129 | /// true if the credentials are valid, false otherwise 130 | public bool validateUserByBind(string username, string password) 131 | { 132 | bool result = true; 133 | var credentials = new NetworkCredential(username, password); 134 | var serverId = new LdapDirectoryIdentifier(connection.SessionOptions.HostName); 135 | 136 | var conn = new LdapConnection(serverId, credentials); 137 | try 138 | { 139 | conn.Bind(); 140 | } 141 | catch (Exception) 142 | { 143 | result = false; 144 | } 145 | 146 | conn.Dispose(); 147 | 148 | return result; 149 | } 150 | 151 | private LdapConnection connection; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/LDAPClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {05169A47-7FF3-4D3F-BF8A-5ED71CAE30BE} 8 | Exe 9 | Properties 10 | LDAPClient 11 | LDAPClient 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/LDAPClient.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | test example.com test 192.168.122.1:389 5 | 6 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace LDAPClient 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | if(args.Length != 4) 14 | { 15 | Console.WriteLine("Usage: LDAPClient "); 16 | Environment.Exit(1); 17 | } 18 | 19 | var client = new Client(args[0], args[1], args[2], args[3]); 20 | 21 | try 22 | { 23 | //Adding a user 24 | client.addUser(new UserModel("uid=sampleuser,ou=users,dc=example,dc=com", 25 | "sampleuser", "users", "plaintextpass")); 26 | } catch(Exception e) 27 | { 28 | //The user may already exist 29 | Console.WriteLine(e); 30 | } 31 | 32 | //Searching for all users 33 | var searchResult = client.search("ou=users,dc=example,dc=com", "objectClass=*"); 34 | foreach(Dictionary d in searchResult) 35 | { 36 | Console.WriteLine(String.Join("\r\n", d.Select(x => x.Key + ": " + x.Value).ToArray())); 37 | } 38 | 39 | //Validating credentials 40 | if(client.validateUser("sampleuser", "plaintextpass")) 41 | { 42 | Console.WriteLine("Valid credentials"); 43 | } 44 | else 45 | { 46 | Console.WriteLine("Invalid credentials"); 47 | } 48 | 49 | //Validating credentials using LDAP bind 50 | //For this to work the server must be configured to map users correctly to its internal database 51 | if(client.validateUserByBind("sampleuser", "plaintextpass")) 52 | { 53 | Console.WriteLine("Valid credentials (bind)"); 54 | } 55 | else 56 | { 57 | Console.WriteLine("Invalid credentials (bind)"); 58 | } 59 | 60 | //Modifying a user 61 | client.changeUserUid("sampleuser", "newsampleuser"); 62 | 63 | //Deleting a user 64 | client.delete("uid=newsampleuser,ou=users,dc=example,dc=com"); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LDAPClient")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LDAPClient")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("05169a47-7ff3-4d3f-bf8a-5ed71cae30be")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LDAPClient/LDAPClient/UserModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace LDAPClient 8 | { 9 | public class UserModel 10 | { 11 | public UserModel(string dn, string uid, string ou, string userPassword) 12 | { 13 | this.dn = dn; 14 | this.uid = uid; 15 | this.ou = ou; 16 | this.userPassword = userPassword; 17 | } 18 | 19 | public string DN { get { return dn; } } 20 | public string UID { get { return uid; } } 21 | public string OU { get { return ou; } } 22 | public string UserPassword { get { return userPassword; } } 23 | 24 | private string dn; 25 | private string uid; 26 | private string ou; 27 | private string userPassword; 28 | } 29 | } 30 | --------------------------------------------------------------------------------