└── 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 |
--------------------------------------------------------------------------------