diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln
index be77f0ab24..42e4b28516 100644
--- a/framework/Volo.Abp.sln
+++ b/framework/Volo.Abp.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.168
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28922.388
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}"
EndProject
@@ -238,6 +238,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Dashboards", "src\Volo.Abp.AspNetCore.Mvc.UI.Dashboards\Volo.Abp.AspNetCore.Mvc.UI.Dashboards.csproj", "{054D766D-5992-460E-A4D8-936D80BE2C1A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Ldap", "src\Volo.Abp.Ldap\Volo.Abp.Ldap.csproj", "{4DADBBD2-4C63-4C90-9661-EBF6252A7D6F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Ldap.Tests", "test\Volo.Abp.Ldap.Tests\Volo.Abp.Ldap.Tests.csproj", "{38FB8F75-426E-4265-8D0E-E121837B6FCC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -708,6 +712,14 @@ Global
{054D766D-5992-460E-A4D8-936D80BE2C1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{054D766D-5992-460E-A4D8-936D80BE2C1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{054D766D-5992-460E-A4D8-936D80BE2C1A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4DADBBD2-4C63-4C90-9661-EBF6252A7D6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4DADBBD2-4C63-4C90-9661-EBF6252A7D6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4DADBBD2-4C63-4C90-9661-EBF6252A7D6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4DADBBD2-4C63-4C90-9661-EBF6252A7D6F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {38FB8F75-426E-4265-8D0E-E121837B6FCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {38FB8F75-426E-4265-8D0E-E121837B6FCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {38FB8F75-426E-4265-8D0E-E121837B6FCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {38FB8F75-426E-4265-8D0E-E121837B6FCC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -829,6 +841,8 @@ Global
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{054D766D-5992-460E-A4D8-936D80BE2C1A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
+ {4DADBBD2-4C63-4C90-9661-EBF6252A7D6F} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
+ {38FB8F75-426E-4265-8D0E-E121837B6FCC} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}
diff --git a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj
new file mode 100644
index 0000000000..6b1cba1094
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.Ldap
+ Volo.Abp.Ldap
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs
new file mode 100644
index 0000000000..22b9ca7a76
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs
@@ -0,0 +1,18 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Autofac;
+using Volo.Abp.Modularity;
+
+namespace Volo.Abp.Ldap
+{
+ [DependsOn(
+ typeof(AbpAutofacModule)
+ )]
+ public class AbpLdapModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var configuration = context.Services.GetConfiguration();
+ Configure(configuration.GetSection("LDAP"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs
new file mode 100644
index 0000000000..9d7fb220cc
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.Ldap.Exceptions
+{
+ public class OrganizationNotExistException : BusinessException
+ {
+ public OrganizationNotExistException(string distinguishedName)
+ : base("LDAP:000001", $"the organization distinguished named {distinguishedName} does not exist.")
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs
new file mode 100644
index 0000000000..f14e88b409
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs
@@ -0,0 +1,72 @@
+using System.Collections.Generic;
+using Volo.Abp.Ldap.Modeling;
+
+namespace Volo.Abp.Ldap
+{
+ public interface ILdapManager
+ {
+ ///
+ /// query the specified organizations.
+ ///
+ /// filter: (&(name=xxx)(objectClass=organizationalUnit)) when name is not null
+ /// filter: (&(name=*)(objectClass=organizationalUnit)) when name is null
+ ///
+ ///
+ ///
+ ///
+ IList GetOrganizations(string name = null);
+
+ ///
+ /// query the specified organization.
+ ///
+ /// filter: (&(distinguishedName=xxx)(objectClass=organizationalUnit)) when organizationName is not null
+ ///
+ ///
+ ///
+ ///
+ LdapOrganization GetOrganization(string distinguishedName);
+
+ void AddSubOrganization(string organizationName, LdapOrganization parentOrganization);
+ void AddSubOrganization(string organizationName, string parentDistinguishedName);
+
+ ///
+ /// query the specified users.
+ ///
+ /// filter: (&(name=xxx)(objectCategory=person)(objectClass=user)) when name is not null
+ /// filter: (&(name=*)(objectCategory=person)(objectClass=user)) when name is null
+ ///
+ /// filter: (&(displayName=xxx)(objectCategory=person)(objectClass=user)) when displayName is not null
+ /// filter: (&(displayName=*)(objectCategory=person)(objectClass=user)) when displayName is null
+ ///
+ /// filter: (&(cn=xxx)(objectCategory=person)(objectClass=user)) when commonName is not null
+ /// filter: (&(cn=*)(objectCategory=person)(objectClass=user)) when commonName is null
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ IList GetUsers(string name = null, string displayName = null, string commonName = null);
+
+ ///
+ /// query the specified User.
+ ///
+ /// filter: (&(distinguishedName=xxx)(objectCategory=person)(objectClass=user)) when distinguishedName is not null
+ ///
+ ///
+ ///
+ ///
+ LdapUser GetUser(string distinguishedName);
+
+ void AddUserToOrganization(string userName, string password, LdapOrganization parentOrganization);
+ void AddUserToOrganization(string userName, string password, string parentDistinguishedName);
+
+ ///
+ /// Authenticate
+ ///
+ /// E.g administrator@yourdomain.com.cn
+ ///
+ ///
+ bool Authenticate(string userDomainName, string password);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs
new file mode 100644
index 0000000000..a2d2eefd74
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs
@@ -0,0 +1,9 @@
+namespace Volo.Abp.Ldap
+{
+ public class LdapCredentials
+ {
+ public string DomainUserName { get; set; }
+
+ public string Password { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs
new file mode 100644
index 0000000000..49a60a964f
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.Ldap
+{
+ public static class LdapHelps
+ {
+ public static string BuildCondition(string name, string value)
+ {
+ return string.IsNullOrWhiteSpace(value) ? "" : $"({name}={value})";
+ }
+
+ public static string BuildFilter(Dictionary conditions)
+ {
+ if (null == conditions )
+ {
+ conditions = new Dictionary();
+ }
+
+ if (conditions.Keys.Count == 0)
+ {
+ conditions.Add("objectClass", "*"); // add default condition
+ }
+
+ var subFilter = string.Empty;
+ foreach (var keyValuePair in conditions)
+ {
+ subFilter += BuildCondition(keyValuePair.Key, keyValuePair.Value);
+ }
+
+ return $"(&{subFilter})";
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs
new file mode 100644
index 0000000000..615b22d70e
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs
@@ -0,0 +1,332 @@
+using System;
+using Microsoft.Extensions.Options;
+using Novell.Directory.Ldap;
+using System.Collections.Generic;
+using System.Text;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Ldap.Exceptions;
+using Volo.Abp.Ldap.Modeling;
+
+namespace Volo.Abp.Ldap
+{
+ public class LdapManager : ILdapManager, ITransientDependency
+ {
+ private readonly string _searchBase;
+ private readonly LdapOptions _ldapOptions;
+
+ private readonly string[] _attributes =
+ {
+ "objectCategory", "objectClass", "cn", "name", "distinguishedName",
+ "ou",
+ "sAMAccountName", "userPrincipalName", "telephoneNumber", "mail"
+ };
+
+ public LdapManager(IOptions ldapSettingsOptions)
+ {
+ _ldapOptions = ldapSettingsOptions.Value;
+ _searchBase = _ldapOptions.SearchBase;
+ }
+
+ #region Organization
+ ///
+ /// query the specified organizations.
+ ///
+ /// filter: (&(name=xxx)(objectClass=organizationalUnit)) when name is not null
+ /// filter: (&(objectClass=organizationalUnit)) when name is null
+ ///
+ ///
+ ///
+ ///
+ public IList GetOrganizations(string name = null)
+ {
+ var conditions = new Dictionary
+ {
+ {"name", name},
+ {"objectClass", "organizationalUnit"},
+ };
+ return Query(_searchBase, conditions);
+ }
+
+ ///
+ /// query the specified organization.
+ ///
+ /// filter: (&(distinguishedName=xxx)(objectClass=organizationalUnit)) when organizationName is not null
+ ///
+ ///
+ ///
+ ///
+ public LdapOrganization GetOrganization(string distinguishedName)
+ {
+ distinguishedName = Check.NotNullOrWhiteSpace(distinguishedName, nameof(distinguishedName));
+ var conditions = new Dictionary
+ {
+ {"distinguishedName", distinguishedName},
+ {"objectClass", "organizationalUnit"},
+ };
+ return QueryOne(_searchBase, conditions);
+ }
+
+ public void AddSubOrganization(string organizationName, LdapOrganization parentOrganization)
+ {
+ organizationName = Check.NotNullOrWhiteSpace(organizationName, nameof(organizationName));
+ var dn = $"OU={organizationName},{parentOrganization.DistinguishedName}";
+
+ var attributeSet = new LdapAttributeSet
+ {
+ new LdapAttribute("objectCategory", $"CN=Organizational-Unit,CN=Schema,CN=Configuration,{_ldapOptions.DomainDistinguishedName}"),
+ new LdapAttribute("objectClass", new[] {"top", "organizationalUnit"}),
+ new LdapAttribute("name", organizationName),
+ };
+
+ var newEntry = new LdapEntry(dn, attributeSet);
+
+ using (var ldapConnection = GetConnection())
+ {
+ ldapConnection.Add(newEntry);
+ }
+ }
+
+ public void AddSubOrganization(string organizationName, string parentDistinguishedName)
+ {
+ organizationName = Check.NotNullOrWhiteSpace(organizationName, nameof(organizationName));
+ parentDistinguishedName =
+ Check.NotNullOrWhiteSpace(parentDistinguishedName, nameof(parentDistinguishedName));
+
+ var parentOrganization = GetOrganization(parentDistinguishedName);
+ if (null == parentOrganization)
+ {
+ throw new OrganizationNotExistException(parentDistinguishedName);
+ }
+
+ AddSubOrganization(organizationName, parentOrganization);
+ }
+
+ #endregion
+
+ #region User
+ ///
+ /// query the specified users.
+ ///
+ /// filter: (&(name=xxx)(objectCategory=person)(objectClass=user)) when name is not null
+ /// filter: (&(objectCategory=person)(objectClass=user)) when name is null
+ ///
+ /// filter: (&(displayName=xxx)(objectCategory=person)(objectClass=user)) when displayName is not null
+ /// filter: (&(objectCategory=person)(objectClass=user)) when displayName is null
+ ///
+ /// filter: (&(cn=xxx)(objectCategory=person)(objectClass=user)) when commonName is not null
+ /// filter: (&(objectCategory=person)(objectClass=user)) when commonName is null
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public IList GetUsers(string name = null, string displayName = null, string commonName = null)
+ {
+ var conditions = new Dictionary
+ {
+ {"objectCategory", "person"},
+ {"objectClass", "user"},
+ {"name", name},
+ {"displayName", displayName},
+ {"cn", commonName},
+ };
+ return Query(_searchBase, conditions);
+ }
+
+ ///
+ /// query the specified User.
+ ///
+ /// filter: (&(distinguishedName=xxx)(objectCategory=person)(objectClass=user)) when distinguishedName is not null
+ ///
+ ///
+ ///
+ ///
+ public LdapUser GetUser(string distinguishedName)
+ {
+ distinguishedName = Check.NotNullOrWhiteSpace(distinguishedName, nameof(distinguishedName));
+ var conditions = new Dictionary
+ {
+ {"objectCategory", "person"},
+ {"objectClass", "user"},
+ {"distinguishedName", distinguishedName},
+ };
+ return QueryOne(_searchBase, conditions);
+ }
+
+ public void AddUserToOrganization(string userName, string password, LdapOrganization parentOrganization)
+ {
+ var dn = $"CN={userName},{parentOrganization.DistinguishedName}";
+ var mail = $"{userName}@{_ldapOptions.DomainName}";
+ sbyte[] encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\""));
+
+ var attributeSet = new LdapAttributeSet
+ {
+ new LdapAttribute("instanceType", "4"),
+ new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{_ldapOptions.DomainDistinguishedName}"),
+ new LdapAttribute("objectClass", new[] {"top", "person", "organizationalPerson", "user"}),
+ new LdapAttribute("name", userName),
+ new LdapAttribute("cn", userName),
+ new LdapAttribute("sAMAccountName", userName),
+ new LdapAttribute("userPrincipalName", userName),
+ new LdapAttribute("sn", userName),
+ new LdapAttribute("displayName", userName),
+ new LdapAttribute("unicodePwd", encodedBytes),
+ new LdapAttribute("userAccountControl", "512"),
+ new LdapAttribute("mail", mail),
+ };
+ var newEntry = new LdapEntry(dn, attributeSet);
+
+ using (var ldapConnection = GetConnection())
+ {
+ ldapConnection.Add(newEntry);
+ }
+ }
+
+ public void AddUserToOrganization(string userName, string password, string parentDistinguishedName)
+ {
+ var dn = $"CN={userName},{parentDistinguishedName}";
+ var mail = $"{userName}@{_ldapOptions.DomainName}";
+ sbyte[] encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\""));
+
+ var attributeSet = new LdapAttributeSet
+ {
+ new LdapAttribute("instanceType", "4"),
+ new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{_ldapOptions.DomainDistinguishedName}"),
+ new LdapAttribute("objectClass", new[] {"top", "person", "organizationalPerson", "user"}),
+ new LdapAttribute("name", userName),
+ new LdapAttribute("cn", userName),
+ new LdapAttribute("sAMAccountName", userName),
+ new LdapAttribute("userPrincipalName", userName),
+ new LdapAttribute("sn", userName),
+ new LdapAttribute("displayName", userName),
+ new LdapAttribute("unicodePwd", encodedBytes),
+ new LdapAttribute("userAccountControl", "512"),
+ new LdapAttribute("mail", mail),
+ };
+ var newEntry = new LdapEntry(dn, attributeSet);
+
+ using (var ldapConnection = GetConnection())
+ {
+ ldapConnection.Add(newEntry);
+ }
+ }
+
+ #endregion
+
+ #region Authenticate
+
+ ///
+ /// Authenticate
+ ///
+ /// E.g administrator@yourdomain.com.cn
+ ///
+ ///
+ public bool Authenticate(string userDomainName, string password)
+ {
+ try
+ {
+ using (GetConnection(userDomainName, password))
+ {
+ return true;
+ }
+ }
+ catch (Exception )
+ {
+ return false;
+ }
+ }
+
+ #endregion
+
+ private ILdapConnection GetConnection(string bindUserName = null, string bindUserPassword = null)
+ {
+ // bindUserName/bindUserPassword only be used when authenticate
+ bindUserName = bindUserName ?? _ldapOptions.Credentials.DomainUserName;
+ bindUserPassword = bindUserPassword ?? _ldapOptions.Credentials.Password;
+
+ var ldapConnection = new LdapConnection() { SecureSocketLayer = _ldapOptions.UseSsl };
+ if (_ldapOptions.UseSsl)
+ {
+ ldapConnection.UserDefinedServerCertValidationDelegate += (sender, certificate, chain, sslPolicyErrors) => true;
+ }
+ ldapConnection.Connect(_ldapOptions.ServerHost, _ldapOptions.ServerPort);
+
+ if (_ldapOptions.UseSsl)
+ {
+ ldapConnection.Bind(LdapConnection.Ldap_V3, bindUserName, bindUserPassword);
+ }
+ else
+ {
+ ldapConnection.Bind(bindUserName, bindUserPassword);
+ }
+ return ldapConnection;
+ }
+
+ private IList Query(string searchBase, Dictionary conditions) where T : class, ILdapEntry
+ {
+ var filter = LdapHelps.BuildFilter(conditions);
+
+ var result = new List();
+
+ using (var ldapConnection = GetConnection())
+ {
+ var search = ldapConnection.Search(searchBase, LdapConnection.SCOPE_SUB, filter,
+ _attributes, false, null, null);
+
+ LdapMessage message;
+ while ((message = search.getResponse()) != null)
+ {
+ if (!(message is LdapSearchResult searchResultMessage))
+ {
+ continue;
+ }
+ var entry = searchResultMessage.Entry;
+ if (typeof(T) == typeof(LdapOrganization))
+ {
+ result.Add(new LdapOrganization(entry.getAttributeSet()) as T);
+ }
+
+ if (typeof(T) == typeof(LdapUser))
+ {
+ result.Add(new LdapUser(entry.getAttributeSet()) as T);
+ }
+ }
+ }
+ return result;
+ }
+
+ private T QueryOne(string searchBase, Dictionary conditions) where T : class, ILdapEntry
+ {
+ var filter = LdapHelps.BuildFilter(conditions);
+
+ using (var ldapConnection = GetConnection())
+ {
+ var search = ldapConnection.Search(searchBase, LdapConnection.SCOPE_SUB, filter,
+ _attributes, false, null, null);
+
+ LdapMessage message;
+ while ((message = search.getResponse()) != null)
+ {
+ if (!(message is LdapSearchResult searchResultMessage))
+ {
+ continue;
+ }
+ var entry = searchResultMessage.Entry;
+ if (typeof(T) == typeof(LdapOrganization))
+ {
+ return new LdapOrganization(entry.getAttributeSet()) as T;
+ }
+
+ if (typeof(T) == typeof(LdapUser))
+ {
+ return new LdapUser(entry.getAttributeSet()) as T;
+ }
+ return null;
+ }
+ }
+ return null;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapOptions.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapOptions.cs
new file mode 100644
index 0000000000..7e4aacfa0e
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapOptions.cs
@@ -0,0 +1,24 @@
+namespace Volo.Abp.Ldap
+{
+ public class LdapOptions
+ {
+ public string ServerHost { get; set; }
+
+ public int ServerPort { get; set; }
+
+ public bool UseSsl { get; set; }
+
+ public string SearchBase { get; set; }
+
+ public string DomainName { get; set; }
+
+ public string DomainDistinguishedName { get; set; }
+
+ public LdapCredentials Credentials { get; set; }
+
+ public LdapOptions()
+ {
+ Credentials = new LdapCredentials();
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs
new file mode 100644
index 0000000000..f15775fc06
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.Ldap.Modeling
+{
+ public interface ILdapEntry
+ {
+ string ObjectCategory { get; set; }
+ string[] ObjectClass { get; set; }
+ string Name { get; set; }
+ string DistinguishedName { get; set; }
+ string CommonName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs
new file mode 100644
index 0000000000..07c11000e8
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs
@@ -0,0 +1,7 @@
+namespace Volo.Abp.Ldap.Modeling
+{
+ public interface ILdapOrganization : ILdapEntry
+ {
+ string OrganizationUnit { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs
new file mode 100644
index 0000000000..8ef68f6607
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs
@@ -0,0 +1,11 @@
+namespace Volo.Abp.Ldap.Modeling
+{
+ public interface ILdapUser : ILdapEntry
+ {
+ string SamAccountName { get; set; }
+ string UserPrincipalName { get; set; }
+ string DisplayName { get; set; }
+ string Email { get; set; }
+ string Phone { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs
new file mode 100644
index 0000000000..6658a983d0
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs
@@ -0,0 +1,24 @@
+using Novell.Directory.Ldap;
+
+namespace Volo.Abp.Ldap.Modeling
+{
+ public abstract class LdapEntryBase : ILdapEntry
+ {
+ public string ObjectCategory { get; set; }
+ public string[] ObjectClass { get; set; }
+ public string Name { get; set; }
+ public string CommonName { get; set; }
+ public string DistinguishedName { get; set; }
+
+ protected LdapEntryBase() { }
+
+ protected LdapEntryBase(LdapAttributeSet attributeSet)
+ {
+ ObjectCategory = attributeSet.getAttribute("objectCategory")?.StringValue;
+ ObjectClass = attributeSet.getAttribute("objectClass")?.StringValueArray;
+ Name = attributeSet.getAttribute("name")?.StringValue;
+ CommonName = attributeSet.getAttribute("cn")?.StringValue;
+ DistinguishedName = attributeSet.getAttribute("distinguishedName")?.StringValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs
new file mode 100644
index 0000000000..e401a2514d
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs
@@ -0,0 +1,17 @@
+using Novell.Directory.Ldap;
+
+namespace Volo.Abp.Ldap.Modeling
+{
+ public class LdapOrganization : LdapEntryBase, ILdapOrganization
+ {
+ public string OrganizationUnit { get; set; }
+
+ public LdapOrganization() { }
+
+ public LdapOrganization(LdapAttributeSet attributeSet)
+ : base(attributeSet)
+ {
+ OrganizationUnit = attributeSet.getAttribute("ou")?.StringValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs
new file mode 100644
index 0000000000..d9f554d512
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs
@@ -0,0 +1,25 @@
+using Novell.Directory.Ldap;
+
+namespace Volo.Abp.Ldap.Modeling
+{
+ public class LdapUser : LdapEntryBase, ILdapUser
+ {
+ public string SamAccountName { get; set; }
+ public string UserPrincipalName { get; set; }
+ public string DisplayName { get; set; }
+ public string Email { get; set; }
+ public string Phone { get; set; }
+
+ public LdapUser() { }
+
+ public LdapUser( LdapAttributeSet attributeSet)
+ : base(attributeSet)
+ {
+ SamAccountName = attributeSet.getAttribute("sAMAccountName")?.StringValue;
+ UserPrincipalName = attributeSet.getAttribute("userPrincipalName")?.StringValue;
+ DisplayName = attributeSet.getAttribute("displayName")?.StringValue;
+ Email = attributeSet.getAttribute("mail")?.StringValue;
+ Phone = attributeSet.getAttribute("telephoneNumber")?.StringValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ldap/readme.md b/framework/src/Volo.Abp.Ldap/readme.md
new file mode 100644
index 0000000000..af86f64e99
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/readme.md
@@ -0,0 +1,173 @@
+# Volo.Abp.Ldap
+
+# Only Authenticate(not read/write AD)
+
+## Configure
+
+add section in `appsettings.json`
+
+### use SSL
+
+```json
+"LDAP": {
+ "ServerHost": "192.168.101.54",
+ "ServerPort": 636,
+ "UseSSL": true
+}
+```
+
+### not use SSL
+
+```json
+"LDAP": {
+ "ServerHost": "192.168.101.54",
+ "ServerPort": 389,
+ "UseSSL": false
+}
+```
+
+## Authenticate
+
+ Injecting `ILdapManager` into a class. For example:
+
+```csharp
+public class TaxAppService : ApplicationService
+{
+ private readonly ILdapManager _ldapManager;
+
+ public TaxAppService(ILdapManager ldapManager)
+ {
+ _ldapManager = ldapManager;
+ }
+
+ public void Authenticate(string userName, string password)
+ {
+ var result = _ldapManager.Authenticate(userName, password);
+ }
+}
+```
+
+- `userName` must be full domain name. E.g abc@abc.com
+
+# Read/Write AD
+
+## Configure
+
+### use SSL
+
+```json
+"LDAP": {
+ "ServerHost": "192.168.101.54",
+ "ServerPort": 636,
+ "UseSSL": true,
+ "Credentials": {
+ "DomainUserName": "administrator@yourdomain.com.cn",
+ "Password": "yH.20190528"
+ },
+ "SearchBase": "DC=yourdomain,DC=com,DC=cn",
+ "DomainName": "yourdomain.com.cn",
+ "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn"
+}
+```
+
+### not use SSL
+
+```json
+"LDAP": {
+ "ServerHost": "192.168.101.54",
+ "ServerPort": 389,
+ "UseSSL": false,
+ "Credentials": {
+ "DomainUserName": "administrator@yourdomain.com.cn",
+ "Password": "yH.20190528"
+ },
+ "SearchBase": "DC=yourdomain,DC=com,DC=cn",
+ "DomainName": "yourdomain.com.cn",
+ "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn"
+}
+```
+
+- `Credentials:DomainUserName` a administrator of AD.
+
+- `Credentials:Password` the password for the administrator.
+- `SearchBase`: where search from AD.
+- `DomainName`: name of you domain. no need `www`.
+- `DomainDistinguishedName`: distinguished name of root domain.
+
+## Query Organizations
+
+```cs
+// query all organizations
+// filter: (&(objectClass=organizationalUnit))
+_ldapManager.GetOrganizations();
+
+// query organizations by name
+// filter: (&(name=abc)(objectClass=organizationalUnit))
+_ldapManager.GetOrganizations("abc");
+
+```
+
+## Query Organization
+
+```csharp
+// query organization by distinguished name
+// filter: (&(distinguishedName=abc)(objectClass=organizationalUnit))
+_ldapManager.GetOrganization("abc");
+
+```
+
+## Add Organization
+
+```csharp
+// use LdapOrganization
+_ldapManager.AddSubOrganization("nameA", parentOrganization);
+
+// or use OrganizationDistinguishedName
+_ldapManager.AddSubOrganization("nameA", "OU=Domain Controllers,DC=yourdomain,DC=com,DC=cn");
+```
+
+## Query Users
+
+```cs
+// query all users
+// filter: (&(objectCategory=person)(objectClass=user))
+_ldapManager.GetUsers();
+
+// query organizations by name
+// filter: (&(name=abc)(objectCategory=person)(objectClass=user))
+_ldapManager.GetUsers(name : "abc");
+
+// query organizations by displayName
+// filter: (&(displayName=abc)(objectCategory=person)(objectClass=user))
+_ldapManager.GetUsers(displayName : "abc");
+
+// query organization by commonName
+// filter: (&(cn=abc)(objectCategory=person)(objectClass=user))
+_ldapManager.GetUsers(commonName : "abc");
+
+```
+
+## Query User
+
+```csharp
+// query a user by distinguished name
+// filter: (&(distinguishedName=abc)(objectCategory=person)(objectClass=user))
+_ldapManager.GetUser("abc");
+
+```
+
+## Add User
+
+```csharp
+// use LdapOrganization
+_ldapManager.AddUserToOrganization("nameA", "passwordA", parentOrganization);
+
+// or use OrganizationDistinguishedName
+_ldapManager.AddUserToOrganization("nameA", "passwordA", "OU=Domain Controllers,DC=yourdomain,DC=com,DC=cn");
+```
+
+# More see [unit test](../../test/Volo.Abp.Ldap.Tests)
+
+
+
+#
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj
new file mode 100644
index 0000000000..e3e1c560c8
--- /dev/null
+++ b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj
@@ -0,0 +1,18 @@
+
+
+
+ netcoreapp2.2
+ latest
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs
new file mode 100644
index 0000000000..35f631b8d2
--- /dev/null
+++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs
@@ -0,0 +1,70 @@
+using System;
+using Shouldly;
+using Volo.Abp.Modularity;
+using Xunit;
+
+namespace Volo.Abp.Ldap
+{
+
+ public class Authenticate_Tests : AbpIntegratedTest
+ {
+ protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
+ {
+ options.UseAutofac();
+ }
+
+ private readonly ILdapManager _ldapManager;
+ private readonly LdapTestData _testData;
+
+ public Authenticate_Tests()
+ {
+ // ReSharper disable once VirtualMemberCallInConstructor
+ _testData = GetRequiredService();
+ _ldapManager = GetRequiredService();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void Authenticate()
+ {
+ var result = _ldapManager.Authenticate(_testData.AdministratorDomainName, _testData.AdministratorPassword);
+
+ result.ShouldBeTrue();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void Authenticate_With_Wrong_Password()
+ {
+ var result = _ldapManager.Authenticate("NonExistentNameA", "PasswordA");
+
+ result.ShouldBeFalse();
+ }
+
+ [DependsOn(typeof(AbpLdapModule))]
+ public class TestModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ // not use ssl
+ // "LDAP": {
+ // "ServerHost": "192.168.101.54",
+ // "ServerPort": 389,
+ // "UseSSL": false
+ // }
+
+ // use ssl
+ // "LDAP": {
+ // "ServerHost": "192.168.101.54",
+ // "ServerPort": 636,
+ // "UseSSL": true
+ // }
+ Configure(settings =>
+ {
+ settings.ServerHost = "192.168.101.54";
+ settings.ServerPort = 636;
+ settings.UseSsl = true;
+ });
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs
new file mode 100644
index 0000000000..06d6834992
--- /dev/null
+++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs
@@ -0,0 +1,84 @@
+using System.Collections.Generic;
+using Shouldly;
+using Xunit;
+
+namespace Volo.Abp.Ldap
+{
+ public class LdapHelps_Tests
+ {
+
+ [Fact]
+ public void BuildCondition_With_Value()
+ {
+ // act
+ var res = LdapHelps.BuildCondition("objectClass", "testNameA");
+
+ // assert
+ res.ShouldBe("(objectClass=testNameA)");
+ }
+
+ [Fact]
+ public void BuildCondition_With_Null_Value()
+ {
+ // act
+ var res = LdapHelps.BuildCondition("objectClass", null);
+
+ // assert
+ res.ShouldBeEmpty();
+ }
+
+ [Fact]
+ public void BuildCondition_With_Empty_Value()
+ {
+ // act
+ var res = LdapHelps.BuildCondition("objectClass", "");
+
+ // assert
+ res.ShouldBeEmpty();
+ }
+
+ [Fact]
+ public void BuildCondition_With_WhiteSpace_Value()
+ {
+ // act
+ var res = LdapHelps.BuildCondition("objectClass", " ");
+
+ // assert
+ res.ShouldBeEmpty();
+ }
+
+ [Fact]
+ public void BuildFilter_With_Null_Condition()
+ {
+ // act
+ var res = LdapHelps.BuildFilter(null);
+
+ // assert
+ res.ShouldBe("(&(objectClass=*))");
+ }
+
+ [Fact]
+ public void BuildFilter_With_Empty_Condition()
+ {
+ // act
+ var res = LdapHelps.BuildFilter(new Dictionary());
+
+ // assert
+ res.ShouldBe("(&(objectClass=*))");
+ }
+
+ [Fact]
+ public void BuildFilter_With_Condition()
+ {
+ // act
+ var conditions = new Dictionary
+ {
+ {"objectClass", "testClassA"}, {"objectCategory", "testCategoryA"}, {"name", null}
+ };
+ var res = LdapHelps.BuildFilter(conditions);
+
+ // assert
+ res.ShouldBe("(&(objectClass=testClassA)(objectCategory=testCategoryA))");
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs
new file mode 100644
index 0000000000..00d9287c4f
--- /dev/null
+++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs
@@ -0,0 +1,245 @@
+using System;
+using Shouldly;
+using Volo.Abp.Modularity;
+using Xunit;
+
+namespace Volo.Abp.Ldap
+{
+
+ public class LdapManager_Tests : AbpIntegratedTest
+ {
+ protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
+ {
+ options.UseAutofac();
+ }
+
+ private readonly ILdapManager _ldapManager;
+ private readonly LdapTestData _testData;
+
+ public LdapManager_Tests()
+ {
+ // ReSharper disable once VirtualMemberCallInConstructor
+ _testData = GetRequiredService();
+ _ldapManager = GetRequiredService();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetOrganizations_With_Empty_Condition()
+ {
+ var result = _ldapManager.GetOrganizations();
+
+ result.ShouldNotBeNull();
+ result.ShouldContain(e => e.Name == _testData.DomainControllersName);
+ result.ShouldContain(e => e.DistinguishedName == _testData.DomainControllersDistinguishedName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetOrganizations_With_Name()
+ {
+ var result = _ldapManager.GetOrganizations(_testData.DomainControllersName);
+
+ result.ShouldNotBeNull();
+ result.ShouldHaveSingleItem();
+ result.ShouldContain(e => e.Name == _testData.DomainControllersName);
+ result.ShouldContain(e => e.DistinguishedName == _testData.DomainControllersDistinguishedName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetOrganizations_With_Non_Existent_Name()
+ {
+ var result = _ldapManager.GetOrganizations("NonExistentNameA");
+
+ result.ShouldNotBeNull();
+ result.ShouldBeEmpty();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetOrganization()
+ {
+ var result = _ldapManager.GetOrganization(_testData.DomainControllersDistinguishedName);
+
+ result.ShouldNotBeNull();
+ result.Name.ShouldBe(_testData.DomainControllersName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetOrganization_With_Non_Existent_DistinguishedName()
+ {
+ var result = _ldapManager.GetOrganization("NonExistentNameA");
+
+ result.ShouldBeNull();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUsers_With_Empty_Condition()
+ {
+ var result = _ldapManager.GetUsers();
+
+ result.ShouldNotBeNull();
+ result.ShouldContain(e => e.Name == _testData.AdministratorName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUsers_With_Name()
+ {
+ var result = _ldapManager.GetUsers(name: _testData.AdministratorName);
+
+ result.ShouldNotBeNull();
+ result.ShouldContain(e => e.Name == _testData.AdministratorName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUsers_With_Non_Existent_Name()
+ {
+ var result = _ldapManager.GetUsers(name: "NonExistentNameA");
+
+ result.ShouldNotBeNull();
+ result.ShouldBeEmpty();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUsers_With_CommonName()
+ {
+ var result = _ldapManager.GetUsers(commonName: _testData.AdministratorName);
+
+ result.ShouldNotBeNull();
+ result.ShouldContain(e => e.Name == _testData.AdministratorName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUsers_With_Non_Existent_CommonName()
+ {
+ var result = _ldapManager.GetUsers(commonName: "NonExistentNameA");
+
+ result.ShouldNotBeNull();
+ result.ShouldBeEmpty();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUsers_With_DisplayName()
+ {
+ var result = _ldapManager.GetUsers(displayName: _testData.AdministratorName);
+
+ result.ShouldNotBeNull();
+ // the administrator in AD. not have display name by default.
+ result.ShouldBeEmpty();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUser()
+ {
+ var result = _ldapManager.GetUser(_testData.AdministratorDistinguishedName);
+
+ result.ShouldNotBeNull();
+ result.Name.ShouldBe(_testData.AdministratorName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void GetUser_With_Non_Existent_DistinguishedName()
+ {
+ var result = _ldapManager.GetOrganization("NonExistentNameA");
+
+ result.ShouldBeNull();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void Authenticate()
+ {
+ var result = _ldapManager.Authenticate(_testData.AdministratorDomainName, _testData.AdministratorPassword);
+
+ result.ShouldBeTrue();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void Authenticate_With_Wrong_Password()
+ {
+ var result = _ldapManager.Authenticate("NonExistentNameA", "PasswordA");
+
+ result.ShouldBeFalse();
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void AddSubOrganization()
+ {
+ var parentOrganization = _ldapManager.GetOrganization(_testData.DomainControllersDistinguishedName);
+ var randomName = $"Test_{DateTime.Now.Ticks}";
+
+ _ldapManager.AddSubOrganization(randomName, parentOrganization);
+
+ var result = _ldapManager.GetOrganizations(randomName);
+ result.ShouldNotBeNull();
+ result.ShouldContain(e => e.Name == randomName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void AddSubOrganization_With_DistinguishedName()
+ {
+ var randomName = $"Test_{DateTime.Now.Ticks}";
+
+ _ldapManager.AddSubOrganization(randomName, _testData.DomainControllersDistinguishedName);
+
+ var result = _ldapManager.GetOrganizations(randomName);
+ result.ShouldNotBeNull();
+ result.ShouldContain(e => e.Name == randomName);
+ }
+
+ [Fact(Skip = "need environment AD ")]
+ public void AddOrganizationUser()
+ {
+ var parentOrganization = _ldapManager.GetOrganization(_testData.DomainControllersDistinguishedName);
+ var randomName = $"Test_{DateTime.Now:yyMMddHHmmss}";
+ _ldapManager.AddUserToOrganization(randomName, _testData.AdministratorPassword, parentOrganization);
+
+ var result = _ldapManager.GetUsers(randomName);
+ result.ShouldNotBeNull();
+ result.ShouldContain(e=>e.Name == randomName);
+ }
+
+ [DependsOn(typeof(AbpLdapModule))]
+ public class TestModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ // not use ssl
+ // "LDAP": {
+ // "ServerHost": "192.168.101.54",
+ // "ServerPort": 389,
+ // "UseSSL": false,
+ // "Credentials": {
+ // "DomainUserName": "administrator@yourdomain.com.cn",
+ // "Password": "yH.20190528"
+ // },
+ // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn",
+ // "DomainName": "yourdomain.com.cn",
+ // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn"
+ // }
+
+ // use ssl
+ // "LDAP": {
+ // "ServerHost": "192.168.101.54",
+ // "ServerPort": 636,
+ // "UseSSL": true,
+ // "Credentials": {
+ // "DomainUserName": "administrator@yourdomain.com.cn",
+ // "Password": "yH.20190528"
+ // },
+ // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn",
+ // "DomainName": "yourdomain.com.cn",
+ // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn"
+ // }
+ Configure(settings =>
+ {
+ settings.ServerHost = "192.168.101.54";
+ settings.ServerPort = 636;
+ settings.UseSsl = true;
+ settings.Credentials.DomainUserName = "administrator@yourdomain.com.cn";
+ settings.Credentials.Password = "yH.20190528";
+ settings.SearchBase = "DC=yourdomain,DC=com,DC=cn";
+ settings.DomainName = "yourdomain.com.cn";
+ settings.DomainDistinguishedName = "DC=yourdomain,DC=com,DC=cn";
+ });
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs
new file mode 100644
index 0000000000..8224686daa
--- /dev/null
+++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs
@@ -0,0 +1,27 @@
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.Ldap
+{
+ public class LdapTestData : ISingletonDependency
+ {
+ public string AdministratorName { get; } = "Administrator";
+ public string AdministratorPassword { get; } = "yH.20190528";
+ public string AdministratorDistinguishedName { get; } = "CN=Administrator,CN=Users,DC=yourdomain,DC=com,DC=cn";
+ public string AdministratorDomainName { get; } = "Administrator@yourdomain.com.cn";
+
+ public string DomainControllersName = "Domain Controllers";
+ public string DomainControllersDistinguishedName = "OU=Domain Controllers,DC=yourdomain,DC=com,DC=cn";
+
+ public string RootDistinguishedName { get; } = "DC=yourdomain,DC=com,DC=cn";
+
+ public string Organization001Name { get; } = "Test_A";
+
+ public string Test001Name { get; } = "test001";
+ public string Test001Password { get; } = "yH.20190528";
+ public string Test001Email { get; } = "test001@yourdomain.com.cn";
+
+ public string Test002Name { get; } = "test002";
+ public string Test002Password { get; } = "yH.20190528";
+ public string Test002WrongPassword { get; } = "yH.20190529";
+ }
+}
\ No newline at end of file