From 1fb6b1343440ca8192c097f9618bcf0c8c9371aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E4=BA=AE?= Date: Fri, 31 May 2019 19:10:05 +0800 Subject: [PATCH] feature: implement the interfaces for reading/writing LDAP. include: Authenticate Query Organizations Add Organization Query Users Query User --- framework/Volo.Abp.sln | 18 +- .../src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj | 24 ++ .../Volo/Abp/Ldap/AbpLdapModule.cs | 18 + .../OrganizationNotExistException.cs | 11 + .../Volo/Abp/Ldap/ILdapManager.cs | 72 ++++ .../Volo/Abp/Ldap/LdapCredentials.cs | 9 + .../Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs | 34 ++ .../Volo/Abp/Ldap/LdapManager.cs | 332 ++++++++++++++++++ .../Volo/Abp/Ldap/LdapOptions.cs | 24 ++ .../Volo/Abp/Ldap/Modeling/ILdapEntry.cs | 11 + .../Abp/Ldap/Modeling/ILdapOrganization.cs | 7 + .../Volo/Abp/Ldap/Modeling/ILdapUser.cs | 11 + .../Volo/Abp/Ldap/Modeling/LdapEntryBase.cs | 24 ++ .../Abp/Ldap/Modeling/LdapOrganization.cs | 17 + .../Volo/Abp/Ldap/Modeling/LdapUser.cs | 25 ++ framework/src/Volo.Abp.Ldap/readme.md | 173 +++++++++ .../Volo.Abp.Ldap.Tests.csproj | 18 + .../Volo/Abp/Ldap/Authenticate_Tests.cs | 70 ++++ .../Volo/Abp/Ldap/LdapHelps_Tests.cs | 84 +++++ .../Volo/Abp/Ldap/LdapManager_Tests.cs | 245 +++++++++++++ .../Volo/Abp/Ldap/LdapTestData.cs | 27 ++ 21 files changed, 1252 insertions(+), 2 deletions(-) create mode 100644 framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapOptions.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs create mode 100644 framework/src/Volo.Abp.Ldap/readme.md create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs 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