{"id":23885919,"url":"https://github.com/flamencist/ldap4net","last_synced_at":"2025-05-16T05:07:18.979Z","repository":{"id":29824355,"uuid":"122486058","full_name":"flamencist/ldap4net","owner":"flamencist","description":"OpenLdap port for DotNet Core (Linux\\OSX\\Windows)","archived":false,"fork":false,"pushed_at":"2024-04-22T06:43:47.000Z","size":877,"stargazers_count":222,"open_issues_count":40,"forks_count":39,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-11T08:18:14.640Z","etag":null,"topics":["activedirectory","ad","c-sharp","csharp","digest-md5","dotnet","gssapi","kerberos","ldap","ldapfornet","linux","macos","mono","openldap","osx","sasl","sasl-external","unix","windows"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flamencist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-22T14:00:41.000Z","updated_at":"2025-05-08T06:29:39.000Z","dependencies_parsed_at":"2024-06-20T22:00:08.860Z","dependency_job_id":null,"html_url":"https://github.com/flamencist/ldap4net","commit_stats":{"total_commits":255,"total_committers":19,"mean_commits":"13.421052631578947","dds":"0.19999999999999996","last_synced_commit":"35c83028c6e0349023c5bd317dbcf0fbdfdf05b9"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flamencist%2Fldap4net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flamencist%2Fldap4net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flamencist%2Fldap4net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flamencist%2Fldap4net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flamencist","download_url":"https://codeload.github.com/flamencist/ldap4net/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254471060,"owners_count":22076585,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activedirectory","ad","c-sharp","csharp","digest-md5","dotnet","gssapi","kerberos","ldap","ldapfornet","linux","macos","mono","openldap","osx","sasl","sasl-external","unix","windows"],"created_at":"2025-01-04T05:54:38.421Z","updated_at":"2025-05-16T05:07:13.964Z","avatar_url":"https://github.com/flamencist.png","language":"C#","readme":"# ldap4net\n\n[![Build Status](https://travis-ci.com/flamencist/ldap4net.svg?branch=master)](https://travis-ci.com/flamencist/ldap4net)\n[![Build Status](https://dev.azure.com/achermyanin/ldap4net/_apis/build/status/flamencist.ldap4net?branchName=master)](https://dev.azure.com/achermyanin/ldap4net/_build/latest?definitionId=1\u0026branchName=master)\n[![NuGet](https://img.shields.io/nuget/v/LdapForNet.svg)](https://www.nuget.org/packages/LdapForNet/)\n[![Total NuGet downloads](https://img.shields.io/nuget/dt/LdapForNet?color=blue\u0026label=downloads\u0026logo=nuget)](https://www.nuget.org/stats/packages/LdapForNet?groupby=Version\u0026groupby=ClientName\u0026groupby=ClientVersion%20%22Total%20NuGet%20downloads%22)\n\nCross platform port of OpenLdap Client library (https://www.openldap.org/software/man.cgi?query=ldap)  \nand Windows Ldap (https://docs.microsoft.com/en-us/windows/win32/api/_ldap/) to DotNet Core\n\nHelp support the project:\n\n\u003ca href=\"https://www.buymeacoffee.com/flamencist\" target=\"_blank\"\u003e\u003cimg src=\"https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png\" alt=\"Buy Me A Coffee\" style=\"height: auto !important;width: auto !important;\" \u003e\u003c/a\u003e\n\nFor Linux\\OSX you must ensure you have the latest OpenLDAP client libraries installed from http://www.openldap.org\n\nFor Linux you must also ensure that the appropriate [symlinks for `libldap.so.2` and `liblber.so.2`](linux.md) exist.\n\nIt works with any LDAP protocol compatible directory server (including Microsoft Active Directory).\n\nSupported paswordless authentication (Kerberos) on all platforms (on Linux\\OSX supported SASL GSSAPI (Kerberos) authentication!).\n\n\n\nSample usage (Kerberos authentication)\n\n```cs\nusing (var cn = new LdapConnection())\n{\n\t// connect\n\tcn.Connect();\n\t// bind using kerberos credential cache file\n\tcn.Bind();\n\t// call ldap op\n\tvar entries = cn.Search(\"\u003c\u003cbasedn\u003e\u003e\", \"(objectClass=*)\");\n}\n\n```\n\n## Overview\n\n* [Supported platforms](#supported-platforms)\n* [Installation](#installation)\n* [API](#api)\n\t* [Connect](#connect)\n\t* [Connect TLS](#connect-tls)\n\t* [Connect SSL (with self signed certificate)](#connect-ssl-with-self-signed-certificate)\n\t* [Connect Timeout](#connect-timeout)\n\t* [Bind](#bind)\n\t* [BindAsync](#bindAsync)\n\t* [Bind Anonymous](#bind-anonymous)\n\t* [Bind DIGEST-MD5](#bind-digest-md5)\n\t* [Bind SASL EXTERNAL (Client certificate)](#bind-sasl-external-client-certificate)\n\t* [Bind SASL EXTERNAL (Client certificate \u0026 Active Directory)](#bind-sasl-external-client-certificate--active-directory)\n\t* [Bind SASL EXTERNAL (Unix Socket)](#bind-sasl-external-unix-socket)\n\t* [Bind SASL proxy](#bind-sasl-proxy)\n\t* [Search](#search)\n\t* [Search (attributes with binary values)](#search-attributes-with-binary-values)\n\t* [Search (retrieve concrete list of attributes)](#search-retrieve-concrete-list-of-attributes)\n\t* [SearchAsync](#searchAsync)\n\t* [SearchByCn](#searchbycn)\n\t* [SearchBySid](#searchbysid)\n\t* [GetOption](#getoption)\n\t* [SetOption](#setoption)\n\t* [Add](#add)\n\t* [Add Binary Values](#add-binary-values)\n\t* [AddAsync](#addAsync)\n\t* [Modify](#modify)\n\t* [Modify Binary Values](#modify-binary-values)\n\t* [Reset password](#reset-password)\n\t* [Change password](#change-password)\n\t* [ModifyAsync](#modifyAsync)\n\t* [Delete](#delete)\n\t* [DeleteAsync](#deleteAsync)\n\t* [Rename](#rename)\n\t* [RenameAsync](#renameAsync)\n\t* [SendRequest](#sendRequest)\n\t* [SendRequestAsync](#sendRequestAsync)\n\t* [Ldap V3 Controls](#ldap-v3-controls)\n\t\t* [PageResultRequestControl\\PageResultResponseControl](#pageresultrequestcontrolpageresultresponsecontrol-1284011355614319)\n\t\t* [DirSyncRequestControl\\DirSyncRequestControl](#dirsyncrequestcontroldirsyncresponsecontrol-1284011355614841)\n\t\t* [SortRequestControl\\SortResponseControl](#sortrequestcontrolsortresponsecontrol-12840113556144731284011355614474)\n\t\t* [AsqRequestControl\\AsqResponseControl](#asqrequestcontrolasqresponsecontrol-12840113556141504)\n\t\t* [DirectoryNotificationControl](#directorynotificationcontrol-1284011355614528)\n\t\t* [VlvRequestControl\\VlvResponseControl](#vlvrequestcontrolvlvresponsecontrol-216840111373034921684011137303410)\n\t* [GetRootDse](#getRootDse)\n\t* [WhoAmI](#whoami)\n\t* [GetNativeLdapPtr (deprecated)](#getnativeldapptr)\n\t* [License](#license)\n\t* [Authors](#authors)\n\n## Supported platforms\n\n* Most of popular Linux distributives\n* FreeBSD\n* OSX\n* Windows\n* Supported on the .NET Standard - minimum required is 2.0 - compatible .NET runtimes: .NET Core, Mono, .NET Framework.\n\n## Features:\n* Supported TLS\\SSL\n* Supported Unicode\\Binary values\n* Supported authentications:\n\t- Simple \\ Basic \\ Anonymous\n\t- SASL:\n\t\t- GSSAPI \\ Kerberos V5 \\ Negotiate \n\t\t- [DIGEST-MD5](https://ldapwiki.com/wiki/DIGEST-MD5)\n\t\t- [EXTERNAL](https://ldapwiki.com/wiki/SASL%20EXTERNAL)\n\t- [SASL proxy authorization](https://www.openldap.org/doc/admin24/sasl.html#SASL%20Proxy%20Authorization)\n* Supported LDAP V3 controls:\n\t- [PageResultRequestControl\\PageResultResponseControl](#pageresultrequestcontrolpageresultresponsecontrol-1284011355614319)\n\t- [DirSyncRequestControl\\DirSyncRequestControl](#dirsyncrequestcontroldirsyncresponsecontrol-1284011355614841)\n\t- [SortRequestControl\\SortResponseControl](#sortrequestcontrolsortresponsecontrol-12840113556144731284011355614474)\n\t- [AsqRequestControl\\AsqResponseControl](#asqrequestcontrolasqresponsecontrol-12840113556141504)\n\t- [DirectoryNotificationControl](#directorynotificationcontrol-1284011355614528)\n\t- [VlvRequestControl\\VlvResponseControl](#vlvrequestcontrolvlvresponsecontrol-216840111373034921684011137303410)\n\n## Installation\n\n``` Install-Package LdapForNet ``` \n\n``` dotnet add package LdapForNet ```\n\n## Api\n\n### Connect\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\t// connect use Domain Controller host from computer hostname and default port 389\n\t// Computer hostname - mycomp.example.com =\u003e DC host - example.com\n\tcn.Connect();\n\t....\n}\n\n```\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\t// connect use hostname and port\n\tcn.Connect(\"dc.example.com\",636);\n\t....\n}\n\n```\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\t// connect with URI\n\tcn.Connect(new Uri(\"ldaps://dc.example.com:636\"));\n\t....\n}\n\n```\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\t// connect with ldap version 2\n\tcn.Connect(new Uri(\"ldaps://dc.example.com:636\"), LdapForNet.Native.Native.LdapVersion.LDAP_VERSION2);\n\t....\n}\n\n```\n\n### Connect TLS\n```c#\nusing (var cn = new LdapConnection())\n{\n\t// connect use hostname and port\n\tcn.Connect(\"dc.example.com\",389);\n\t//set true if use self signed certificate for developing purpose\n \tcn.StartTransportLayerSecurity(true); \n\t....\n}\n\n```\n\n### Connect SSL (with self signed certificate)\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect(\"dc.example.com\", 636, LdapSchema.LDAPS);\n\tcn.TrustAllCertificates();\n\t....\n}\n\n```\n\n### Connect Timeout\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Timeout = new TimeSpan(0, 1 ,0); // 1 minute\n\t....\n}\n```\n\n### Bind\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\t// bind using kerberos credential cache file\n\tcn.Bind();\n\t...\n}\n\n```\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect(\"ldap.forumsys.com\");\n\t// bind using userdn and password\n\tcn.Bind(LdapAuthMechanism.SIMPLE,\"cn=read-only-admin,dc=example,dc=com\",\"password\");\n\t...\n}\n\n```\n\n### BindAsync\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\t// bind using kerberos credential cache file\n\tcn.BindAsync().Wait();\n\t...\n}\n\n```\n\n### Bind Anonymous\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind(LdapAuthType.Anonymous, new LdapCredential());\n\t...\n}\n\n```\n\n### Bind DIGEST-MD5\n[About DIGEST-MD5](https://ldapwiki.com/wiki/DIGEST-MD5)\n\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n\n    cn.Bind(LdapAuthType.Digest, new LdapCredential\n    {\n        UserName = \"username\",\n        Password = \"clearTextPassword\"\n    });\n\t...\n}\n\n```\n\n### Bind SASL EXTERNAL (Client certificate)\n[About client certificate authentication in openldap](https://jpmens.net/pages/ldap-external/)\n\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect(\"dc.example.com\",636,LdapSchema.LDAPS);\n    var cert = new X509Certificate2(\"yourcert.pfx\", \"yourstrongpassword\",\n        X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);\n\n    cn.SetClientCertificate(cert);\n\n    cn.Bind(LdapAuthType.External, new LdapCredential());\n\t...\n}\n\n```\n\n### Bind SASL EXTERNAL (Client certificate \u0026 Active Directory)\n[About client certificate authentication](https://techcommunity.microsoft.com/t5/iis-support-blog/client-certificate-authentication-part-1/ba-p/324623#) \n\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect(\"dc.example.com\",636,LdapSchema.LDAPS);\n    var cert = new X509Certificate2(\"yourcert.pfx\", \"yourstrongpassword\",\n        X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);\n\n    cn.SetClientCertificate(cert);\n\n    cn.Bind(LdapAuthType.ExternalAd, new LdapCredential());\n\t...\n}\n\n```\n\n### Bind SASL EXTERNAL (Unix Socket)\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.ConnectI(\"/tmp/yoursocketfile.unix\");\n    cn.Bind(LdapAuthType.External, new LdapCredential());\n\t...\n}\n\n```\n\n### Bind SASL proxy\n[About SASL auhtorization proxy](https://www.openldap.org/doc/admin24/sasl.html#SASL%20Proxy%20Authorization)\n\nWorks on UNIX systems\n```c#\n\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n\n    cn.Bind(LdapAuthType.Digest, new LdapCredential\n    {\n        UserName = \"username\",\n        Password = \"clearTextPassword\",\n        AuthorizationId = \"dn:cn=admin,dc=example,dc=com\" \n    });\n\t...\n}\n\n```\n\nWorks on UNIX systems\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n\n    cn.Bind(LdapAuthType.Digest, new LdapCredential\n    {\n        UserName = \"username\",\n        Password = \"clearTextPassword\",\n        AuthorizationId = \"u:admin\" \n    });\n\t...\n}\n\n```\n\nWorks on UNIX systems\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n\n    cn.Bind(LdapAuthType.GssApi, new LdapCredential\n    {\n        AuthorizationId = \"u:admin\" \n    });\n\t...\n}\n\n```\n\nWorks on Windows system\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n\n    cn.Bind(LdapAuthType.Negotiate, new LdapCredential\n    {\n        UserName = \"username\",\n        Password = \"clearTextPassword\"\n    });\n\t...\n}\n\n```\n\n### Search\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search all objects in catalog (default search scope = LdapSearchScope.LDAP_SCOPE_SUBTREE)\n\tvar entries = cn.Search(\"dc=example,dc=com\",\"(objectClass=*)\");\n}\n```\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search  objects in catalog at first level scope\n\tvar entries = cn.Search(\"dc=example,dc=com\",\"(objectClass=*)\", LdapSearchScope.LDAP_SCOPE_ONELEVEL);\n}\n```\n\n### Search (attributes with binary values)\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tvar response = (SearchResponse) connection.SendRequest(new SearchRequest(\"cn=admin,dc=example,dc=com\", \"(\u0026(objectclass=top)(cn=admin))\", LdapSearchScope.LDAP_SCOPE_SUBTREE));\n\tvar directoryAttribute = response.Entries.First().Attributes[\"objectSid\"];\n\tvar objectSid = directoryAttribute.GetValues\u003cbyte[]\u003e().First();\n}\n```\n\n### Search (retrieve concrete list of attributes)\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tvar response = (SearchResponse)connection.SendRequest(new SearchRequest(Config.RootDn, \"(\u0026(objectclass=top)(cn=admin))\",LdapSearchScope.LDAP_SCOPE_SUBTREE,\"cn\",\"objectClass\"));\n\tvar count = entries[0].Attributes.AttributeNames.Count; // 2\n}\n```\n\n### SearchAsync\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search all objects in catalog (default search scope = LdapSearchScope.LDAP_SCOPE_SUBTREE)\n\tvar entries = cn.SearchAsync(\"dc=example,dc=com\",\"(objectClass=*)\").Result;\n}\n```\n\n### SearchByCn  \n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search  by CN, get @base from machine hostname (my.example.com =\u003e dn=example,dn=com )\n\tvar entries = cn.SearchByCn(\"read-only-admin\");\n}\n```\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search  by CN\n\tvar entries = cn.SearchByCn(\"ou=admins,dn=example,dn=com\", \"read-only-admin\", LdapSearchScope.LDAP_SCOPE_ONELEVEL);\n}\n\n```\n\n\n### SearchBySid  \n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search  by CN, get @base from machine hostname (my.example.com =\u003e dn=example,dn=com )\n\tvar entries = cn.SearchBySid(\"S-1-5-21-2127521184-1604012920-1887927527-72713\");\n}\n```\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\t//search  by CN\n\tvar entries = cn.SearchBySid(\"ou=admins,dn=example,dn=com\", \"S-1-5-21-2127521184-1604012920-1887927527-72713\", LdapSearchScope.LDAP_SCOPE_ONELEVEL);\n}\n\n```\n\n### GetOption\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tvar ldapVersion = cn.GetOption\u003cint\u003e(LdapOption.LDAP_OPT_PROTOCOL_VERSION);\n\tvar host = cn.GetOption\u003cstring\u003e(LdapOption.LDAP_OPT_HOST_NAME);\n\tvar refferals = cn.GetOption\u003cIntPtr\u003e(LdapOption.LDAP_OPT_REFERRALS);\n\tcn.Bind();\n}\n```\n\n### SetOption\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tvar ldapVersion = (int)LdapVersion.LDAP_VERSION3;\n\tcn.SetOption(LdapOption.LDAP_OPT_PROTOCOL_VERSION, ref ldapVersion);\n\tcn.Bind();\n}\n```\n\n### Add\n   \n   \n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    cn.Add(new LdapEntry\n    {\n    Dn = \"cn=test,dc=example,dc=com\",\n    Attributes = new Dictionary\u003cstring, List\u003cstring\u003e\u003e\n    {\n        {\"sn\", new List\u003cstring\u003e {\"Winston\"}},\n        {\"objectclass\", new List\u003cstring\u003e {\"inetOrgPerson\"}},\n        {\"givenName\", new List\u003cstring\u003e {\"your_name\"}},\n        {\"description\", new List\u003cstring\u003e {\"your_description\"}}\n    }\n    });\n}\n```\n\n### Add Binary Values\n\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    var image = new DirectoryAttribute\n    {\n        Name = \"jpegPhoto\"\n    };\n    image.Add(new byte[]{1,2,3,4});\n    directoryEntry.Attributes.Add(image);\n    var response = (AddResponse)connection.SendRequest(new AddRequest(\"cn=test,dc=example,dc=com\", image));\n}\n   ```\n\n\n### AddAsync\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tawait cn.AddAsync(new LdapEntry\n\t{\n\tDn = \"cn=test,dc=example,dc=com\",\n\tAttributes = new Dictionary\u003cstring, List\u003cstring\u003e\u003e\n\t{\n\t    {\"sn\", new List\u003cstring\u003e {\"Winston\"}},\n\t    {\"objectclass\", new List\u003cstring\u003e {\"inetOrgPerson\"}},\n\t    {\"givenName\", new List\u003cstring\u003e {\"your_name\"}},\n\t    {\"description\", new List\u003cstring\u003e {\"your_description\"}}\n\t}\n\t});\n}\n```\n\n### Modify\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tcn.Modify(new LdapModifyEntry\n\t{\n\tDn = \"cn=test,dc=example,dc=com\",\n\tAttributes = new List\u003cLdapModifyAttribute\u003e\n\t{\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_REPLACE,\n\t\tType = \"givenName\",\n\t\tValues = new List\u003cstring\u003e {\"test_value_2\"}\n\t    },\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_ADD,\n\t\tType = \"displayName\",\n\t\tValues = new List\u003cstring\u003e {\"test_display_name\"}\n\t    },\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_ADD,\n\t\tType = \"sn\",\n\t\tValues = new List\u003cstring\u003e {\"test\"}\n\t    },\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_DELETE,\n\t\tType = \"description\",\n\t\tValues = new List\u003cstring\u003e {\"test_value\"}\n\t    }\n\t}\n\t});\n}\n```\n\n\n### Modify Binary Values\n\n```c#\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    var image = new DirectoryModificationAttribute\n    {\n        LdapModOperation = LdapModOperation.LDAP_MOD_REPLACE,\n        Name = \"jpegPhoto\"\n    };\n    image.Add(new byte[]{ 5, 6, 7, 8});\n    var response = (ModifyResponse)connection.SendRequest(new ModifyRequest(\"cn=test,dc=example,dc=com\", image));\n}\n```\n\n### Reset password\n\nMicrosoft Active Directory\n\n```c#\nusing (var cn = new LdapConnection())\n{\n      // need use ssl/tls for reset password\n      cn.Connect(\"dc.example.com\", 636, LdapSchema.LDAPS);\n      cn.Bind();\n    \n      var attribute = new DirectoryModificationAttribute()\n      {\n          Name = \"unicodePwd\",\n          LdapModOperation = Native.LdapModOperation.LDAP_MOD_REPLACE\n      };\n    \n      string password = \"\\\"strongPassword\\\"\";\n      byte[] encodedBytes = System.Text.Encoding.Unicode.GetBytes(password);\n      attribute.Add\u003cbyte[]\u003e(encodedBytes);\n    \n      var response = (ModifyResponse)cn.SendRequest(new ModifyRequest(\"CN=yourUser,CN=Users,dc=dc,dc=local\", attribute));\n}\n```\n\n### Change password\n\nMicrosoft Active Directory\n\n```c#\nusing (var cn = new LdapConnection())\n{\n      // need use ssl/tls for reset password\n      cn.Connect(\"dc.example.com\", 636, LdapSchema.LDAPS);\n      cn.Bind();\n\n      var oldPasswordAttribute = new DirectoryModificationAttribute\n      {\n            Name = \"unicodePwd\",\n            LdapModOperation = Native.LdapModOperation.LDAP_MOD_DELETE\n      };\n\n      oldPasswordAttribute.Add(Encoding.Unicode.GetBytes($\"\\\"{oldPassword}\\\"\"));\n\n      var newPasswordAttribute = new DirectoryModificationAttribute\n      {\n            Name = \"unicodePwd\",\n            LdapModOperation = Native.LdapModOperation.LDAP_MOD_ADD\n      };\n\n      newPasswordAttribute.Add(Encoding.Unicode.GetBytes($\"\\\"{newPassword}\\\"\"));\n\n      var response = await _ldapConnection.Value.SendRequestAsync(new ModifyRequest(\"CN=yourUser,CN=Users,dc=dc,dc=local\", oldPasswordAttribute, newPasswordAttribute));\n}\n```\n\n### ModifyAsync\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tawait cn.ModifyAsync(new LdapModifyEntry\n\t{\n\tDn = \"cn=test,dc=example,dc=com\",\n\tAttributes = new List\u003cLdapModifyAttribute\u003e\n\t{\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_REPLACE,\n\t\tType = \"givenName\",\n\t\tValues = new List\u003cstring\u003e {\"test_value_2\"}\n\t    },\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_ADD,\n\t\tType = \"displayName\",\n\t\tValues = new List\u003cstring\u003e {\"test_display_name\"}\n\t    },\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_ADD,\n\t\tType = \"sn\",\n\t\tValues = new List\u003cstring\u003e {\"test\"}\n\t    },\n\t    new LdapModifyAttribute\n\t    {\n\t\tLdapModOperation = LdapModOperation.LDAP_MOD_DELETE,\n\t\tType = \"description\",\n\t\tValues = new List\u003cstring\u003e {\"test_value\"}\n\t    }\n\t}\n\t});\n}\n```\n\n### Delete\n\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tcn.Delete(\"cn=test,dc=example,dc=com\");\n}\n```\n\n### DeleteAsync\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tawait cn.DeleteAsync(\"cn=test,dc=example,dc=com\");\n}\n```\n\n### Rename\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tcn.Rename(\"cn=test,dc=example,dc=com\", \"cn=test2\", null, true);\n}\n```\n\n### RenameAsync\n\n```c#\nusing (var cn = new LdapConnection())\n{\n\tcn.Connect();\n\tcn.Bind();\n\tawait cn.RenameAsync(\"cn=test,dc=example,dc=com\", \"cn=test2\", null, true);\n}\n```\n\n### SendRequest\nGeneric method for ldap requests.\nInspired by .NET Framework LdapConnection.SendRequest\n\n ```cs\n using (var cn = new LdapConnection())\n {\n \tcn.Connect();\n \tcn.Bind();\n \tcn.SendRequest(new DeleteRequest(\"cn=test,dc=example,dc=com\"));\n }\n ```\n\n### SendRequestAsync\nGeneric method for ldap requests.\nInspired by .NET Framework LdapConnection.SendRequest\n\n ```cs\n using (var cn = new LdapConnection())\n {\n \tcn.Connect();\n \tcn.Bind();\n \tvar cancellationTokenSource = new CancellationTokenSource();\n \t//whoami\n \tvar res = await cn.SendRequestAsync(new ExtendedRequest(\"1.3.6.1.4.1.4203.1.11.3\"), cancellationTokenSource.Token);\n \tvar extendedResponse = (ExtendedResponse) res;\n \tvar name = Encoding.UTF8.GetString(extendedResponse.ResponseValue);\n }\n ```\n\n### Ldap V3 Controls\n#### PageResultRequestControl\\PageResultResponseControl [(1.2.840.113556.1.4.319)](https://ldapwiki.com/wiki/Simple%20Paged%20Results%20Control)\n```c#\n\nusing (var cn = new LdapConnection())\n{\n    var results = new List\u003cDirectoryEntry\u003e();\n    cn.Connect();\n    cn.Bind();\n    var directoryRequest = new SearchRequest(\"dc=example,dc=com\", \"(objectclass=top)\", LdapSearchScope.LDAP_SCOPE_SUB);\n    var resultRequestControl = new PageResultRequestControl(3);\n    directoryRequest.Controls.Add(resultRequestControl);\n\n    var response = (SearchResponse)cn.SendRequest(directoryRequest);\n    results.AddRange(response.Entries);\n\n    PageResultResponseControl pageResultResponseControl;\n    while (true)\n    {\n        pageResultResponseControl = (PageResultResponseControl)response.Controls.FirstOrDefault(_ =\u003e _ is PageResultResponseControl);\n        if (pageResultResponseControl == null || pageResultResponseControl.Cookie.Length == 0)\n        {\n            break;\n        }\n\n        resultRequestControl.Cookie = pageResultResponseControl.Cookie;\n        response = (SearchResponse)cn.SendRequest(directoryRequest);\n        results.AddRange(response.Entries);\n    }\n    var entries = results.Select(_=\u003e_.ToLdapEntry()).ToList();\n}\n```\n\nNote: If you are not getting results beyond the first page, this could because subordinate referrals are turned on as explained [here](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/ldap-paged-queries-subordinate-referrals-not-chased). In that case, one option is to turn off subordinate referrals (as described in option 3 in the link's suggested workarounds). This can be done as follows:\n\n```c#\ncn.SetOption(LdapOption.LDAP_OPT_REFERRALS, IntPtr.Zero);\n```\n\n#### DirSyncRequestControl\\DirSyncResponseControl [(1.2.840.113556.1.4.841)](https://ldapwiki.com/wiki/Directory%20Synchronization%20Control)\nLdap user should have ``DS-Replication-Get-Changes`` extended right (https://docs.microsoft.com/en-us/windows/win32/ad/polling-for-changes-using-the-dirsync-control)\n```c#\n\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    var directoryRequest = new SearchRequest(\"dc=example,dc=com\", \"(objectclass=top)\", LdapSearchScope.LDAP_SCOPE_SUB);\n    var dirSyncRequestControl = new DirSyncRequestControl\n    {\n        Cookie = new byte[0],\n        Option = DirectorySynchronizationOptions.IncrementalValues,\n        AttributeCount = int.MaxValue\n    };\n    directoryRequest.Controls.Add(dirSyncRequestControl);\n\n    var response = (SearchResponse)cn.SendRequest(directoryRequest);\n        \n    while (true)\n    {\n        var responseControl = (DirSyncResponseControl)response.Controls.FirstOrDefault(_ =\u003e _ is DirSyncResponseControl);\n        if (responseControl == null || responseControl.Cookie.Length == 0)\n        {\n            break;\n        }\n\n        dirSyncRequestControl.Cookie = responseControl.Cookie;\n\n        Thread.Sleep(60*1000);\n        response = (SearchResponse)cn.SendRequest(directoryRequest);\n            \n        if (response.Entries.Any())\n        {\n            //handle changes\n        }\n    }\n}\n```\n\n#### SortRequestControl\\SortResponseControl [(1.2.840.113556.1.4.473\\1.2.840.113556.1.4.474)](https://ldapwiki.com/wiki/Server%20Side%20Sort%20Control)\n```c#\n\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    var directoryRequest = new SearchRequest(\"dc=example,dc=com\", \"(objectclass=top)\", LdapSearchScope.LDAP_SCOPE_SUB);\n\n    directoryRequest.Controls.Add(new SortRequestControl(\"cn\", true));\n\n    var response = (SearchResponse)cn.SendRequest(directoryRequest);\n}\n```\n\n#### AsqRequestControl\\AsqResponseControl [(1.2.840.113556.1.4.1504)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/77d880bf-aadd-4f6f-bb78-076af8e22cd8)\n```c#\n\n// get all members of group 'Domain Admins'\nusing (var connection = new LdapConnection())\n{\n    connection.Connect();\n    connection.BindAsync().Wait();\n    var directoryRequest = new SearchRequest(\"CN=Domain Admins,CN=Users,dc=example,dc=com\", \"(objectClass=user)\", LdapSearchScope.LDAP_SCOPE_BASE);\n    directoryRequest.Controls.Add(new AsqRequestControl(\"member\"));\n\n    var response = (SearchResponse)connection.SendRequest(directoryRequest);\n}\n```\n\n#### DirectoryNotificationControl [(1.2.840.113556.1.4.528)](https://ldapwiki.com/wiki/LDAP_SERVER_NOTIFICATION_OID)\n```c#\n\n//get single notification from ldap server\nvar cts = new CancellationTokenSource();\nusing (var connection = new LdapConnection())\n{\n    var results = new List\u003cDirectoryEntry\u003e();\n    connection.Connect();\n    connection.BindAsync().Wait();\n    var directoryRequest = new SearchRequest(\"CN=Administrator,CN=Users,dc=example,dc=com\", \"(objectClass=*)\", LdapSearchScope.LDAP_SCOPE_BASE, \"mail\")\n    {\n        OnPartialResult = searchResponse =\u003e\n        {\n            results.AddRange(searchResponse.Entries);\n            cts.Cancel();\n        }\n    };\n    var directoryNotificationControl = new DirectoryNotificationControl();\n    directoryRequest.Controls.Add(directoryNotificationControl);\n\n\n    var response = (SearchResponse) connection.SendRequestAsync(directoryRequest,cts.Token).Result;\n                \n}\n```\n\n#### VlvRequestControl\\VlvResponseControl [(2.16.840.1.113730.3.4.9\\2.16.840.1.113730.3.4.10)](https://docs.microsoft.com/en-us/windows/win32/controls/use-virtual-list-view-controls)\n\n```c#\nusing (var connection = new LdapConnection())\n{\n    var results = new List\u003cDirectoryEntry\u003e();\n    connection.Connect();\n    connection.Bind();\n    var directoryRequest = new SearchRequest(\"dc=example,dc=com\", \"(objectClass=*)\", LdapSearchScope.LDAP_SCOPE_SUB);\n    var pageSize = 3;\n\n    var vlvRequestControl = new VlvRequestControl(0, pageSize - 1, 1);\n    directoryRequest.Controls.Add(new SortRequestControl(\"cn\", false));\n    directoryRequest.Controls.Add(vlvRequestControl);\n\n    while (true)\n    {\n        var response = (SearchResponse)connection.SendRequest(directoryRequest);\n        results.AddRange(response.Entries);\n        var vlvResponseControl = (VlvResponseControl)response.Controls.Single(_ =\u003e _.GetType() == typeof(VlvResponseControl));\n        vlvRequestControl.Offset += pageSize;\n        if(vlvRequestControl.Offset \u003e vlvResponseControl.ContentCount)\n        {\n            break;\n        }\n    }\n                \n    var entries = results.Select(_ =\u003e _.ToLdapEntry()).ToList();\n}\n\n```\n\n### GetRootDse\nInformation about server https://ldapwiki.com/wiki/RootDSE\n\n```c#\n\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    var rootDse =  connection.GetRootDse();\n}\n```\n\n### WhoAmI\nReturns authorization id of user https://ldapwiki.com/wiki/Who%20Am%20I%20Extended%20Operation\n\n```c#\n\nusing (var cn = new LdapConnection())\n{\n    cn.Connect();\n    cn.Bind();\n    var authzId = connection.WhoAmI().Result;\n}\n```\n\n### License\n\nThis software is distributed under the terms of the MIT License (MIT).\n\n### Authors\n\nAlexander Chermyanin / [LinkedIn](https://www.linkedin.com/in/alexander-chermyanin)\n\n\n\nContributions and bugs reports are welcome.\n","funding_links":["https://www.buymeacoffee.com/flamencist"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflamencist%2Fldap4net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflamencist%2Fldap4net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflamencist%2Fldap4net/lists"}