Merge pull request #584 from ONLYOFFICE/feature/LDAP-new

Feature/LDAP-new
This commit is contained in:
Pavel Bannov 2022-07-01 14:50:32 +03:00 committed by GitHub
commit e3e12b902f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 10506 additions and 44 deletions

View File

@ -103,6 +103,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.EventBus.Extensions.Log
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Migration", "common\ASC.Migration\ASC.Migration.csproj", "{05B8FF27-446B-49BF-B508-4A4C096D2BB2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ActiveDirectory", "common\ASC.ActiveDirectory\ASC.ActiveDirectory.csproj", "{9F81862F-303D-467F-8DC9-044BE2CCF329}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -293,6 +295,10 @@ Global
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{05B8FF27-446B-49BF-B508-4A4C096D2BB2}.Release|Any CPU.Build.0 = Release|Any CPU
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -2,6 +2,7 @@
"solution": {
"path": "ASC.Web.sln",
"projects": [
"common\\ASC.ActiveDirectory\\ASC.ActiveDirectory.csproj",
"common\\ASC.Api.Core\\ASC.Api.Core.csproj",
"common\\ASC.Common\\ASC.Common.csproj",
"common\\ASC.Core.Common\\ASC.Core.Common.csproj",

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Novell.Directory.Ldap.NETStandard" Version="3.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ASC.Common\ASC.Common.csproj" />
<ProjectReference Include="..\ASC.Core.Common\ASC.Core.Common.csproj" />
<ProjectReference Include="..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,50 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
public class ActiveDirectoryDbContext : BaseDbContext
{
public DbSet<DbTenant> Tenants { get; set; }
public DbSet<DbWebstudioSettings> WebstudioSettings { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ModelBuilderWrapper
.From(modelBuilder, _provider)
.AddDbTenant()
.AddWebstudioSettings()
.AddDbFunction();
}
}
public static class ActiveDirectoryDbContextExtention
{
public static DIHelper AddCRMDbContextService(this DIHelper services)
{
return services.AddDbContextManagerService<ActiveDirectoryDbContext>();
}
}

View File

@ -0,0 +1,173 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Data;
[Serializable]
public class LdapCertificateConfirmRequest
{
private volatile bool _approved;
private volatile bool _requested;
private volatile string _serialNumber;
private volatile string _issuerName;
private volatile string _subjectName;
private volatile string _hash;
private volatile int[] _certificateErrors;
public bool Approved { get { return _approved; } set { _approved = value; } }
public bool Requested { get { return _requested; } set { _requested = value; } }
public string SerialNumber { get { return _serialNumber; } set { _serialNumber = value; } }
public string IssuerName { get { return _issuerName; } set { _issuerName = value; } }
public string SubjectName { get { return _subjectName; } set { _subjectName = value; } }
public DateTime ValidFrom { get; set; }
public DateTime ValidUntil { get; set; }
public string Hash { get { return _hash; } set { _hash = value; } }
public int[] CertificateErrors { get { return _certificateErrors; } set { _certificateErrors = value; } }
private enum LdapCertificateProblem
{
CertExpired = -2146762495,
CertCnNoMatch = -2146762481,
// ReSharper disable once UnusedMember.Local
CertIssuerChaining = -2146762489,
CertUntrustedCa = -2146762478,
// ReSharper disable once UnusedMember.Local
CertUntrustedRoot = -2146762487,
CertMalformed = -2146762488,
CertUnrecognizedError = -2146762477
}
public static int[] GetLdapCertProblems(X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors, ILogger log = null)
{
var certificateErrors = new List<int>();
try
{
if (sslPolicyErrors == SslPolicyErrors.None)
{
return certificateErrors.ToArray();
}
var expDate = DateTime.Parse(certificate.GetExpirationDateString()).ToUniversalTime();
var utcNow = DateTime.UtcNow;
if (expDate < utcNow && expDate.AddDays(1) >= utcNow)
{
certificateErrors.Add((int)LdapCertificateProblem.CertExpired);
}
if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors))
{
certificateErrors.Add((int)LdapCertificateProblem.CertMalformed);
}
if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
{
if (log != null)
{
log.WarnGetLdapCertProblems(Enum.GetName(typeof(SslPolicyErrors), LdapCertificateProblem.CertCnNoMatch));
}
certificateErrors.Add((int)LdapCertificateProblem.CertCnNoMatch);
}
if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable))
{
if (log != null)
{
log.WarnGetLdapCertProblems(Enum.GetName(typeof(SslPolicyErrors), LdapCertificateProblem.CertCnNoMatch));
}
certificateErrors.Add((int)LdapCertificateProblem.CertUntrustedCa);
}
}
catch (Exception ex)
{
if (log != null)
{
log.ErrorGetLdapCertProblems(ex);
}
certificateErrors.Add((int)LdapCertificateProblem.CertUnrecognizedError);
}
return certificateErrors.ToArray();
}
public static LdapCertificateConfirmRequest FromCert(X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors, bool approved = false, bool requested = false, ILogger log = null)
{
var certificateErrors = GetLdapCertProblems(certificate, chain, sslPolicyErrors, log);
try
{
string serialNumber = "", issuerName = "", subjectName = "", hash = "";
DateTime validFrom = DateTime.UtcNow, validUntil = DateTime.UtcNow;
LdapUtils.SkipErrors(() => serialNumber = certificate.GetSerialNumberString(), log);
LdapUtils.SkipErrors(() => issuerName = certificate.Issuer, log);
LdapUtils.SkipErrors(() => subjectName = certificate.Subject, log);
LdapUtils.SkipErrors(() => validFrom = DateTime.Parse(certificate.GetEffectiveDateString()), log);
LdapUtils.SkipErrors(() => validUntil = DateTime.Parse(certificate.GetExpirationDateString()), log);
LdapUtils.SkipErrors(() => hash = certificate.GetCertHashString(), log);
var certificateConfirmRequest = new LdapCertificateConfirmRequest
{
SerialNumber = serialNumber,
IssuerName = issuerName,
SubjectName = subjectName,
ValidFrom = validFrom,
ValidUntil = validUntil,
Hash = hash,
CertificateErrors = certificateErrors,
Approved = approved,
Requested = requested
};
return certificateConfirmRequest;
}
catch (Exception ex)
{
if (log != null)
{
log.ErrorLdapCertificateConfirmRequest(ex);
}
return null;
}
}
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}

View File

@ -0,0 +1,88 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Data;
public class LdapLogin
{
public string Username { get; private set; }
public string Domain { get; private set; }
public LdapLogin(string username, string domain)
{
Username = username;
Domain = domain;
}
public override string ToString()
{
return !string.IsNullOrEmpty(Domain) ? string.Format("{0}@{1}", Username, Domain) : Username;
}
public static LdapLogin ParseLogin(string login)
{
if (string.IsNullOrEmpty(login))
{
return null;
}
string username;
string domain = null;
if (login.Contains("\\"))
{
var splited = login.Split('\\');
if (!splited.Any() || splited.Length != 2)
{
return null;
}
domain = splited[0];
username = splited[1];
}
else if (login.Contains("@"))
{
var splited = login.Split('@');
if (!splited.Any() || splited.Length != 2)
{
return null;
}
username = splited[0];
domain = splited[1];
}
else
{
username = login;
}
var result = new LdapLogin(username, domain);
return result;
}
}

View File

@ -0,0 +1,58 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Data;
/// <summary>
/// LDAP object class
/// </summary>
public abstract class LdapObject
{
#region .Public
public abstract string DistinguishedName { get; }
public abstract string Sid { get; }
public abstract string SidAttribute { get; }
public abstract bool IsDisabled { get; }
#endregion
/// <summary>
/// Get property object
/// </summary>
/// <param name="propertyName">property name</param>
/// <returns>value object</returns>
public abstract object GetValue(string propertyName, bool getBytes = false);
/// <summary>
/// Get property values
/// </summary>
/// <param name="propertyName">property name</param>
/// <returns>list of values</returns>
public abstract List<string> GetValues(string propertyName);
}

View File

@ -0,0 +1,271 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Mapping = ASC.ActiveDirectory.Base.Settings.LdapSettings.MappingFields;
namespace ASC.ActiveDirectory.Base.Data;
/// <summary>
/// LDAP object extensions class
/// </summary>
[Scope]
public class LdapObjectExtension
{
private readonly TenantUtil _tenantUtil;
private readonly ILogger<LdapObjectExtension> _logger;
public LdapObjectExtension(TenantUtil tenantUtil, ILogger<LdapObjectExtension> logger)
{
_tenantUtil = tenantUtil;
_logger = logger;
}
public string GetAttribute(LdapObject ldapObject, string attribute)
{
if (string.IsNullOrEmpty(attribute))
{
return string.Empty;
}
try
{
return ldapObject.GetValue(attribute) as string;
}
catch (Exception e)
{
_logger.ErrorCanNotGetAttribute(attribute, ldapObject.DistinguishedName, e);
return string.Empty;
}
}
public List<string> GetAttributes(LdapObject ldapObject, string attribute)
{
var list = new List<string>();
if (string.IsNullOrEmpty(attribute))
{
return list;
}
try
{
return ldapObject.GetValues(attribute);
}
catch (Exception e)
{
_logger.ErrorCanNotGetAttributes(attribute, ldapObject.DistinguishedName, e);
return list;
}
}
private const int MAX_NUMBER_OF_SYMBOLS = 64;
private const string EXT_MOB_PHONE = "extmobphone";
private const string EXT_MAIL = "extmail";
private const string EXT_PHONE = "extphone";
private const string EXT_SKYPE = "extskype";
private List<string> GetContacts(LdapObject ldapUser, Mapping key, LdapSettings settings)
{
if (!settings.LdapMapping.ContainsKey(key))
{
return null;
}
var bindings = settings.LdapMapping[key].Split(',').Select(x => x.Trim()).ToArray();
if (bindings.Length > 1)
{
var list = new List<string>();
foreach (var bind in bindings)
{
list.AddRange(GetAttributes(ldapUser, bind));
}
return list;
}
else
{
return GetAttributes(ldapUser, bindings[0]);
}
}
private void PopulateContacts(List<string> Contacts, string type, List<string> values)
{
if (values == null || !values.Any())
{
return;
}
foreach (var val in values)
{
Contacts.Add(type);
Contacts.Add(val);
}
}
public UserInfo ToUserInfo(LdapObject ldapUser, LdapUserImporter ldapUserImporter)
{
var settings = ldapUserImporter.Settings;
var resource = ldapUserImporter.Resource;
var userName = GetAttribute(ldapUser, settings.LoginAttribute);
var firstName = settings.LdapMapping.ContainsKey(Mapping.FirstNameAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.FirstNameAttribute]) : string.Empty;
var secondName = settings.LdapMapping.ContainsKey(Mapping.SecondNameAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.SecondNameAttribute]) : string.Empty;
var birthDay = settings.LdapMapping.ContainsKey(Mapping.BirthDayAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.BirthDayAttribute]) : string.Empty;
var gender = settings.LdapMapping.ContainsKey(Mapping.GenderAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.GenderAttribute]) : string.Empty;
var primaryPhone = settings.LdapMapping.ContainsKey(Mapping.MobilePhoneAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.MobilePhoneAttribute]) : string.Empty;
var mail = settings.LdapMapping.ContainsKey(Mapping.MailAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.MailAttribute]) : string.Empty;
var title = settings.LdapMapping.ContainsKey(Mapping.TitleAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.TitleAttribute]) : string.Empty;
var location = settings.LdapMapping.ContainsKey(Mapping.LocationAttribute) ? GetAttribute(ldapUser, settings.LdapMapping[Mapping.LocationAttribute]) : string.Empty;
var phones = GetContacts(ldapUser, Mapping.AdditionalPhone, settings);
var mobilePhones = GetContacts(ldapUser, Mapping.AdditionalMobilePhone, settings);
var emails = GetContacts(ldapUser, Mapping.AdditionalMail, settings);
var skype = GetContacts(ldapUser, Mapping.Skype, settings);
if (string.IsNullOrEmpty(userName))
{
throw new Exception("LDAP LoginAttribute is empty");
}
var contacts = new List<string>();
PopulateContacts(contacts, EXT_PHONE, phones);
PopulateContacts(contacts, EXT_MOB_PHONE, mobilePhones);
PopulateContacts(contacts, EXT_MAIL, emails);
PopulateContacts(contacts, EXT_SKYPE, skype);
var user = new UserInfo
{
Id = Guid.Empty,
UserName = userName,
Sid = ldapUser.Sid,
ActivationStatus = settings.SendWelcomeEmail && !string.IsNullOrEmpty(mail) ? EmployeeActivationStatus.Pending : EmployeeActivationStatus.NotActivated,
Status = ldapUser.IsDisabled ? EmployeeStatus.Terminated : EmployeeStatus.Active,
Title = !string.IsNullOrEmpty(title) ? title : string.Empty,
Location = !string.IsNullOrEmpty(location) ? location : string.Empty,
WorkFromDate = _tenantUtil.DateTimeNow(),
ContactsList = contacts
};
if (!string.IsNullOrEmpty(firstName))
{
user.FirstName = firstName.Length > MAX_NUMBER_OF_SYMBOLS
? firstName.Substring(0, MAX_NUMBER_OF_SYMBOLS)
: firstName;
}
else
{
user.FirstName = resource.FirstName;
}
if (!string.IsNullOrEmpty(secondName))
{
user.LastName = secondName.Length > MAX_NUMBER_OF_SYMBOLS
? secondName.Substring(0, MAX_NUMBER_OF_SYMBOLS)
: secondName;
}
else
{
user.LastName = resource.LastName;
}
if (!string.IsNullOrEmpty(birthDay))
{
DateTime date;
if (DateTime.TryParse(birthDay, out date))
{
user.BirthDate = date;
}
}
if (!string.IsNullOrEmpty(gender))
{
bool b;
if (bool.TryParse(gender, out b))
{
user.Sex = b;
}
else
{
switch (gender.ToLowerInvariant())
{
case "male":
case "m":
user.Sex = true;
break;
case "female":
case "f":
user.Sex = false;
break;
}
}
}
if (string.IsNullOrEmpty(mail))
{
user.Email = userName.Contains("@") ? userName : string.Format("{0}@{1}", userName, ldapUserImporter.LDAPDomain);
user.ActivationStatus = EmployeeActivationStatus.AutoGenerated;
}
else
{
user.Email = mail;
}
user.MobilePhone = string.IsNullOrEmpty(primaryPhone)
? null : primaryPhone;
return user;
}
public GroupInfo ToGroupInfo(LdapObject ldapGroup, LdapSettings settings)
{
var name = GetAttribute(ldapGroup, settings.GroupNameAttribute);
if (string.IsNullOrEmpty(name))
{
throw new Exception("LDAP GroupNameAttribute is empty");
}
var group = new GroupInfo
{
Name = name,
Sid = ldapGroup.Sid
};
return group;
}
public string GetDomainFromDn(LdapObject ldapObject)
{
if (ldapObject == null || string.IsNullOrEmpty(ldapObject.DistinguishedName))
{
return null;
}
return LdapUtils.DistinguishedNameToDomain(ldapObject.DistinguishedName);
}
}

View File

@ -0,0 +1,58 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
[Scope]
public class DbHelper
{
private readonly Lazy<ActiveDirectoryDbContext> _lazyActiveDirectoryDbContext;
private readonly LdapSettings _ldapSettings;
private ActiveDirectoryDbContext ActiveDirectoryDbContext { get => _lazyActiveDirectoryDbContext.Value; }
public DbHelper(
DbContextManager<ActiveDirectoryDbContext> activeDirectoryDbContext,
LdapSettings ldapSettings)
{
_ldapSettings = ldapSettings;
_lazyActiveDirectoryDbContext = new Lazy<ActiveDirectoryDbContext>(() => activeDirectoryDbContext.Value);
}
public List<int> GetTenants()
{
var id = _ldapSettings.ID;
var enableLdapAuthentication = _ldapSettings.EnableLdapAuthentication;
var data = ActiveDirectoryDbContext.WebstudioSettings
.Where(r => r.Id == id)
.Join(ActiveDirectoryDbContext.Tenants, r => r.TenantId, r => r.Id, (settings, tenant) => new { settings, tenant })
.Select(r => JsonExtensions.JsonValue(nameof(r.settings.Data).ToLower(), enableLdapAuthentication.ToString()))
.Distinct()
.Select(r => r != null ? Convert.ToInt32(r) : 0)
.ToList();
return data;
}
}

View File

@ -0,0 +1,134 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Expressions;
/// <summary>
/// Criteria
/// </summary>
public class Criteria : ICloneable
{
private readonly CriteriaType _type;
private readonly List<Expression> _expressions = new List<Expression>();
private readonly List<Criteria> _nestedCriteras = new List<Criteria>();
/// <summary>
/// Constructor
/// </summary>
/// <param name="type">Type of critera</param>
/// <param name="expressions">Expressions</param>
public Criteria(CriteriaType type, params Expression[] expressions)
{
_expressions.AddRange(expressions);
_type = type;
}
/// <summary>
/// Add nested expressions as And criteria
/// </summary>
/// <param name="expressions">Expressions</param>
/// <returns>Self</returns>
public Criteria And(params Expression[] expressions)
{
_nestedCriteras.Add(All(expressions));
return this;
}
/// <summary>
/// Add nested expressions as Or criteria
/// </summary>
/// <param name="expressions">Expressions</param>
/// <returns>Self</returns>
public Criteria Or(params Expression[] expressions)
{
_nestedCriteras.Add(Any(expressions));
return this;
}
/// <summary>
/// Add nested Criteria
/// </summary>
/// <param name="nested"></param>
/// <returns>себя</returns>
public Criteria Add(Criteria nested)
{
_nestedCriteras.Add(nested);
return this;
}
/// <summary>
/// Criteria as a string
/// </summary>
/// <returns>Criteria string</returns>
public override string ToString()
{
var criteria = "({0}{1}{2})";
var expressions = _expressions.Aggregate(string.Empty, (current, expr) => current + expr.ToString());
var criterias = _nestedCriteras.Aggregate(string.Empty, (current, crit) => current + crit.ToString());
return string.Format(criteria, _type == CriteriaType.And ? "&" : "|", expressions, criterias);
}
/// <summary>
/// Group of Expression union as And
/// </summary>
/// <param name="expressions">Expressions</param>
/// <returns>new Criteria</returns>
public static Criteria All(params Expression[] expressions)
{
return new Criteria(CriteriaType.And, expressions);
}
/// <summary>
/// Group of Expression union as Or
/// </summary>
/// <param name="expressions">Expressions</param>
/// <returns>new Criteria</returns>
public static Criteria Any(params Expression[] expressions)
{
return new Criteria(CriteriaType.Or, expressions);
}
#region ICloneable Members
/// <summary>
/// ICloneable implemetation
/// </summary>
/// <returns>Clone object</returns>
public object Clone()
{
var cr = new Criteria(_type);
foreach (var ex in _expressions)
{
cr._expressions.Add(ex.Clone() as Expression);
}
foreach (var nc in _nestedCriteras)
{
cr._nestedCriteras.Add(nc.Clone() as Criteria);
}
return cr;
}
#endregion
}

View File

@ -0,0 +1,36 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Expressions;
/// <summary>
/// Criteria enum
/// </summary>
public enum CriteriaType
{
None,
And,
Or
}

View File

@ -0,0 +1,304 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Expressions;
public class Expression : ICloneable
{
private readonly Op _op;
private bool _negative;
private readonly string _attributeName;
private readonly string _attributeValue;
private const string EQUIAL = "=";
private const string APPROXIMATELY_EQUIAL = "~=";
private const string GREATER = ">";
private const string GREATER_OR_EQUAL = ">=";
private const string LESS = "<";
private const string LESS_OR_EQUAL = "<=";
internal Expression()
{
}
public string Name
{
get { return _attributeName; }
}
public string Value
{
get { return _attributeValue; }
}
public Op Operation
{
get { return _op; }
}
/// <summary>
/// To specify unary operations
/// </summary>
/// <param name="op">Operator</param>
/// <param name="attrbuteName">Attribute name</param>
public Expression(string attrbuteName, Op op)
{
if (op != Op.Exists && op != Op.NotExists)
{
throw new ArgumentException("op");
}
if (string.IsNullOrEmpty(attrbuteName))
{
throw new ArgumentException("attrbuteName");
}
_op = op;
_attributeName = attrbuteName;
_attributeValue = "*";
}
/// <summary>
/// To specify binary operations
/// </summary>
/// <param name="op">Operator</param>
/// <param name="attrbuteName">Attribute name</param>
/// <param name="attrbuteValue">Attribute value</param>
public Expression(string attrbuteName, Op op, string attrbuteValue)
{
if (op == Op.Exists || op == Op.NotExists)
{
throw new ArgumentException("op");
}
if (string.IsNullOrEmpty(attrbuteName))
{
throw new ArgumentException("attrbuteName");
}
_op = op;
_attributeName = attrbuteName;
_attributeValue = attrbuteValue;
}
/// <summary>
/// Expression as a string
/// </summary>
/// <returns>Expression string</returns>
public override string ToString()
{
string sop;
switch (_op)
{
case Op.NotExists:
case Op.Exists:
case Op.Equal:
case Op.NotEqual:
sop = EQUIAL;
break;
case Op.Greater:
sop = GREATER;
break;
case Op.GreaterOrEqual:
sop = GREATER_OR_EQUAL;
break;
case Op.Less:
sop = LESS;
break;
case Op.LessOrEqual:
sop = LESS_OR_EQUAL;
break;
default:
throw new ArgumentOutOfRangeException();
}
var expressionString = "({0}{1}{2}{3})";
expressionString = string.Format(expressionString,
//positive or negative
(((int)_op & 0x010000) == 0x010000 || _negative) ? "!" : "", _attributeName, sop,
EscapeLdapSearchFilter(_attributeValue));
return expressionString;
}
/// <summary>
/// Escapes the LDAP search filter to prevent LDAP injection attacks.
/// </summary>
/// <param name="searchFilter">The search filter.</param>
/// <see cref="https://blogs.oracle.com/shankar/entry/what_is_ldap_injection" />
/// <see cref="http://msdn.microsoft.com/en-us/library/aa746475.aspx" />
/// <returns>The escaped search filter.</returns>
private static string EscapeLdapSearchFilter(string searchFilter)
{
var escape = new StringBuilder(); // If using JDK >= 1.5 consider using StringBuilder
foreach (var current in searchFilter)
{
switch (current)
{
case '\\':
escape.Append(@"\5c");
break;
case '*':
escape.Append(@"\2a");
break;
case '(':
escape.Append(@"\28");
break;
case ')':
escape.Append(@"\29");
break;
case '\u0000':
escape.Append(@"\00");
break;
case '/':
escape.Append(@"\2f");
break;
default:
escape.Append(current);
break;
}
}
return escape.ToString();
}
/// <summary>
/// Negation
/// </summary>
/// <returns>Self</returns>
public Expression Negative()
{
_negative = !_negative;
return this;
}
/// <summary>
/// Existence
/// </summary>
/// <param name="attrbuteName"></param>
/// <returns>New Expression</returns>
public static Expression Exists(string attrbuteName)
{
return new Expression(attrbuteName, Op.Exists);
}
/// <summary>
/// Non-Existence
/// </summary>
/// <param name="attrbuteName"></param>
/// <returns>New Expression</returns>
public static Expression NotExists(string attrbuteName)
{
return new Expression(attrbuteName, Op.NotExists);
}
/// <summary>
/// Equality
/// </summary>
/// <param name="attrbuteName"></param>
/// <param name="attrbuteValue"></param>
/// <returns>New Expression</returns>
public static Expression Equal(string attrbuteName, string attrbuteValue)
{
return new Expression(attrbuteName, Op.Equal, attrbuteValue);
}
/// <summary>
/// Not equality
/// </summary>
/// <param name="attrbuteName"></param>
/// <param name="attrbuteValue"></param>
/// <returns></returns>
public static Expression NotEqual(string attrbuteName, string attrbuteValue)
{
return new Expression(attrbuteName, Op.NotEqual, attrbuteValue);
}
public static Expression Parse(string origin)
{
string spliter = null;
var op = Op.Equal;
var index = origin.IndexOf(EQUIAL, StringComparison.Ordinal);
if (index > -1)
{
spliter = EQUIAL;
op = Op.Equal;
}
else if ((index = origin.IndexOf(GREATER, StringComparison.Ordinal)) > -1)
{
spliter = GREATER;
op = Op.Greater;
}
else if ((index = origin.IndexOf(GREATER_OR_EQUAL, StringComparison.Ordinal)) > -1)
{
spliter = GREATER_OR_EQUAL;
op = Op.GreaterOrEqual;
}
else if ((index = origin.IndexOf(LESS, StringComparison.Ordinal)) > -1)
{
spliter = LESS;
op = Op.Less;
}
else if ((index = origin.IndexOf(LESS_OR_EQUAL, StringComparison.Ordinal)) > -1)
{
spliter = LESS_OR_EQUAL;
op = Op.LessOrEqual;
}
else if ((index = origin.IndexOf(APPROXIMATELY_EQUIAL, StringComparison.Ordinal)) > -1)
{
spliter = APPROXIMATELY_EQUIAL;
op = Op.Exists;
}
if (string.IsNullOrEmpty(spliter))
{
return null;
}
var attributeName = origin.Substring(0, index);
var attributeValue = origin.Substring(index + 1);
if (string.IsNullOrEmpty(attributeName) || string.IsNullOrEmpty(attributeValue))
{
return null;
}
return new Expression(attributeName, op, attributeValue);
}
#region ICloneable Members
/// <summary>
/// ICloneable implemetation
/// </summary>
/// <returns>Clone object</returns>
public object Clone()
{
return MemberwiseClone();
}
#endregion
}

View File

@ -0,0 +1,55 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Expressions;
/// <summary>
/// Operations
/// </summary>
/// <remarks>
/// [1 - negation][1 - binary][number]
/// </remarks>
public enum Op
{
//------------ UNARY -------------
/// <summary>Attribute exists</summary>
Exists = 0x000001,
/// <summary>Attribute does not exist</summary>
NotExists = 0x010002,
//------------ BINARY -------------
/// <summary>Equal</summary>
Equal = 0x000103,
/// <summary>Not equal</summary>
NotEqual = 0x010104,
/// <summary>Strong less</summary>
Less = 0x000105,
/// <summary>Less or equal</summary>
LessOrEqual = 0x000106,
/// <summary>Strong greater</summary>
Greater = 0x000107,
/// <summary>Greater or equal</summary>
GreaterOrEqual = 0x000108
}

View File

@ -0,0 +1,415 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
/// <summary>
/// Constants of Active Directory
/// </summary>
public sealed class LdapConstants
{
public const int STANDART_LDAP_PORT = 389;
public const int SSL_LDAP_PORT = 636;
public const int LDAP_ERROR_INVALID_CREDENTIALS = 0x31;
public const int LDAP_V3 = 3;
public const string OBJECT_FILTER = "(ObjectClass=*)";
/// <summary>
/// User Account type
/// </summary>
[Flags]
public enum AccountType : uint
{
// ReSharper disable InconsistentNaming
/// <summary></summary>
SAM_DOMAIN_OBJECT = 0x00000000,
/// <summary></summary>
SAM_GROUP_OBJECT = 0x10000000,
/// <summary></summary>
SAM_NON_SECURITY_GROUP_OBJECT = 0x10000001,
/// <summary></summary>
SAM_ALIAS_OBJECT = 0x20000000,
/// <summary></summary>
SAM_NON_SECURITY_ALIAS_OBJECT = 0x20000001,
/// <summary></summary>
SAM_USER_OBJECT = 0x30000000,
//SAM_NORMAL_USER_ACCOUNT = 0x30000000,
/// <summary></summary>
SAM_MACHINE_ACCOUNT = 0x30000001,
/// <summary></summary>
SAM_TRUST_ACCOUNT = 0x30000002,
/// <summary></summary>
SAM_APP_BASIC_GROUP = 0x40000000,
/// <summary></summary>
SAM_APP_QUERY_GROUP = 0x40000001
// ReSharper restore InconsistentNaming
}
/// <summary>
/// User Account Control
/// </summary>
[Flags]
public enum UserAccountControl : uint
{
// ReSharper disable InconsistentNaming
/// <summary>Zero flag</summary>
EMPTY = 0x00000000,
/// <summary>The logon script is executed.</summary>
ADS_UF_SCRIPT = 0x00000001,
/// <summary>The user account is disabled.</summary>
ADS_UF_ACCOUNTDISABLE = 0x00000002,
/// <summary>The home directory is required.</summary>
ADS_UF_HOMEDIR_REQUIRED = 0x00000008,
/// <summary>The account is currently locked out.</summary>
ADS_UF_LOCKOUT = 0x00000010,
/// <summary>No password is required.</summary>
ADS_UF_PASSWD_NOTREQD = 0x00000020,
/// <summary>The user cannot change the password</summary>
ADS_UF_PASSWD_CANT_CHANGE = 0x00000040,
/// <summary>The user can send an encrypted password.</summary>
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x00000080,
/// <summary>This is an account for users whose primary account is in another domain.
/// This account provides user access to this domain, but not to any domain that trusts
/// this domain. Also known as a local user account.</summary>
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0x00000100,
/// <summary>This is a default account type that represents a typical user.</summary>
ADS_UF_NORMAL_ACCOUNT = 0x00000200,
/// <summary>This is a computer account for a computer that is a member of this domain.</summary>
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x00001000,
/// <summary>This is a computer account for a system backup domain controller
/// that is a member of this domain.</summary>
ADS_UF_SERVER_TRUST_ACCOUNT = 0x00002000,
/// <summary>The password for this account will never expire.</summary>
ADS_UF_DONT_EXPIRE_PASSWD = 0x00010000,
/// <summary>The user must log on using a smart card.</summary>
ADS_UF_SMARTCARD_REQUIRED = 0x00040000,
/// <summary>The service account (user or computer account), under which a service runs,
/// is trusted for Kerberos delegation. Any such service can impersonate a client
/// requesting the service.</summary>
ADS_UF_TRUSTED_FOR_DELEGATION = 0x00080000,
/// <summary>The security context of the user will not be delegated to a service even
/// if the service account is set as trusted for Kerberos delegation.</summary>
ADS_UF_NOT_DELEGATED = 0x00100000,
/// <summary>Restrict this principal to use only Data Encryption Standard
/// (DES) encryption types for keys.</summary>
ADS_UF_USE_DES_KEY_ONLY = 0x00200000,
/// <summary>This account does not require Kerberos pre-authentication for logon.</summary>
ADS_UF_DONT_REQUIRE_PREAUTH = 0x00400000,
/// <summary>The user password has expired. This flag is created by the system
/// using data from the Pwd-Last-Set attribute and the domain policy.</summary>
ADS_UF_PASSWORD_EXPIRED = 0x00800000,
/// <summary>The account is enabled for delegation. This is a security-sensitive
/// setting; accounts with this option enabled should be strictly controlled.
/// This setting enables a service running under the account to assume a client
/// identity and authenticate as that user to other remote servers on the network.</summary>
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x01000000
// ReSharper restore InconsistentNaming
}
/// <summary>
/// Type of Group
/// </summary>
[Flags]
public enum GroupType : uint
{
// ReSharper disable InconsistentNaming
/// <summary>System group</summary>
SYSTEM = 0x00000001,
/// <summary>Global scope group</summary>
GLOBAL_SCOPE = 0x00000002,
/// <summary>Local domain scope group</summary>
LOCAL_DOMAIN_SCOPE = 0x00000004,
/// <summary>Universal scope group</summary>
UNIVERSAL_SCOPE = 0x00000008,
/// <summary>Specifies an APP_BASIC group for Windows Server Authorization Manager.</summary>
APP_BASIC = 0x000000010,
/// <summary>Specifies an APP_QUERY group for Windows Server Authorization Manager.</summary>
APP_QUERY = 0x000000020,
/// <summary>Security group</summary>
SECURITY_GROUP = 0x80000000
// ReSharper restore InconsistentNaming
}
/// <summary>
/// Schema attributes of Active Directory
/// </summary>
// ReSharper disable once InconsistentNaming
public static class ADSchemaAttributes
{
/// <summary>Relative Distinguished Name </summary>
public const string NAME = "name";
/// <summary>Common-Name</summary>
public const string COMMON_NAME = "cn";
/// <summary>Display-Name</summary>
public const string DISPLAY_NAME = "displayName";
/// <summary>The list of classes from which this class is derived.</summary>
public const string OBJECT_CLASS = "objectClass";
/// <summary>DN category</summary>
public const string OBJECT_CATEGORY = "objectCategory";
/// <summary>The unique identifier for an object.</summary>
public const string OBJECT_GUID = "objectGUID";
/// <summary>Show-In-Advanced-View-Only</summary>
public const string SHOW_IN_ADVANCED_VIEW_ONLY = "showInAdvancedViewOnly";
/// <summary>Obj-Dist-Name</summary>
public const string DISTINGUISHED_NAME = "distinguishedName";
/// <summary>Is-Critical-System-Object</summary>
public const string IS_CRITICAL_SYSTEM_OBJECT = "isCriticalSystemObject";
/// <summary>NT-Security-Descriptor in format SDDL</summary>
public const string NT_SECURITY_DESCRIPTOR = "nTSecurityDescriptor";
/// <summary>Is-Member-Of-DL</summary>
public const string MEMBER_OF = "memberOf";
/// <summary>Users which are members of this object</summary>
public const string MEMBER = "member";
/// <summary>Organizational-Unit-Name</summary>
public const string ORGANIZATIONAL_UNIT_NAME = "ou";
/// <summary>Organization-Name</summary>
public const string ORGANIZATION_NAME = "o";
/// <summary>SAM-Account-Name</summary>
public const string ACCOUNT_NAME = "sAMAccountName";
/// <summary>SAM-Account-Type</summary>
public const string ACCOUNT_TYPE = "sAMAccountType";
/// <summary>A binary value that specifies the security identifier (SID) of the user.
/// The SID is a unique value used to identify the user as a security principal.</summary>
public const string OBJECT_SID = "objectSid"; //Object-Sid
/// <summary>Flags that control the behavior of the user account.</summary>
public const string USER_ACCOUNT_CONTROL = "userAccountControl";
/// <summary>This attribute contains the UPN that is an Internet-style login name
/// for a user based on the Internet standard RFC 822. The UPN is shorter than
/// the distinguished name and easier to remember. By convention, this should map
/// to the user e-mail name. The value set for this attribute is equal to the length
/// of the user's ID and the domain name. For more information about this attribute,
/// see the Naming Properties topic in the Active Directory guide.</summary>
public const string USER_PRINCIPAL_NAME = "userPrincipalName";
/// <summary>Contains the given name (first name) of the user.</summary>
public const string FIRST_NAME = "givenName";
/// <summary>This attribute contains the family or last name for a user.</summary>
public const string SURNAME = "sn";
/// <summary>Primary-Group-ID</summary>
public const string PRIMARY_GROUP_ID = "primaryGroupID";
/// <summary>Name of computer as registered in DNS</summary>
public const string DNS_HOST_NAME = "dNSHostName";
/// <summary>The Operating System Version string </summary>
public const string OPERATING_SYSTEM_VERSION = "operatingSystemVersion";
/// <summary>The Operating System Service Pack ID String </summary>
public const string OPERATING_SYSTEM_SERVICE_PACK = "operatingSystemServicePack";
/// <summary>The hotfix level of the operating system.</summary>
public const string OPERATING_SYSTEM_HOTFIX = "operatingSystemHotfix";
/// <summary>The Operating System name .</summary>
public const string OPERATING_SYSTEM = "operatingSystem";
/// <summary>The TCP/IP address for a network segment. Also called the subnet address.</summary>
public const string NETWORK_ADDRESS = "networkAddress";
/// <summary>Mobile phone</summary>
public const string MOBILE = "mobile";
/// <summary>Email address</summary>
public const string MAIL = "mail";
/// <summary>Telephone number</summary>
public const string TELEPHONE_NUMBER = "telephoneNumber";
/// <summary>Title</summary>
public const string TITLE = "title";
/// <summary>Street Address</summary>
public const string STREET = "street";
/// <summary>Postal code</summary>
public const string POSTAL_CODE = "postalCode";
/// <summary>Home phone</summary>
public const string HOME_PHONE = "homePhone";
/// <summary>Initials</summary>
public const string INITIALS = "initials";
/// <summary>Department</summary>
public const string DIVISION = "division";
/// <summary>Company</summary>
public const string COMPANY = "company";
}
public static class RfcLDAPAttributes
{
public const string ENTRY_DN = "entryDN";
public const string GUID = "GUID";
public const string ENTRY_UUID = "entryUUID";
public const string NS_UNIQUE_ID = "nsuniqueid";
public const string UID = "uid";
public const string MEMBER_UID = "memberUid";
public const string DN = "dn";
}
/// <summary>
/// Standart attributes of ObjectClass
/// </summary>
public static class ObjectClassKnowedValues
{
/// <summary>
/// top value
/// </summary>
public const string TOP = "top";
/// <summary>
/// Domain name
/// </summary>
public const string DOMAIN = "domain";
/// <summary>
/// Domain DNS
/// </summary>
public const string DOMAIN_DNS = "domainDNS";
/// <summary>
/// Group name
/// </summary>
public const string GROUP = "group";
/// <summary>
/// posix-group
/// </summary>
public const string POSIX_GROUP = "posixGroup";
/// <summary>
/// Person
/// </summary>
public const string PERSON = "person";
/// <summary>
/// Container
/// </summary>
public const string CONTAINER = "container";
/// <summary>
/// Org unit
/// </summary>
public const string ORGANIZATIONAL_UNIT = "organizationalUnit";
/// <summary>
/// Org name
/// </summary>
public const string ORGANIZATION = "organization";
/// <summary>
/// posix-account
/// </summary>
public const string POSIX_ACCOUNT = "posixAccount";
/// <summary>
/// Org person
/// </summary>
public const string ORGANIZATIONAL_PERSON = "organizationalPerson";
/// <summary>
/// User
/// </summary>
public const string USER = "user";
/// <summary>
/// Computer
/// </summary>
public const string COMPUTER = "computer";
/// <summary>
/// RPC container
/// </summary>
public const string RPC_CONTAINER = "rpcContainer";
/// <summary>
/// Built in domain flag
/// </summary>
public const string BUILD_IN_DOMAIN = "builtinDomain";
}
}

View File

@ -0,0 +1,158 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
[Scope]
public abstract class LdapHelper : IDisposable
{
public LdapSettings Settings { get; private set; }
public abstract bool IsConnected { get; }
protected readonly ILogger<LdapHelper> _logger;
protected readonly InstanceCrypto _instanceCrypto;
protected LdapHelper(
ILogger<LdapHelper> logger,
InstanceCrypto instanceCrypto)
{
_logger = logger;
_instanceCrypto = instanceCrypto;
}
public void Init(LdapSettings settings)
{
Settings = settings;
}
public abstract void Connect();
public abstract Dictionary<string, string[]> GetCapabilities();
public abstract string SearchDomain();
public abstract void CheckCredentials(string login, string password, string server, int portNumber,
bool startTls, bool ssl, bool acceptCertificate, string acceptCertificateHash);
public abstract bool CheckUserDn(string userDn);
public abstract List<LdapObject> GetUsers(string filter = null, int limit = -1);
public abstract LdapObject GetUserBySid(string sid);
public abstract bool CheckGroupDn(string groupDn);
public abstract List<LdapObject> GetGroups(Criteria criteria = null);
public bool UserExistsInGroup(LdapObject domainGroup, LdapObject domainUser, LdapSettings settings) // string memberString, string groupAttribute, string primaryGroupId)
{
try
{
if (domainGroup == null || domainUser == null)
{
return false;
}
var memberString = domainUser.GetValue(Settings.UserAttribute) as string;
if (string.IsNullOrEmpty(memberString))
{
return false;
}
var groupAttribute = settings.GroupAttribute;
if (string.IsNullOrEmpty(groupAttribute))
{
return false;
}
var userPrimaryGroupId = domainUser.GetValue(LdapConstants.ADSchemaAttributes.PRIMARY_GROUP_ID) as string;
if (!string.IsNullOrEmpty(userPrimaryGroupId) && domainGroup.Sid.EndsWith("-" + userPrimaryGroupId))
{
// Domain Users found
return true;
}
else
{
var members = domainGroup.GetValues(groupAttribute);
if (members.Count == 0)
{
return false;
}
if (members.Any(member => memberString.Equals(member, StringComparison.InvariantCultureIgnoreCase)
|| member.Equals(domainUser.DistinguishedName, StringComparison.InvariantCultureIgnoreCase)))
{
return true;
}
}
}
catch (Exception e)
{
_logger.ErrorUserExistsInGroupFailed(e);
}
return false;
}
public string GetPassword(byte[] passwordBytes)
{
if (passwordBytes == null || passwordBytes.Length == 0)
{
return string.Empty;
}
string password;
try
{
password = _instanceCrypto.Decrypt(passwordBytes, new UnicodeEncoding());
}
catch (Exception)
{
password = string.Empty;
}
return password;
}
public byte[] GetPasswordBytes(string password)
{
byte[] passwordBytes;
try
{
passwordBytes = _instanceCrypto.Encrypt(new UnicodeEncoding().GetBytes(password));
}
catch (Exception)
{
passwordBytes = Array.Empty<byte>();
}
return passwordBytes;
}
public abstract void Dispose();
}

View File

@ -0,0 +1,131 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
[Singletone(Additional = typeof(LdapNotifyHelperExtension))]
public class LdapNotifyService : BackgroundService
{
private readonly ConcurrentDictionary<int, Tuple<INotifyClient, LdapNotifySource>> _clients;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly WorkContext _workContext;
private readonly LdapSaveSyncOperation _ldapSaveSyncOperation;
private readonly NotifyEngineQueue _notifyEngineQueue;
public LdapNotifyService(
IServiceScopeFactory serviceScopeFactory,
WorkContext workContext,
LdapSaveSyncOperation ldapSaveSyncOperation,
NotifyEngineQueue notifyEngineQueue)
{
_clients = new ConcurrentDictionary<int, Tuple<INotifyClient, LdapNotifySource>>();
_serviceScopeFactory = serviceScopeFactory;
_workContext = workContext;
_ldapSaveSyncOperation = ldapSaveSyncOperation;
_notifyEngineQueue = notifyEngineQueue;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
using var scope = _serviceScopeFactory.CreateScope();
var tenantManager = scope.ServiceProvider.GetRequiredService<TenantManager>();
var settingsManager = scope.ServiceProvider.GetRequiredService<SettingsManager>();
var dbHelper = scope.ServiceProvider.GetRequiredService<DbHelper>();
var tenants = tenantManager.GetTenants(dbHelper.GetTenants());
foreach (var t in tenants)
{
var tId = t.Id;
var ldapSettings = settingsManager.LoadForTenant<LdapSettings>(tId);
if (!ldapSettings.EnableLdapAuthentication)
{
continue;
}
var cronSettings = settingsManager.LoadForTenant<LdapCronSettings>(tId);
if (string.IsNullOrEmpty(cronSettings.Cron))
{
continue;
}
RegisterAutoSync(t, cronSettings.Cron);
}
return Task.CompletedTask;
}
public void RegisterAutoSync(Tenant tenant, string cron)
{
if (!_clients.ContainsKey(tenant.Id))
{
using var scope = _serviceScopeFactory.CreateScope();
var source = scope.ServiceProvider.GetRequiredService<LdapNotifySource>();
source.Init(tenant);
var client = _workContext.NotifyContext.RegisterClient(_notifyEngineQueue, source);
_workContext.RegisterSendMethod(source.AutoSync, cron);
_clients.TryAdd(tenant.Id, new Tuple<INotifyClient, LdapNotifySource>(client, source));
}
}
public void UnregisterAutoSync(Tenant tenant)
{
if (_clients.ContainsKey(tenant.Id))
{
var client = _clients[tenant.Id];
_workContext.UnregisterSendMethod(client.Item2.AutoSync);
_clients.TryRemove(tenant.Id, out _);
}
}
public void AutoSync(Tenant tenant)
{
using var scope = _serviceScopeFactory.CreateScope();
var settingsManager = scope.ServiceProvider.GetRequiredService<SettingsManager>();
var ldapSettings = settingsManager.LoadForTenant<LdapSettings>(tenant.Id);
if (!ldapSettings.EnableLdapAuthentication)
{
var cronSettings = settingsManager.LoadForTenant<LdapCronSettings>(tenant.Id);
cronSettings.Cron = "";
settingsManager.SaveForTenant(cronSettings, tenant.Id);
UnregisterAutoSync(tenant);
return;
}
_ldapSaveSyncOperation.RunJob(ldapSettings, tenant, LdapOperationType.Sync);
}
}
public static class LdapNotifyHelperExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<DbHelper>();
services.TryAdd<LdapNotifySource>();
services.TryAdd<NotifyEngineQueue>();
}
}

View File

@ -0,0 +1,74 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
[Scope]
public class LdapNotifySource : INotifySource
{
private Tenant _tenant;
private readonly LdapNotifyService _ldapNotifyHelper;
public string Id
{
get { return "asc.activedirectory." + _tenant.Id; }
}
public LdapNotifySource(LdapNotifyService ldapNotifyHelper)
{
_ldapNotifyHelper = ldapNotifyHelper;
}
public void Init(Tenant tenant)
{
_tenant = tenant;
}
public void AutoSync(DateTime date)
{
_ldapNotifyHelper.AutoSync(_tenant);
}
public IActionProvider GetActionProvider()
{
throw new NotImplementedException();
}
public IPatternProvider GetPatternProvider()
{
throw new NotImplementedException();
}
public IRecipientProvider GetRecipientsProvider()
{
throw new NotImplementedException();
}
public ISubscriptionProvider GetSubscriptionProvider()
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,934 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Constants = ASC.Core.Users.Constants;
namespace ASC.ActiveDirectory.Base;
[Scope]
public class LdapUserImporter : IDisposable
{
public List<LdapObject> AllDomainUsers { get; private set; }
public List<LdapObject> AllDomainGroups { get; private set; }
public Dictionary<LdapObject, LdapSettingsStatus> AllSkipedDomainUsers { get; private set; }
public Dictionary<LdapObject, LdapSettingsStatus> AllSkipedDomainGroups { get; private set; }
private string _ldapDomain;
private readonly string _unknownDomain;
public string LDAPDomain
{
get
{
if (!string.IsNullOrEmpty(_ldapDomain))
{
return _ldapDomain;
}
_ldapDomain = LoadLDAPDomain();
if (string.IsNullOrEmpty(_ldapDomain))
{
_ldapDomain = _unknownDomain;
}
return _ldapDomain;
}
}
public List<string> PrimaryGroupIds { get; set; }
public LdapSettings Settings
{
get { return LdapHelper.Settings; }
}
public LdapHelper LdapHelper { get; private set; }
public LdapLocalization Resource { get; private set; }
private List<string> _watchedNestedGroups;
private readonly ILogger<LdapUserImporter> _logger;
private readonly LdapObjectExtension _ldapObjectExtension;
private UserManager UserManager { get; set; }
public LdapUserImporter(
ILogger<LdapUserImporter> logger,
UserManager userManager,
IConfiguration configuration,
NovellLdapHelper novellLdapHelper,
LdapObjectExtension ldapObjectExtension)
{
_unknownDomain = configuration["ldap:domain"] ?? "LDAP";
AllDomainUsers = new List<LdapObject>();
AllDomainGroups = new List<LdapObject>();
AllSkipedDomainUsers = new Dictionary<LdapObject, LdapSettingsStatus>();
AllSkipedDomainGroups = new Dictionary<LdapObject, LdapSettingsStatus>();
LdapHelper = novellLdapHelper;
_logger = logger;
UserManager = userManager;
_watchedNestedGroups = new List<string>();
_ldapObjectExtension = ldapObjectExtension;
}
public void Init(LdapSettings settings, LdapLocalization resource)
{
((NovellLdapHelper)LdapHelper).Init(settings);
Resource = resource;
}
public List<UserInfo> GetDiscoveredUsersByAttributes()
{
var users = new List<UserInfo>();
if (!AllDomainUsers.Any() && !TryLoadLDAPUsers())
{
return users;
}
var usersToAdd = AllDomainUsers.Select(ldapObject => _ldapObjectExtension.ToUserInfo(ldapObject, this));
users.AddRange(usersToAdd);
return users;
}
public List<GroupInfo> GetDiscoveredGroupsByAttributes()
{
if (!Settings.GroupMembership)
{
return new List<GroupInfo>();
}
if (!AllDomainGroups.Any() && !TryLoadLDAPGroups())
{
return new List<GroupInfo>();
}
var groups = new List<GroupInfo>();
var groupsToAdd = AllDomainGroups.ConvertAll(g => _ldapObjectExtension.ToGroupInfo(g, Settings));
groups.AddRange(groupsToAdd);
return groups;
}
public List<UserInfo> GetGroupUsers(GroupInfo groupInfo)
{
return GetGroupUsers(groupInfo, true);
}
private List<UserInfo> GetGroupUsers(GroupInfo groupInfo, bool clearCache)
{
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
_logger.DebugGetGroupUsers(groupInfo.Name);
var users = new List<UserInfo>();
if (!AllDomainGroups.Any() && !TryLoadLDAPGroups())
{
return users;
}
var domainGroup = AllDomainGroups.FirstOrDefault(lg => lg.Sid.Equals(groupInfo.Sid));
if (domainGroup == null)
{
return users;
}
var members = _ldapObjectExtension.GetAttributes(domainGroup, Settings.GroupAttribute);
foreach (var member in members)
{
var ldapUser = FindUserByMember(member);
if (ldapUser == null)
{
var nestedLdapGroup = FindGroupByMember(member);
if (nestedLdapGroup != null)
{
_logger.DebugFoundNestedLdapGroup(nestedLdapGroup.DistinguishedName);
if (clearCache)
{
_watchedNestedGroups = new List<string>();
}
if (_watchedNestedGroups.Contains(nestedLdapGroup.DistinguishedName))
{
_logger.DebugSkipAlreadyWatched(nestedLdapGroup.DistinguishedName);
continue;
}
_watchedNestedGroups.Add(nestedLdapGroup.DistinguishedName);
var nestedGroupInfo = _ldapObjectExtension.ToGroupInfo(nestedLdapGroup, Settings);
var nestedGroupUsers = GetGroupUsers(nestedGroupInfo, false);
foreach (var groupUser in nestedGroupUsers)
{
if (!users.Exists(u => u.Sid == groupUser.Sid))
{
users.Add(groupUser);
}
}
}
continue;
}
var userInfo = _ldapObjectExtension.ToUserInfo(ldapUser, this);
if (!users.Exists(u => u.Sid == userInfo.Sid))
{
users.Add(userInfo);
}
}
if (PrimaryGroupIds != null && PrimaryGroupIds.Any(id => domainGroup.Sid.EndsWith("-" + id)))
{
// Domain Users found
var ldapUsers = FindUsersByPrimaryGroup(domainGroup.Sid);
foreach (var ldapUser in ldapUsers)
{
var userInfo = _ldapObjectExtension.ToUserInfo(ldapUser, this);
if (!users.Exists(u => u.Sid == userInfo.Sid))
{
users.Add(userInfo);
}
}
}
return users;
}
const string GROUP_MEMBERSHIP = "groupMembership";
private IEnumerable<LdapObject> GetLdapUserGroups(LdapObject ldapUser)
{
var ldapUserGroups = new List<LdapObject>();
try
{
if (!Settings.GroupMembership)
{
return ldapUserGroups;
}
if (ldapUser == null ||
string.IsNullOrEmpty(ldapUser.Sid))
{
return ldapUserGroups;
}
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
var userGroups = _ldapObjectExtension.GetAttributes(ldapUser, LdapConstants.ADSchemaAttributes.MEMBER_OF)
.Select(s => LdapUtils.UnescapeLdapString(s))
.ToList();
if (!userGroups.Any())
{
userGroups = _ldapObjectExtension.GetAttributes(ldapUser, GROUP_MEMBERSHIP);
}
var searchExpressions = new List<Expression>();
var primaryGroupId = ldapUser.GetValue(LdapConstants.ADSchemaAttributes.PRIMARY_GROUP_ID) as string;
if (!string.IsNullOrEmpty(primaryGroupId))
{
var userSid = ldapUser.Sid;
var index = userSid.LastIndexOf("-", StringComparison.InvariantCultureIgnoreCase);
if (index > -1)
{
var primaryGroupSid = userSid.Substring(0, index + 1) + primaryGroupId;
searchExpressions.Add(Expression.Equal(ldapUser.SidAttribute, primaryGroupSid));
}
}
if (userGroups.Any())
{
var cnRegex = new Regex(",[A-z]{2}=");
searchExpressions.AddRange(userGroups
.Select(g => g.Substring(0, cnRegex.Match(g).Index))
.Where(s => !string.IsNullOrEmpty(s))
.Select(Expression.Parse)
.Where(e => e != null));
var criteria = Criteria.Any(searchExpressions.ToArray());
var foundList = LdapHelper.GetGroups(criteria);
if (foundList.Any())
{
ldapUserGroups.AddRange(foundList);
}
}
else
{
var ldapGroups = LdapHelper.GetGroups();
ldapUserGroups.AddRange(
ldapGroups.Where(
ldapGroup =>
LdapHelper.UserExistsInGroup(ldapGroup, ldapUser, Settings)));
}
}
catch (Exception ex)
{
if (ldapUser != null)
{
_logger.ErrorIsUserExistInGroups(ldapUser.DistinguishedName, ldapUser.Sid, ex);
}
}
return ldapUserGroups;
}
public IEnumerable<GroupInfo> GetAndCheckCurrentGroups(LdapObject ldapUser, IEnumerable<GroupInfo> portalGroups)
{
var result = new List<GroupInfo>();
try
{
var searchExpressions = new List<Expression>();
if (portalGroups != null && portalGroups.Any())
{
searchExpressions.AddRange(portalGroups.Select(g => Expression.Equal(LdapConstants.ADSchemaAttributes.OBJECT_SID, g.Sid)));
}
else
{
return result;
}
var criteria = Criteria.Any(searchExpressions.ToArray());
var foundList = LdapHelper.GetGroups(criteria);
if (foundList.Any())
{
var stillExistingGroups = portalGroups.Where(g => foundList.Any(fg => fg.Sid == g.Sid));
foreach (var group in stillExistingGroups)
{
if (GetGroupUsers(group).Any(u => u.Sid == ldapUser.Sid))
{
result.Add(group);
}
}
}
}
catch (Exception ex)
{
if (ldapUser != null)
{
_logger.ErrorGetAndCheckCurrentGroups(ldapUser.DistinguishedName, ldapUser.Sid, ex);
}
}
return result;
}
public bool TrySyncUserGroupMembership(Tuple<UserInfo, LdapObject> ldapUserInfo)
{
if (ldapUserInfo == null ||
!Settings.GroupMembership)
{
return false;
}
var userInfo = ldapUserInfo.Item1;
var ldapUser = ldapUserInfo.Item2;
var portalUserLdapGroups =
UserManager.GetUserGroups(userInfo.Id, IncludeType.All)
.Where(g => !string.IsNullOrEmpty(g.Sid))
.ToList();
var ldapUserGroupList = new List<LdapObject>();
ldapUserGroupList.AddRange(GetLdapUserGroups(ldapUser));
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
var actualPortalLdapGroups = GetAndCheckCurrentGroups(ldapUser, portalUserLdapGroups).ToList();
foreach (var ldapUserGroup in ldapUserGroupList)
{
var groupInfo = UserManager.GetGroupInfoBySid(ldapUserGroup.Sid);
if (Equals(groupInfo, Constants.LostGroupInfo))
{
_logger.DebugTrySyncUserGroupMembershipCreatingPortalGroup(ldapUserGroup.DistinguishedName, ldapUserGroup.Sid);
groupInfo = UserManager.SaveGroupInfo(_ldapObjectExtension.ToGroupInfo(ldapUserGroup, Settings));
_logger.DebugTrySyncUserGroupMembershipAddingUserToGroup(userInfo.UserName, ldapUser.Sid, groupInfo.Name, groupInfo.Sid);
UserManager.AddUserIntoGroup(userInfo.Id, groupInfo.ID);
}
else if (!portalUserLdapGroups.Contains(groupInfo))
{
_logger.DebugTrySyncUserGroupMembershipAddingUserToGroup(userInfo.UserName, ldapUser.Sid, groupInfo.Name, groupInfo.Sid);
UserManager.AddUserIntoGroup(userInfo.Id, groupInfo.ID);
}
actualPortalLdapGroups.Add(groupInfo);
}
foreach (var portalUserLdapGroup in portalUserLdapGroups)
{
if (!actualPortalLdapGroups.Contains(portalUserLdapGroup))
{
_logger.DebugTrySyncUserGroupMembershipRemovingUserFromGroup(userInfo.UserName, ldapUser.Sid, portalUserLdapGroup.Name, portalUserLdapGroup.Sid);
UserManager.RemoveUserFromGroup(userInfo.Id, portalUserLdapGroup.ID);
}
}
return actualPortalLdapGroups.Count != 0;
}
public bool TryLoadLDAPUsers()
{
try
{
if (!Settings.EnableLdapAuthentication)
{
return false;
}
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
var users = LdapHelper.GetUsers();
foreach (var user in users)
{
if (string.IsNullOrEmpty(user.Sid))
{
AllSkipedDomainUsers.Add(user, LdapSettingsStatus.WrongSidAttribute);
continue;
}
if (!CheckLoginAttribute(user, Settings.LoginAttribute))
{
AllSkipedDomainUsers.Add(user, LdapSettingsStatus.WrongLoginAttribute);
continue;
}
if (!Settings.GroupMembership)
{
AllDomainUsers.Add(user);
continue;
}
if (!Settings.UserAttribute.Equals(LdapConstants.RfcLDAPAttributes.DN,
StringComparison.InvariantCultureIgnoreCase) && !CheckUserAttribute(user, Settings.UserAttribute))
{
AllSkipedDomainUsers.Add(user, LdapSettingsStatus.WrongUserAttribute);
continue;
}
AllDomainUsers.Add(user);
}
if (AllDomainUsers.Any())
{
PrimaryGroupIds = AllDomainUsers.Select(u => u.GetValue(LdapConstants.ADSchemaAttributes.PRIMARY_GROUP_ID)).Cast<string>()
.Distinct().ToList();
}
return AllDomainUsers.Any() || !users.Any();
}
catch (ArgumentException)
{
_logger.ErrorTryLoadLDAPUsersIncorrectUserFilter(Settings.UserFilter);
}
return false;
}
public bool TryLoadLDAPGroups()
{
try
{
if (!Settings.EnableLdapAuthentication || !Settings.GroupMembership)
{
return false;
}
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
var groups = LdapHelper.GetGroups();
foreach (var group in groups)
{
if (string.IsNullOrEmpty(group.Sid))
{
AllSkipedDomainGroups.Add(group, LdapSettingsStatus.WrongSidAttribute);
continue;
}
if (!CheckGroupAttribute(group, Settings.GroupAttribute))
{
AllSkipedDomainGroups.Add(group, LdapSettingsStatus.WrongGroupAttribute);
continue;
}
if (!CheckGroupNameAttribute(group, Settings.GroupNameAttribute))
{
AllSkipedDomainGroups.Add(group, LdapSettingsStatus.WrongGroupNameAttribute);
continue;
}
AllDomainGroups.Add(group);
}
return AllDomainGroups.Any() || !groups.Any();
}
catch (ArgumentException)
{
_logger.ErrorTryLoadLDAPUsersIncorrectGroupFilter(Settings.GroupFilter);
}
return false;
}
private string LoadLDAPDomain()
{
try
{
if (!Settings.EnableLdapAuthentication)
{
return null;
}
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
string ldapDomain;
if (AllDomainUsers.Any())
{
ldapDomain = _ldapObjectExtension.GetDomainFromDn(AllDomainUsers.First());
if (!string.IsNullOrEmpty(ldapDomain))
{
return ldapDomain;
}
}
ldapDomain = LdapHelper.SearchDomain();
if (!string.IsNullOrEmpty(ldapDomain))
{
return ldapDomain;
}
ldapDomain = LdapUtils.DistinguishedNameToDomain(Settings.UserDN);
if (!string.IsNullOrEmpty(ldapDomain))
{
return ldapDomain;
}
ldapDomain = LdapUtils.DistinguishedNameToDomain(Settings.GroupDN);
if (!string.IsNullOrEmpty(ldapDomain))
{
return ldapDomain;
}
}
catch (Exception ex)
{
_logger.ErrorLoadLDAPDomain(ex);
}
return null;
}
protected bool CheckLoginAttribute(LdapObject user, string loginAttribute)
{
try
{
var member = user.GetValue(loginAttribute);
if (member == null || string.IsNullOrWhiteSpace(member.ToString()))
{
_logger.DebugLoginAttributeParameterNotFound(Settings.LoginAttribute, user.DistinguishedName);
return false;
}
}
catch (Exception e)
{
_logger.ErrorLoginAttributeParameterNotFound(Settings.LoginAttribute, loginAttribute, e);
return false;
}
return true;
}
protected bool CheckUserAttribute(LdapObject user, string userAttr)
{
try
{
var userAttribute = user.GetValue(userAttr);
if (userAttribute == null || string.IsNullOrWhiteSpace(userAttribute.ToString()))
{
_logger.DebugUserAttributeParameterNotFound(Settings.UserAttribute,
user.DistinguishedName);
return false;
}
}
catch (Exception e)
{
_logger.ErrorUserAttributeParameterNotFound(Settings.UserAttribute, userAttr, e);
return false;
}
return true;
}
protected bool CheckGroupAttribute(LdapObject group, string groupAttr)
{
try
{
group.GetValue(groupAttr); // Group attribute can be empty - example => Domain users
}
catch (Exception e)
{
_logger.ErrorGroupAttributeParameterNotFound(Settings.GroupAttribute, groupAttr, e);
return false;
}
return true;
}
protected bool CheckGroupNameAttribute(LdapObject group, string groupAttr)
{
try
{
var groupNameAttribute = group.GetValues(groupAttr);
if (!groupNameAttribute.Any())
{
_logger.DebugGroupNameAttributeParameterNotFound(Settings.GroupNameAttribute,
groupAttr);
return false;
}
}
catch (Exception e)
{
_logger.ErrorGroupAttributeParameterNotFound(Settings.GroupNameAttribute,
groupAttr, e);
return false;
}
return true;
}
private List<LdapObject> FindUsersByPrimaryGroup(string sid)
{
_logger.DebugFindUsersByPrimaryGroup();
if (!AllDomainUsers.Any() && !TryLoadLDAPUsers())
{
return null;
}
return
AllDomainUsers.Where(
lu =>
{
var primaryGroupId = lu.GetValue(LdapConstants.ADSchemaAttributes.PRIMARY_GROUP_ID) as string;
return !string.IsNullOrEmpty(primaryGroupId) &&
sid.EndsWith(primaryGroupId);
})
.ToList();
}
private LdapObject FindUserByMember(string userAttributeValue)
{
if (!AllDomainUsers.Any() && !TryLoadLDAPUsers())
{
return null;
}
_logger.DebugFindUserByMember(userAttributeValue);
return AllDomainUsers.FirstOrDefault(u =>
u.DistinguishedName.Equals(userAttributeValue, StringComparison.InvariantCultureIgnoreCase)
|| Convert.ToString(u.GetValue(Settings.UserAttribute)).Equals(userAttributeValue,
StringComparison.InvariantCultureIgnoreCase));
}
private LdapObject FindGroupByMember(string member)
{
if (!AllDomainGroups.Any() && !TryLoadLDAPGroups())
{
return null;
}
_logger.DebugFindGroupByMember(member);
return AllDomainGroups.FirstOrDefault(g =>
g.DistinguishedName.Equals(member, StringComparison.InvariantCultureIgnoreCase));
}
public List<Tuple<UserInfo, LdapObject>> FindLdapUsers(string login)
{
var listResults = new List<Tuple<UserInfo, LdapObject>>();
var ldapLogin = LdapLogin.ParseLogin(login);
if (ldapLogin == null)
{
return listResults;
}
if (!LdapHelper.IsConnected)
{
LdapHelper.Connect();
}
var exps = new List<Expression> { Expression.Equal(Settings.LoginAttribute, ldapLogin.Username) };
if (!ldapLogin.Username.Equals(login) && ldapLogin.ToString().Equals(login))
{
exps.Add(Expression.Equal(Settings.LoginAttribute, login));
}
string email = null;
if (!string.IsNullOrEmpty(Settings.MailAttribute) && !string.IsNullOrEmpty(ldapLogin.Domain) && login.Contains("@"))
{
email = ldapLogin.ToString();
exps.Add(Expression.Equal(Settings.MailAttribute, email));
}
var searchTerm = exps.Count > 1 ? Criteria.Any(exps.ToArray()).ToString() : exps.First().ToString();
var users = LdapHelper.GetUsers(searchTerm, !string.IsNullOrEmpty(email) ? -1 : 1)
.Where(user => user != null)
.ToLookup(lu =>
{
var ui = Constants.LostUser;
try
{
if (string.IsNullOrEmpty(_ldapDomain))
{
_ldapDomain = LdapUtils.DistinguishedNameToDomain(lu.DistinguishedName);
}
ui = _ldapObjectExtension.ToUserInfo(lu, this);
}
catch (Exception ex)
{
_logger.ErrorToUserInfo(ex);
}
return Tuple.Create(ui, lu);
});
if (!users.Any())
{
return listResults;
}
foreach (var user in users)
{
var ui = user.Key.Item1;
if (ui.Equals(Constants.LostUser))
{
continue;
}
var ul = user.Key.Item2;
var ldapLoginAttribute = ul.GetValue(Settings.LoginAttribute) as string;
if (string.IsNullOrEmpty(ldapLoginAttribute))
{
_logger.WarnLoginAttributeIsEmpty(ul.DistinguishedName, Settings.LoginAttribute);
continue;
}
if (ldapLoginAttribute.Equals(login))
{
listResults.Add(user.Key);
continue;
}
if (!string.IsNullOrEmpty(email))
{
if (ui.Email.Equals(email, StringComparison.InvariantCultureIgnoreCase))
{
listResults.Add(user.Key);
continue;
}
}
if (LdapUtils.IsLoginAccepted(ldapLogin, ui, LDAPDomain))
{
listResults.Add(user.Key);
}
}
return listResults;
}
public List<LdapObject> FindUsersByAttribute(string key, string value, StringComparison comparison = StringComparison.InvariantCultureIgnoreCase)
{
var users = new List<LdapObject>();
if (!AllDomainUsers.Any() && !TryLoadLDAPUsers())
{
return users;
}
return users.Where(us => !us.IsDisabled && string.Equals((string)us.GetValue(key), value, comparison)).ToList();
}
public List<LdapObject> FindUsersByAttribute(string key, IEnumerable<string> value, StringComparison comparison = StringComparison.InvariantCultureIgnoreCase)
{
var users = new List<LdapObject>();
if (!AllDomainUsers.Any() && !TryLoadLDAPUsers())
{
return users;
}
return AllDomainUsers.Where(us => !us.IsDisabled && value.Any(val => string.Equals(val, (string)us.GetValue(key), comparison))).ToList();
}
public List<LdapObject> FindGroupsByAttribute(string key, string value, StringComparison comparison = StringComparison.InvariantCultureIgnoreCase)
{
var gr = new List<LdapObject>();
if (!AllDomainGroups.Any() && !TryLoadLDAPGroups())
{
return gr;
}
return gr.Where(g => !g.IsDisabled && string.Equals((string)g.GetValue(key), value, comparison)).ToList();
}
public List<LdapObject> FindGroupsByAttribute(string key, IEnumerable<string> value, StringComparison comparison = StringComparison.InvariantCultureIgnoreCase)
{
var gr = new List<LdapObject>();
if (!AllDomainGroups.Any() && !TryLoadLDAPGroups())
{
return gr;
}
return AllDomainGroups.Where(g => !g.IsDisabled && value.Any(val => string.Equals(val, (string)g.GetValue(key), comparison))).ToList();
}
public Tuple<UserInfo, LdapObject> Login(string login, string password)
{
try
{
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password))
{
return null;
}
var ldapUsers = FindLdapUsers(login);
_logger.DebugFindLdapUsers(login, ldapUsers.Count);
foreach (var ldapUser in ldapUsers)
{
string currentLogin = null;
try
{
var ldapUserInfo = ldapUser.Item1;
var ldapUserObject = ldapUser.Item2;
if (ldapUserInfo.Equals(Constants.LostUser)
|| ldapUserObject == null)
{
continue;
}
else if (string.IsNullOrEmpty(ldapUserObject.DistinguishedName)
|| string.IsNullOrEmpty(ldapUserObject.Sid))
{
_logger.DebugLdapUserImporterFailed(login, ldapUserObject.Sid);
continue;
}
currentLogin = ldapUserObject.DistinguishedName;
_logger.DebugLdapUserImporterLogin(currentLogin);
LdapHelper.CheckCredentials(currentLogin, password, Settings.Server,
Settings.PortNumber, Settings.StartTls, Settings.Ssl, Settings.AcceptCertificate,
Settings.AcceptCertificateHash);
return new Tuple<UserInfo, LdapObject>(ldapUserInfo, ldapUserObject);
}
catch (Exception ex)
{
_logger.ErrorLdapUserImporterLoginFailed(currentLogin ?? login, ex);
}
}
}
catch (Exception ex)
{
_logger.ErrorLdapUserImporterLoginFailed(login, ex);
}
return null;
}
public void Dispose()
{
if (LdapHelper != null)
{
LdapHelper.Dispose();
}
}
}

View File

@ -0,0 +1,81 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base;
public static class NotifyConstants
{
public static string TagUserName = "UserName";
public static string TagUserEmail = "UserEmail";
public static string TagMyStaffLink = "MyStaffLink";
public static INotifyAction ActionLdapActivation = new NotifyAction("user_ldap_activation");
public static ITagValue TagGreenButton(string btnText, string btnUrl)
{
Func<string> action = () =>
{
return
string.Format(@"<table style=""height: 48px; width: 540px; border-collapse: collapse; empty-cells: show; vertical-align: middle; text-align: center; margin: 30px auto; padding: 0;""><tbody><tr cellpadding=""0"" cellspacing=""0"" border=""0"">{2}<td style=""height: 48px; width: 380px; margin:0; padding:0; background-color: #66b76d; -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px;""><a style=""{3}"" target=""_blank"" href=""{0}"">{1}</a></td>{2}</tr></tbody></table>",
btnUrl,
btnText,
"<td style=\"height: 48px; width: 80px; margin:0; padding:0;\">&nbsp;</td>",
"color: #fff; font-family: Helvetica, Arial, Tahoma; font-size: 18px; font-weight: 600; vertical-align: middle; display: block; padding: 12px 0; text-align: center; text-decoration: none; background-color: #66b76d;");
};
return new TagActionValue("GreenButton", action);
}
private class TagActionValue : ITagValue
{
private readonly Func<string> action;
public string Tag
{
get;
private set;
}
public object Value
{
get { return action(); }
}
public TagActionValue(string name, Func<string> action)
{
Tag = name;
this.action = action;
}
}
}
public static class NotifyCommonTags
{
public static string Footer = "Footer";
public static string MasterTemplate = "MasterTemplate";
public static string WithoutUnsubscribe = "WithoutUnsubscribe";
}

View File

@ -0,0 +1,458 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Settings;
[Scope]
[Serializable]
public class LdapSettings : ISettings<LdapSettings>, ICloneable
{
[JsonIgnore]
public Guid ID
{
get { return new Guid("{197149b3-fbc9-44c2-b42a-232f7e729c16}"); }
}
public LdapSettings()
{
LdapMapping = new Dictionary<MappingFields, string>();
AccessRights = new Dictionary<AccessRight, string>();
}
public enum MappingFields
{
FirstNameAttribute,
SecondNameAttribute,
BirthDayAttribute,
GenderAttribute,
MobilePhoneAttribute,
MailAttribute,
TitleAttribute,
LocationAttribute,
AvatarAttribute,
AdditionalPhone,
AdditionalMobilePhone,
AdditionalMail,
Skype
}
public enum AccessRight
{
FullAccess,
Documents,
Projects,
CRM,
Community,
People,
Mail
}
public static readonly Dictionary<AccessRight, Guid> AccessRightsGuids = new Dictionary<AccessRight, Guid>()
{
{ AccessRight.FullAccess, Guid.Empty },
{ AccessRight.Documents, WebItemManager.DocumentsProductID },
{ AccessRight.Projects, WebItemManager.ProjectsProductID },
{ AccessRight.CRM, WebItemManager.CRMProductID },
{ AccessRight.Community, WebItemManager.CommunityProductID },
{ AccessRight.People, WebItemManager.PeopleProductID },
{ AccessRight.Mail, WebItemManager.MailProductID }
};
public LdapSettings GetDefault()
{
var isMono = WorkContext.IsMono;
var settings = new LdapSettings()
{
Server = "",
UserDN = "",
PortNumber = LdapConstants.STANDART_LDAP_PORT,
UserFilter = string.Format("({0}=*)",
isMono
? LdapConstants.RfcLDAPAttributes.UID
: LdapConstants.ADSchemaAttributes.USER_PRINCIPAL_NAME),
LoginAttribute = isMono
? LdapConstants.RfcLDAPAttributes.UID
: LdapConstants.ADSchemaAttributes.ACCOUNT_NAME,
FirstNameAttribute = LdapConstants.ADSchemaAttributes.FIRST_NAME,
SecondNameAttribute = LdapConstants.ADSchemaAttributes.SURNAME,
MailAttribute = LdapConstants.ADSchemaAttributes.MAIL,
TitleAttribute = LdapConstants.ADSchemaAttributes.TITLE,
MobilePhoneAttribute = LdapConstants.ADSchemaAttributes.MOBILE,
LocationAttribute = LdapConstants.ADSchemaAttributes.STREET,
GroupDN = "",
GroupFilter = string.Format("({0}={1})", LdapConstants.ADSchemaAttributes.OBJECT_CLASS,
isMono
? LdapConstants.ObjectClassKnowedValues.POSIX_GROUP
: LdapConstants.ObjectClassKnowedValues.GROUP),
UserAttribute =
isMono
? LdapConstants.RfcLDAPAttributes.UID
: LdapConstants.ADSchemaAttributes.DISTINGUISHED_NAME,
GroupAttribute = isMono ? LdapConstants.RfcLDAPAttributes.MEMBER_UID : LdapConstants.ADSchemaAttributes.MEMBER,
GroupNameAttribute = LdapConstants.ADSchemaAttributes.COMMON_NAME,
Authentication = true,
AcceptCertificate = false,
AcceptCertificateHash = null,
StartTls = false,
Ssl = false,
SendWelcomeEmail = false
};
return settings;
}
public override bool Equals(object obj)
{
var settings = obj as LdapSettings;
return settings != null
&& EnableLdapAuthentication == settings.EnableLdapAuthentication
&& StartTls == settings.StartTls
&& Ssl == settings.Ssl
&& SendWelcomeEmail == settings.SendWelcomeEmail
&& (string.IsNullOrEmpty(Server)
&& string.IsNullOrEmpty(settings.Server)
|| Server == settings.Server)
&& (string.IsNullOrEmpty(UserDN)
&& string.IsNullOrEmpty(settings.UserDN)
|| UserDN == settings.UserDN)
&& PortNumber == settings.PortNumber
&& UserFilter == settings.UserFilter
&& LoginAttribute == settings.LoginAttribute
&& LdapMapping.Count == settings.LdapMapping.Count
&& LdapMapping.All(pair => settings.LdapMapping.ContainsKey(pair.Key)
&& pair.Value == settings.LdapMapping[pair.Key])
&& AccessRights.Count == settings.AccessRights.Count
&& AccessRights.All(pair => settings.AccessRights.ContainsKey(pair.Key)
&& pair.Value == settings.AccessRights[pair.Key])
&& GroupMembership == settings.GroupMembership
&& (string.IsNullOrEmpty(GroupDN)
&& string.IsNullOrEmpty(settings.GroupDN)
|| GroupDN == settings.GroupDN)
&& GroupFilter == settings.GroupFilter
&& UserAttribute == settings.UserAttribute
&& GroupAttribute == settings.GroupAttribute
&& (string.IsNullOrEmpty(Login)
&& string.IsNullOrEmpty(settings.Login)
|| Login == settings.Login)
&& Authentication == settings.Authentication;
}
public override int GetHashCode()
{
var hash = 3;
hash = (hash * 2) + EnableLdapAuthentication.GetHashCode();
hash = (hash * 2) + StartTls.GetHashCode();
hash = (hash * 2) + Ssl.GetHashCode();
hash = (hash * 2) + SendWelcomeEmail.GetHashCode();
hash = (hash * 2) + Server.GetHashCode();
hash = (hash * 2) + UserDN.GetHashCode();
hash = (hash * 2) + PortNumber.GetHashCode();
hash = (hash * 2) + UserFilter.GetHashCode();
hash = (hash * 2) + LoginAttribute.GetHashCode();
hash = (hash * 2) + GroupMembership.GetHashCode();
hash = (hash * 2) + GroupDN.GetHashCode();
hash = (hash * 2) + GroupNameAttribute.GetHashCode();
hash = (hash * 2) + GroupFilter.GetHashCode();
hash = (hash * 2) + UserAttribute.GetHashCode();
hash = (hash * 2) + GroupAttribute.GetHashCode();
hash = (hash * 2) + Authentication.GetHashCode();
hash = (hash * 2) + Login.GetHashCode();
foreach (var pair in LdapMapping)
{
hash = (hash * 2) + pair.Value.GetHashCode();
}
foreach (var pair in AccessRights)
{
hash = (hash * 2) + pair.Value.GetHashCode();
}
return hash;
}
public object Clone()
{
return MemberwiseClone();
}
public bool EnableLdapAuthentication { get; set; }
public bool StartTls { get; set; }
public bool Ssl { get; set; }
public bool SendWelcomeEmail { get; set; }
public string Server { get; set; }
// ReSharper disable once InconsistentNaming
public string UserDN { get; set; }
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public int PortNumber { get; set; }
public string UserFilter { get; set; }
public string LoginAttribute { get; set; }
public Dictionary<MappingFields, string> LdapMapping { get; set; }
//ToDo: use SId instead of group name
public Dictionary<AccessRight, string> AccessRights { get; set; }
public string FirstNameAttribute
{
get
{
return GetOldSetting(MappingFields.FirstNameAttribute);
}
set
{
SetOldSetting(MappingFields.FirstNameAttribute, value);
}
}
public string SecondNameAttribute
{
get
{
return GetOldSetting(MappingFields.SecondNameAttribute);
}
set
{
SetOldSetting(MappingFields.SecondNameAttribute, value);
}
}
public string MailAttribute
{
get
{
return GetOldSetting(MappingFields.MailAttribute);
}
set
{
SetOldSetting(MappingFields.MailAttribute, value);
}
}
public string TitleAttribute
{
get
{
return GetOldSetting(MappingFields.TitleAttribute);
}
set
{
SetOldSetting(MappingFields.TitleAttribute, value);
}
}
public string MobilePhoneAttribute
{
get
{
return GetOldSetting(MappingFields.MobilePhoneAttribute);
}
set
{
SetOldSetting(MappingFields.MobilePhoneAttribute, value);
}
}
public string LocationAttribute
{
get
{
return GetOldSetting(MappingFields.LocationAttribute);
}
set
{
SetOldSetting(MappingFields.LocationAttribute, value);
}
}
public bool GroupMembership { get; set; }
// ReSharper disable once InconsistentNaming
public string GroupDN { get; set; }
public string GroupNameAttribute { get; set; }
public string GroupFilter { get; set; }
public string UserAttribute { get; set; }
public string GroupAttribute { get; set; }
public bool Authentication { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public byte[] PasswordBytes { get; set; }
public bool IsDefault { get; set; }
public bool AcceptCertificate { get; set; }
public string AcceptCertificateHash { get; set; }
private string GetOldSetting(MappingFields field)
{
if (LdapMapping == null)
{
LdapMapping = new Dictionary<MappingFields, string>();
}
if (LdapMapping.ContainsKey(field))
{
return LdapMapping[field];
}
else
{
return "";
}
}
private void SetOldSetting(MappingFields field, string value)
{
if (LdapMapping == null)
{
LdapMapping = new Dictionary<MappingFields, string>();
}
if (string.IsNullOrEmpty(value))
{
if (LdapMapping.ContainsKey(field))
{
LdapMapping.Remove(field);
}
return;
}
if (LdapMapping.ContainsKey(field))
{
LdapMapping[field] = value;
}
else
{
LdapMapping.Add(field, value);
}
}
}
[Scope]
[Serializable]
public class LdapCronSettings : ISettings<LdapCronSettings>
{
[JsonIgnore]
public Guid ID
{
get { return new Guid("{58C42C54-56CD-4BEF-A3ED-C60ACCF6E975}"); }
}
public LdapCronSettings GetDefault()
{
return new LdapCronSettings()
{
Cron = null
};
}
public string Cron { get; set; }
}
[Serializable]
public class LdapCurrentAcccessSettings : ISettings<LdapCurrentAcccessSettings>
{
[JsonIgnore]
public Guid ID
{
get { return new Guid("{134B5EAA-F612-4834-AEAB-34C90515EA4E}"); }
}
public LdapCurrentAcccessSettings GetDefault()
{
return new LdapCurrentAcccessSettings() { CurrentAccessRights = null };
}
public LdapCurrentAcccessSettings()
{
CurrentAccessRights = new Dictionary<LdapSettings.AccessRight, List<string>>();
}
public Dictionary<LdapSettings.AccessRight, List<string>> CurrentAccessRights { get; set; }
}
[Serializable]
public class LdapCurrentUserPhotos : ISettings<LdapCurrentUserPhotos>
{
[JsonIgnore]
public Guid ID
{
get { return new Guid("{50AE3C2B-0783-480F-AF30-679D0F0A2D3E}"); }
}
public LdapCurrentUserPhotos GetDefault()
{
return new LdapCurrentUserPhotos() { CurrentPhotos = null };
}
public LdapCurrentUserPhotos()
{
CurrentPhotos = new Dictionary<Guid, string>();
}
public Dictionary<Guid, string> CurrentPhotos { get; set; }
}
[Serializable]
public class LdapCurrentDomain : ISettings<LdapCurrentDomain>
{
[JsonIgnore]
public Guid ID
{
get { return new Guid("{75A5F745-F697-4418-B38D-0FE0D277E258}"); }
}
public LdapCurrentDomain GetDefault()
{
return new LdapCurrentDomain() { CurrentDomain = null };
}
public string CurrentDomain { get; set; }
}

View File

@ -0,0 +1,50 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Settings;
public abstract class LdapSettingsChecker
{
protected readonly ILogger<LdapSettingsChecker> _logger;
public LdapUserImporter LdapImporter { get; private set; }
public LdapSettings Settings
{
get { return LdapImporter.Settings; }
}
protected LdapSettingsChecker(ILogger<LdapSettingsChecker> logger)
{
_logger = logger;
}
public void Init(LdapUserImporter importer)
{
LdapImporter = importer;
}
public abstract LdapSettingsStatus CheckSettings();
}

View File

@ -0,0 +1,49 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Base.Settings;
public enum LdapSettingsStatus
{
Ok = 0,
WrongServerOrPort = 1,
WrongUserDn = 2,
IncorrectLDAPFilter = 3,
UsersNotFound = 4,
WrongLoginAttribute = 5,
WrongGroupDn = 6,
IncorrectGroupLDAPFilter = 7,
GroupsNotFound = 8,
WrongGroupAttribute = 9,
WrongUserAttribute = 10,
WrongGroupNameAttribute = 11,
CredentialsNotValid = 12,
ConnectError = 13,
StrongAuthRequired = 14,
WrongSidAttribute = 15,
CertificateRequest = 16,
TlsNotSupported = 17,
DomainNotFound = 18
}

View File

@ -0,0 +1,59 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations.Data;
public class LdapChange
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public LdapChangeAction Action { get; private set; }
public string Sid { get; private set; }
public string Name { get; private set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Email { get; private set; }
[JsonConverter(typeof(JsonStringEnumConverter))]
public LdapChangeType Type { get; private set; }
public List<LdapItemChange> Changes { get; private set; }
public LdapChange(string sid, string name, LdapChangeType type, LdapChangeAction action,
List<LdapItemChange> changes = null) : this(sid, name, null, type, action, changes)
{
}
public LdapChange(string sid, string name, string email, LdapChangeType type, LdapChangeAction action, List<LdapItemChange> changes = null)
{
Sid = sid;
Name = name;
Type = type;
Action = action;
Changes = changes ?? new List<LdapItemChange>();
Email = email;
}
}

View File

@ -0,0 +1,219 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations.Data;
[Scope]
public class LdapChangeCollection : List<LdapChange>
{
private readonly UserFormatter _userFormatter;
public LdapChangeCollection(UserFormatter userFormatter)
{
_userFormatter = userFormatter;
}
#region User
public void SetSkipUserChange(UserInfo user)
{
var change = new LdapChange(user.Sid,
_userFormatter.GetUserName(user, DisplayUserNameFormat.Default),
user.Email,
LdapChangeType.User, LdapChangeAction.Skip);
Add(change);
}
public void SetSaveAsPortalUserChange(UserInfo user)
{
var fieldChanges = new List<LdapItemChange>
{
new LdapItemChange(LdapItemChangeKey.Sid, user.Sid, null)
};
var change = new LdapChange(user.Sid,
_userFormatter.GetUserName(user, DisplayUserNameFormat.Default),
user.Email, LdapChangeType.User, LdapChangeAction.SaveAsPortal, fieldChanges);
Add(change);
}
public void SetNoneUserChange(UserInfo user)
{
var change = new LdapChange(user.Sid,
_userFormatter.GetUserName(user, DisplayUserNameFormat.Default), user.Email,
LdapChangeType.User, LdapChangeAction.None);
Add(change);
}
public void SetUpdateUserChange(UserInfo beforeUserInfo, UserInfo afterUserInfo, ILogger log = null)
{
var fieldChanges =
LdapUserMapping.Fields.Select(field => GetPropChange(field, beforeUserInfo, afterUserInfo, log))
.Where(pch => pch != null)
.ToList();
var change = new LdapChange(beforeUserInfo.Sid,
_userFormatter.GetUserName(afterUserInfo, DisplayUserNameFormat.Default), afterUserInfo.Email,
LdapChangeType.User, LdapChangeAction.Update, fieldChanges);
Add(change);
}
public void SetAddUserChange(UserInfo user, ILogger log = null)
{
var fieldChanges =
LdapUserMapping.Fields.Select(field => GetPropChange(field, after: user, log: log))
.Where(pch => pch != null)
.ToList();
var change = new LdapChange(user.Sid,
_userFormatter.GetUserName(user, DisplayUserNameFormat.Default), user.Email,
LdapChangeType.User, LdapChangeAction.Add, fieldChanges);
Add(change);
}
public void SetRemoveUserChange(UserInfo user)
{
var change = new LdapChange(user.Sid,
_userFormatter.GetUserName(user, DisplayUserNameFormat.Default), user.Email,
LdapChangeType.User, LdapChangeAction.Remove);
Add(change);
}
#endregion
#region Group
public void SetAddGroupChange(GroupInfo group, ILogger log = null)
{
var fieldChanges = new List<LdapItemChange>
{
new LdapItemChange(LdapItemChangeKey.Name, null, group.Name),
new LdapItemChange(LdapItemChangeKey.Sid, null, group.Sid)
};
var change = new LdapChange(group.Sid, group.Name,
LdapChangeType.Group, LdapChangeAction.Add, fieldChanges);
Add(change);
}
public void SetAddGroupMembersChange(GroupInfo group,
List<UserInfo> members)
{
var fieldChanges =
members.Select(
member =>
new LdapItemChange(LdapItemChangeKey.Member, null,
_userFormatter.GetUserName(member, DisplayUserNameFormat.Default))).ToList();
var change = new LdapChange(group.Sid, group.Name,
LdapChangeType.Group, LdapChangeAction.AddMember, fieldChanges);
Add(change);
}
public void SetSkipGroupChange(GroupInfo group)
{
var change = new LdapChange(group.Sid, group.Name, LdapChangeType.Group,
LdapChangeAction.Skip);
Add(change);
}
public void SetUpdateGroupChange(GroupInfo group)
{
var fieldChanges = new List<LdapItemChange>
{
new LdapItemChange(LdapItemChangeKey.Name, group.Name, group.Name)
};
var change = new LdapChange(group.Sid, group.Name,
LdapChangeType.Group, LdapChangeAction.Update, fieldChanges);
Add(change);
}
public void SetRemoveGroupChange(GroupInfo group, ILogger log = null)
{
var change = new LdapChange(group.Sid, group.Name,
LdapChangeType.Group, LdapChangeAction.Remove);
Add(change);
}
public void SetRemoveGroupMembersChange(GroupInfo group,
List<UserInfo> members)
{
var fieldChanges =
members.Select(
member =>
new LdapItemChange(LdapItemChangeKey.Member, null,
_userFormatter.GetUserName(member, DisplayUserNameFormat.Default))).ToList();
var change = new LdapChange(group.Sid, group.Name,
LdapChangeType.Group, LdapChangeAction.RemoveMember, fieldChanges);
Add(change);
}
#endregion
private static LdapItemChange GetPropChange(string propName, UserInfo before = null, UserInfo after = null, ILogger log = null)
{
try
{
var valueSrc = before != null
? before.GetType().GetProperty(propName).GetValue(before, null) as string
: "";
var valueDst = after != null
? after.GetType().GetProperty(propName).GetValue(before, null) as string
: "";
LdapItemChangeKey key;
if (!Enum.TryParse(propName, out key))
{
throw new InvalidEnumArgumentException(propName);
}
var change = new LdapItemChange(key, valueSrc, valueDst);
return change;
}
catch (Exception ex)
{
if (log != null)
{
log.ErrorCanNotGetSidProperty(propName, ex);
}
}
return null;
}
}

View File

@ -0,0 +1,74 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations.Data;
public enum LdapChangeType
{
User,
Group
}
public enum LdapItemChangeKey
{
Sid,
Name,
FirstName,
LastName,
Mail,
Phone,
Title,
Location,
Member
}
public enum LdapChangeAction
{
None,
Skip,
Add,
AddMember,
Merge,
Update,
Remove,
RemoveMember,
SaveAsPortal
}
public static class LdapUserMapping
{
public static readonly List<string> Fields = new List<string>
{
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.FirstName),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.LastName),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.Mail),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.Phone),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.Title),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.Location),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.Sid),
Enum.GetName(typeof(LdapItemChangeKey), LdapItemChangeKey.Member)
};
}

View File

@ -0,0 +1,47 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations.Data;
public class LdapItemChange
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public LdapItemChangeKey Key { get; private set; }
public string Before { get; private set; }
public string After { get; private set; }
public bool IsChanged { get; private set; }
public LdapItemChange(LdapItemChangeKey key, string before, string after)
{
Key = key;
Before = before;
After = after;
IsChanged = Before != null && !Before.Equals(After) || After != null && !After.Equals(Before);
}
}

View File

@ -0,0 +1,40 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations.Data;
public static class LdapTaskProperty
{
public static string OWNER = "LDAPOwner";
public static string OPERATION_TYPE = "LDAPOperationType";
public static string SOURCE = "LDAPSource";
public static string PROGRESS = "LDAPProgress";
public static string RESULT = "LDAPResult";
public static string ERROR = "LDAPError";
public static string WARNING = "LDAPWarning";
public static string CERT_REQUEST = "LDAPCertRequest";
public static string FINISHED = "LDAPFinished";
}

View File

@ -0,0 +1,614 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations;
[Scope]
public class LdapLocalization
{
private ResourceManager _resourceManager;
private ResourceManager _notifyResourceManager;
public void Init(ResourceManager resourceManager = null, ResourceManager notifyResourceManager = null)
{
_resourceManager = resourceManager;
_notifyResourceManager = notifyResourceManager;
}
public string FirstName
{
get
{
const string def_key = "FirstName";
const string def_val = "First Name";
return GetValueOrDefault(def_key, def_val);
}
}
public string LastName
{
get
{
const string def_key = "LastName";
const string def_val = "Last Name";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsModifyLdapUsers
{
get
{
const string def_key = "LdapSettingsModifyLdapUsers";
const string def_val = "Modifying LDAP users on ordinary portal users";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsTenantQuotaSettled
{
get
{
const string def_key = "LdapSettingsTenantQuotaSettled";
const string def_val = "The current pricing plan user limit has been reached";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorCantCreateUsers
{
get
{
const string def_key = "LdapSettingsErrorCantCreateUsers";
const string def_val = "Users could not be created, the received data are incorrect.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsInternalServerError
{
get
{
const string def_key = "LdapSettingsInternalServerError";
const string def_val = "Server internal error.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusGettingUsersFromLdap
{
get
{
const string def_key = "LdapSettingsStatusGettingUsersFromLdap";
const string def_val = "Retrieving the user list from the LDAP server";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusGivingRights
{
get
{
const string def_key = "LdapSettingsStatusGivingRights";
const string def_val = "Setting user {0} as {1} admin";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorUsersNotFound
{
get
{
const string def_key = "LdapSettingsErrorUsersNotFound";
const string def_val = "No users could be found.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusRemovingOldRights
{
get
{
const string def_key = "LdapSettingsStatusRemovingOldRights";
const string def_val = "Removing outdated access rights that have been loaded via LDAP earlier";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusRemovingOldUsers
{
get
{
const string def_key = "LdapSettingsStatusRemovingOldUsers";
const string def_val = "Removing outdated user profiles that have been loaded via LDAP earlier";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusSavingUserPhoto
{
get
{
const string def_key = "LdapSettingsStatusSavingUserPhoto";
const string def_val = "Saving photo";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusSavingUsers
{
get
{
const string def_key = "LdapSettingsStatusSavingUsers";
const string def_val = "Saving users";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusSyncingUsers
{
get
{
const string def_key = "LdapSettingsStatusSyncingUsers";
const string def_val = "Syncing users";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusRemovingOldGroups
{
get
{
const string def_key = "LdapSettingsStatusRemovingOldGroups";
const string def_val = "Removing outdated groups that have been loaded via LDAP earlier";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusGettingGroupsFromLdap
{
get
{
const string def_key = "LdapSettingsStatusGettingGroupsFromLdap";
const string def_val = "Retrieving the group list from the LDAP server";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorGroupsNotFound
{
get
{
const string def_key = "LdapSettingsErrorGroupsNotFound";
const string def_val = "No groups could be found.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusSavingGroups
{
get
{
const string def_key = "LdapSettingsStatusSavingGroups";
const string def_val = "Saving groups";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorCantGetLdapSettings
{
get
{
const string def_key = "LdapSettingsErrorCantGetLdapSettings";
const string def_val = "The server could not get settings.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusCheckingLdapSettings
{
get
{
const string def_key = "LdapSettingsStatusCheckingLdapSettings";
const string def_val = "Checking LDAP support settings";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusLoadingBaseInfo
{
get
{
const string def_key = "LdapSettingsStatusLoadingBaseInfo";
const string def_val = "Loading LDAP base info";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusCertificateVerification
{
get
{
const string def_key = "LdapSettingsStatusCertificateVerification";
const string def_val = "Certificate verification";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongServerOrPort
{
get
{
const string def_key = "LdapSettingsErrorWrongServerOrPort";
const string def_val =
"Unable to connect to LDAP server. Please check if the server address and port number are correct.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongUserDn
{
get
{
const string def_key = "LdapSettingsErrorWrongUserDN";
const string def_val = "Incorrect User DN.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorIncorrectLdapFilter
{
get
{
const string def_key = "LdapSettingsErrorIncorrectLdapFilter";
const string def_val = "Invalid User Filter value.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorLostRights
{
get
{
const string def_key = "LdapSettingsErrorLostRights";
const string def_val = "You attempted to take away admin rights from yourself. Your admin rights was unaffected.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorRemovedYourself
{
get
{
const string def_key = "LdapSettingsErrorRemovedYourself";
const string def_val = "Your account has been unlinked from LDAP. You may need to set a password for your account because you won't be able to login using LDAP password.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongLoginAttribute
{
get
{
const string def_key = "LdapSettingsErrorWrongLoginAttribute";
const string def_val = "Could not get Login Attribute for one or several users.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongGroupDn
{
get
{
const string def_key = "LdapSettingsErrorWrongGroupDN";
const string def_val = "Incorrect Group DN.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongGroupFilter
{
get
{
const string def_key = "LdapSettingsErrorWrongGroupFilter";
const string def_val = "Could not get Group Attribute for one or several groups.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongGroupAttribute
{
get
{
const string def_key = "LdapSettingsErrorWrongGroupAttribute";
const string def_val = "Could not get User Attribute for one or several users.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongUserAttribute
{
get
{
const string def_key = "LdapSettingsErrorWrongUserAttribute";
const string def_val = "Could not get User Attribute for one or several users.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorWrongGroupNameAttribute
{
get
{
const string def_key = "LdapSettingsErrorWrongGroupNameAttribute";
const string def_val = "Could not obtain Group Name Attribute for one or several groups.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorCredentialsNotValid
{
get
{
const string def_key = "LdapSettingsErrorCredentialsNotValid";
const string def_val = "Incorrect login or password.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsConnectError
{
get
{
const string def_key = "LdapSettingsConnectError";
const string def_val =
"A more secure authentication type is required. Please use encripted connection or enable plain authentication on the server.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStrongAuthRequired
{
get
{
const string def_key = "LdapSettingsStrongAuthRequired";
const string def_val =
"A more secure authentication type is required. Please use encripted connection or enable plain authentication on the server.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsWrongSidAttribute
{
get
{
const string def_key = "LdapSettingsWrongSidAttribute";
const string def_val =
"Unique ID for user/group objects could not be obtained. By default the system will try to match one of the following identifiers: entryUUID, nsuniqueid, GUID, objectSid. If none of the attributes corresponds to your LDAP server, please specify the necessary attribute in the ldap.unique.id setting of the web.appsettings.config file.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsTlsNotSupported
{
get
{
const string def_key = "LdapSettingsTlsNotSupported";
const string def_val = "StartTLS not supported for current LDAP server.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorDomainNotFound
{
get
{
const string def_key = "LdapSettingsErrorDomainNotFound";
const string def_val = "LDAP domain not found.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorUnknownError
{
get
{
const string def_key = "LdapSettingsErrorUnknownError";
const string def_val = "Unknown error.";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusSavingSettings
{
get
{
const string def_key = "LdapSettingsStatusSavingSettings";
const string def_val = "Saving settings";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsErrorCantSaveLdapSettings
{
get
{
const string def_key = "LdapSettingsErrorCantSaveLdapSettings";
const string def_val = "The server could not save settings.";
return GetValueOrDefault(def_key, def_val);
}
}
public string ErrorEmailEmpty
{
get
{
const string def_key = "ErrorEmailEmpty";
const string def_val = "Email field is empty";
return GetValueOrDefault(def_key, def_val);
}
}
public string ErrorAccessDenied
{
get
{
const string def_key = "ErrorAccessDenied";
const string def_val = "No permissions to perform this action";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusAddingGroupUser
{
get
{
const string def_key = "LdapSettingsStatusAddingGroupUser";
const string def_val = "adding user";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusRemovingGroupUser
{
get
{
const string def_key = "LdapSettingsStatusRemovingGroupUser";
const string def_val = "removing user";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusUpdatingAccessRights
{
get
{
const string def_key = "LdapSettingsStatusUpdatingAccessRights";
const string def_val = "Updating users access rights";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusUpdatingUserPhotos
{
get
{
const string def_key = "LdapSettingsStatusUpdatingUserPhotos";
const string def_val = "Updating user photos";
return GetValueOrDefault(def_key, def_val);
}
}
public string LdapSettingsStatusDisconnecting
{
get
{
const string def_key = "LdapSettingsStatusDisconnecting";
const string def_val = "LDAP disconnecting";
return GetValueOrDefault(def_key, def_val);
}
}
public string NotifyButtonJoin
{
get
{
const string def_key = "ButtonAccessYourPortal";
const string def_val = "Click here to join the portal";
return GetValueOrDefault(def_key, def_val);
}
}
private string GetValueOrDefault(string key, string defaultValue)
{
try
{
var val = _resourceManager != null ? _resourceManager.GetString(key) : null;
if (val == null && _notifyResourceManager != null)
{
val = _notifyResourceManager.GetString(key);
}
return val != null ? val : defaultValue;
}
catch
{
//
}
return defaultValue;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations;
public class LdapOperationStatus
{
public bool Completed { get; set; }
public string Id { get; set; }
public string Status { get; set; }
public string Error { get; set; }
public string Warning { get; set; }
public int Percents { get; set; }
public string CertificateConfirmRequest { get; set; }
public string Source { get; set; }
public string OperationType { get; set; }
}

View File

@ -0,0 +1,35 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations;
public enum LdapOperationType
{
Save,
Sync,
SaveTest,
SyncTest
}

View File

@ -0,0 +1,247 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.ComplexOperations;
[Singletone(Additional = typeof(LdapOperationExtension))]
public class LdapSaveSyncOperation
{
public const string CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME = "ldapOperation";
private readonly DistributedTaskQueue _progressQueue;
private readonly IServiceProvider _serviceProvider;
public LdapSaveSyncOperation(
IServiceProvider serviceProvider,
IDistributedTaskQueueFactory queueFactory)
{
_serviceProvider = serviceProvider;
_progressQueue = queueFactory.CreateQueue(CUSTOM_DISTRIBUTED_TASK_QUEUE_NAME);
}
public void RunJob(LdapSettings settings, Tenant tenant, LdapOperationType operationType, LdapLocalization resource = null, string userId = null)
{
var item = _progressQueue.GetAllTasks<LdapOperationJob>().FirstOrDefault(t => t.TenantId == tenant.Id);
if (item != null && item.IsCompleted)
{
_progressQueue.DequeueTask(item.Id);
item = null;
}
if (item == null)
{
using var scope = _serviceProvider.CreateScope();
item = scope.ServiceProvider.GetRequiredService<LdapOperationJob>();
item.InitJob(settings, tenant, operationType, resource, userId);
_progressQueue.EnqueueTask(item);
}
item.PublishChanges();
}
public LdapOperationStatus TestLdapSave(LdapSettings ldapSettings, Tenant tenant, string userId)
{
var (hasStarted, operations) = HasStarterdForTenant(tenant.Id, LdapOperationType.SyncTest, LdapOperationType.SaveTest);
if (hasStarted)
{
return ToLdapOperationStatus(tenant.Id);
}
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapLocalization = new LdapLocalization();
ldapLocalization.Init(Resource.ResourceManager);
RunJob(ldapSettings, tenant, LdapOperationType.SaveTest, ldapLocalization, userId);
return ToLdapOperationStatus(tenant.Id);
}
public LdapOperationStatus SaveLdapSettings(LdapSettings ldapSettings, Tenant tenant, string userId)
{
var operations = GetOperationsForTenant(tenant.Id);
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
//ToDo
ldapSettings.AccessRights.Clear();
if (!ldapSettings.LdapMapping.ContainsKey(LdapSettings.MappingFields.MailAttribute) || string.IsNullOrEmpty(ldapSettings.LdapMapping[LdapSettings.MappingFields.MailAttribute]))
{
ldapSettings.SendWelcomeEmail = false;
}
var ldapLocalization = new LdapLocalization();
ldapLocalization.Init(Resource.ResourceManager, WebstudioNotifyPatternResource.ResourceManager);
RunJob(ldapSettings, tenant, LdapOperationType.Save, ldapLocalization, userId);
return ToLdapOperationStatus(tenant.Id);
}
public LdapOperationStatus SyncLdap(LdapSettings ldapSettings, Tenant tenant, string userId)
{
var (hasStarted, operations) = HasStarterdForTenant(tenant.Id, LdapOperationType.Sync, LdapOperationType.Save);
if (hasStarted)
{
return ToLdapOperationStatus(tenant.Id);
}
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapLocalization = new LdapLocalization();
ldapLocalization.Init(Resource.ResourceManager);
RunJob(ldapSettings, tenant, LdapOperationType.Sync, ldapLocalization, userId);
return ToLdapOperationStatus(tenant.Id);
}
public LdapOperationStatus TestLdapSync(LdapSettings ldapSettings, Tenant tenant)
{
var (hasStarted, operations) = HasStarterdForTenant(tenant.Id, LdapOperationType.SyncTest, LdapOperationType.SaveTest);
if (hasStarted)
{
return ToLdapOperationStatus(tenant.Id);
}
if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
{
return GetStartProcessError();
}
var ldapLocalization = new LdapLocalization();
ldapLocalization.Init(Resource.ResourceManager);
RunJob(ldapSettings, tenant, LdapOperationType.SyncTest, ldapLocalization);
return ToLdapOperationStatus(tenant.Id);
}
public LdapOperationStatus ToLdapOperationStatus(int tenantId)
{
var operations = _progressQueue.GetAllTasks<LdapOperationJob>().ToList();
foreach (var o in operations)
{
if (Process.GetProcesses().Any(p => p.Id == o.InstanceId))
{
continue;
}
o[LdapTaskProperty.PROGRESS] = 100;
_progressQueue.DequeueTask(o.Id);
}
var operation =
operations
.FirstOrDefault(t => t[LdapTaskProperty.OWNER] == tenantId);
if (operation == null)
{
return null;
}
if (DistributedTaskStatus.Running < operation.Status)
{
operation[LdapTaskProperty.PROGRESS] = 100;
_progressQueue.DequeueTask(operation.Id);
}
var result = new LdapOperationStatus
{
Id = operation.Id,
Completed = operation[LdapTaskProperty.FINISHED],
Percents = operation[LdapTaskProperty.PROGRESS],
Status = operation[LdapTaskProperty.RESULT],
Error = operation[LdapTaskProperty.ERROR],
CertificateConfirmRequest = operation[LdapTaskProperty.CERT_REQUEST] != "" ? operation[LdapTaskProperty.CERT_REQUEST] : null,
Source = operation[LdapTaskProperty.SOURCE],
OperationType = operation[LdapTaskProperty.OPERATION_TYPE],
Warning = operation[LdapTaskProperty.WARNING]
};
if (!(string.IsNullOrEmpty(result.Warning)))
{
operation[LdapTaskProperty.WARNING] = ""; // "mark" as read
}
return result;
}
private static LdapOperationStatus GetStartProcessError()
{
var result = new LdapOperationStatus
{
Id = null,
Completed = true,
Percents = 0,
Status = "",
Error = Resource.LdapSettingsTooManyOperations,
CertificateConfirmRequest = null,
Source = ""
};
return result;
}
private (bool hasStarted, List<LdapOperationJob> operations) HasStarterdForTenant(int tenantId, LdapOperationType arg1, LdapOperationType arg2)
{
var operations = GetOperationsForTenant(tenantId);
var hasStarted = operations.Any(o =>
{
var opType = o[LdapTaskProperty.OPERATION_TYPE];
return o.Status <= DistributedTaskStatus.Running &&
(opType == arg1.ToString() || opType == arg2.ToString());
});
return (hasStarted, operations);
}
private List<LdapOperationJob> GetOperationsForTenant(int tenantId)
{
return _progressQueue.GetAllTasks<LdapOperationJob>()
.Where(t => t[LdapTaskProperty.OWNER] == tenantId)
.ToList();
}
public static class LdapOperationExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<LdapOperationJob>();
}
}
}

View File

@ -0,0 +1,83 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
global using System.Collections.Concurrent;
global using System.ComponentModel;
global using System.Diagnostics;
global using System.Globalization;
global using System.Net.Mail;
global using System.Net.Security;
global using System.Net.Sockets;
global using System.Resources;
global using System.Security;
global using System.Security.Cryptography;
global using System.Security.Cryptography.X509Certificates;
global using System.Text;
global using System.Text.Json;
global using System.Text.Json.Serialization;
global using System.Text.RegularExpressions;
global using ASC.ActiveDirectory.Base;
global using ASC.ActiveDirectory.Base.Data;
global using ASC.ActiveDirectory.Base.Expressions;
global using ASC.ActiveDirectory.Base.Settings;
global using ASC.ActiveDirectory.ComplexOperations;
global using ASC.ActiveDirectory.ComplexOperations.Data;
global using ASC.ActiveDirectory.Log;
global using ASC.ActiveDirectory.Novell;
global using ASC.ActiveDirectory.Novell.Data;
global using ASC.ActiveDirectory.Novell.Exceptions;
global using ASC.ActiveDirectory.Novell.Extensions;
global using ASC.Common;
global using ASC.Common.Security.Authorizing;
global using ASC.Common.Threading;
global using ASC.Core;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.EF.Model;
global using ASC.Core.Common.Settings;
global using ASC.Core.Tenants;
global using ASC.Core.Users;
global using ASC.Notify;
global using ASC.Notify.Engine;
global using ASC.Notify.Model;
global using ASC.Notify.Patterns;
global using ASC.Notify.Recipients;
global using ASC.Security.Cryptography;
global using ASC.Web.Core;
global using ASC.Web.Core.PublicResources;
global using ASC.Web.Core.Users;
global using ASC.Web.Studio.Utility;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using Novell.Directory.Ldap;
global using Novell.Directory.Ldap.Controls;
global using Novell.Directory.Ldap.Rfc2251;
global using Novell.Directory.Ldap.Utilclass;

View File

@ -0,0 +1,752 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Constants = ASC.Core.Users.Constants;
using Mapping = ASC.ActiveDirectory.Base.Settings.LdapSettings.MappingFields;
using SecurityContext = ASC.Core.SecurityContext;
namespace ASC.ActiveDirectory;
[Scope]
public class LdapUserManager
{
private readonly ILogger<LdapUserManager> _logger;
private readonly UserManager _userManager;
private readonly TenantManager _tenantManager;
private readonly TenantUtil _tenantUtil;
private readonly SecurityContext _securityContext;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly SettingsManager _settingsManager;
private readonly DisplayUserSettingsHelper _displayUserSettingsHelper;
private readonly UserFormatter _userFormatter;
private readonly IServiceProvider _serviceProvider;
private readonly NovellLdapUserImporter _novellLdapUserImporter;
private LdapLocalization _resource;
public LdapUserManager(
ILogger<LdapUserManager> logger,
IServiceProvider serviceProvider,
UserManager userManager,
TenantManager tenantManager,
TenantUtil tenantUtil,
SecurityContext securityContext,
CommonLinkUtility commonLinkUtility,
SettingsManager settingsManager,
DisplayUserSettingsHelper displayUserSettingsHelper,
UserFormatter userFormatter,
NovellLdapUserImporter novellLdapUserImporter,
WorkContext workContext)
{
_logger = logger;
_userManager = userManager;
_tenantManager = tenantManager;
_tenantUtil = tenantUtil;
_securityContext = securityContext;
_commonLinkUtility = commonLinkUtility;
_settingsManager = settingsManager;
_displayUserSettingsHelper = displayUserSettingsHelper;
_userFormatter = userFormatter;
_serviceProvider = serviceProvider;
_novellLdapUserImporter = novellLdapUserImporter;
}
public void Init(LdapLocalization resource = null)
{
_resource = resource ?? new LdapLocalization();
}
private bool TestUniqueUserName(string uniqueName)
{
return !string.IsNullOrEmpty(uniqueName) && Equals(_userManager.GetUserByUserName(uniqueName), Constants.LostUser);
}
private string MakeUniqueName(UserInfo userInfo)
{
if (string.IsNullOrEmpty(userInfo.Email))
{
throw new ArgumentException(_resource.ErrorEmailEmpty, "userInfo");
}
var uniqueName = new MailAddress(userInfo.Email).User;
var startUniqueName = uniqueName;
var i = 0;
while (!TestUniqueUserName(uniqueName))
{
uniqueName = string.Format("{0}{1}", startUniqueName, (++i).ToString(CultureInfo.InvariantCulture));
}
return uniqueName;
}
private bool CheckUniqueEmail(Guid userId, string email)
{
var foundUser = _userManager.GetUserByEmail(email);
return Equals(foundUser, Constants.LostUser) || foundUser.Id == userId;
}
public bool TryAddLDAPUser(UserInfo ldapUserInfo, bool onlyGetChanges, out UserInfo portalUserInfo)
{
portalUserInfo = Constants.LostUser;
try
{
if (ldapUserInfo == null)
{
throw new ArgumentNullException("ldapUserInfo");
}
_logger.DebugTryAddLdapUser(ldapUserInfo.Sid, ldapUserInfo.Email, ldapUserInfo.UserName);
if (!CheckUniqueEmail(ldapUserInfo.Id, ldapUserInfo.Email))
{
_logger.DebugUserAlredyExistsForEmail(ldapUserInfo.Sid, ldapUserInfo.Email);
return false;
}
if (!TryChangeExistingUserName(ldapUserInfo.UserName, onlyGetChanges))
{
_logger.DebugUserAlredyExistsForUserName(ldapUserInfo.Sid, ldapUserInfo.UserName);
return false;
}
var q = _tenantManager.GetTenantQuota(_tenantManager.GetCurrentTenant().Id);
if (q.ActiveUsers <= _userManager.GetUsersByGroup(Constants.GroupUser.ID).Length)
{
_logger.DebugExceedQuota(ldapUserInfo.Sid, ldapUserInfo.UserName);
throw new TenantQuotaException(string.Format("Exceeds the maximum active users ({0})", q.ActiveUsers));
}
if (!ldapUserInfo.WorkFromDate.HasValue)
{
ldapUserInfo.WorkFromDate = _tenantUtil.DateTimeNow();
}
if (onlyGetChanges)
{
portalUserInfo = ldapUserInfo;
return true;
}
_logger.DebugSaveUserInfo(ldapUserInfo.GetUserInfoString());
portalUserInfo = _userManager.SaveUserInfo(ldapUserInfo);
var passwordHash = LdapUtils.GeneratePassword();
_logger.DebugSetUserPassword(portalUserInfo.Id);
_securityContext.SetUserPasswordHash(portalUserInfo.Id, passwordHash);
return true;
}
catch (TenantQuotaException ex)
{
// rethrow if quota
throw ex;
}
catch (Exception ex)
{
if (ldapUserInfo != null)
{
_logger.ErrorTryAddLdapUser(ldapUserInfo.UserName, ldapUserInfo.Sid, ex);
}
}
return false;
}
private bool TryChangeExistingUserName(string ldapUserName, bool onlyGetChanges)
{
try
{
if (string.IsNullOrEmpty(ldapUserName))
{
return false;
}
var otherUser = _userManager.GetUserByUserName(ldapUserName);
if (Equals(otherUser, Constants.LostUser))
{
return true;
}
if (otherUser.IsLDAP())
{
return false;
}
otherUser.UserName = MakeUniqueName(otherUser);
if (onlyGetChanges)
{
return true;
}
_logger.DebugTryChangeExistingUserName();
_logger.DebugSaveUserInfo(otherUser.GetUserInfoString());
_userManager.SaveUserInfo(otherUser);
return true;
}
catch (Exception ex)
{
_logger.ErrorTryChangeOtherUserName(ldapUserName, ex);
}
return false;
}
public UserInfo GetLDAPSyncUserChange(UserInfo ldapUserInfo, List<UserInfo> ldapUsers, out LdapChangeCollection changes)
{
return SyncLDAPUser(ldapUserInfo, ldapUsers, out changes, true);
}
public UserInfo SyncLDAPUser(UserInfo ldapUserInfo, List<UserInfo> ldapUsers = null)
{
LdapChangeCollection changes;
return SyncLDAPUser(ldapUserInfo, ldapUsers, out changes);
}
private UserInfo SyncLDAPUser(UserInfo ldapUserInfo, List<UserInfo> ldapUsers, out LdapChangeCollection changes, bool onlyGetChanges = false)
{
UserInfo result;
changes = new LdapChangeCollection(_userFormatter);
UserInfo userToUpdate;
var userBySid = _userManager.GetUserBySid(ldapUserInfo.Sid);
if (Equals(userBySid, Constants.LostUser))
{
var userByEmail = _userManager.GetUserByEmail(ldapUserInfo.Email);
if (Equals(userByEmail, Constants.LostUser))
{
if (ldapUserInfo.Status != EmployeeStatus.Active)
{
if (onlyGetChanges)
{
changes.SetSkipUserChange(ldapUserInfo);
}
_logger.DebugSyncUserLdapFailedWithStatus(ldapUserInfo.Sid, ldapUserInfo.UserName,
Enum.GetName(typeof(EmployeeStatus), ldapUserInfo.Status));
return Constants.LostUser;
}
if (!TryAddLDAPUser(ldapUserInfo, onlyGetChanges, out result))
{
if (onlyGetChanges)
{
changes.SetSkipUserChange(ldapUserInfo);
}
return Constants.LostUser;
}
if (onlyGetChanges)
{
changes.SetAddUserChange(result, _logger);
}
if (!onlyGetChanges && _settingsManager.Load<LdapSettings>().SendWelcomeEmail &&
(ldapUserInfo.ActivationStatus != EmployeeActivationStatus.AutoGenerated))
{
using var scope = _serviceProvider.CreateScope();
var tenantManager = scope.ServiceProvider.GetRequiredService<TenantManager>();
var ldapNotifyHelper = scope.ServiceProvider.GetRequiredService<LdapNotifyService>();
var source = scope.ServiceProvider.GetRequiredService<LdapNotifySource>();
source.Init(tenantManager.GetCurrentTenant());
var workContext = scope.ServiceProvider.GetRequiredService<WorkContext>();
var notifuEngineQueue = scope.ServiceProvider.GetRequiredService<NotifyEngineQueue>();
var client = workContext.NotifyContext.RegisterClient(notifuEngineQueue, source);
var confirmLink = _commonLinkUtility.GetConfirmationUrl(ldapUserInfo.Email, ConfirmType.EmailActivation);
client.SendNoticeToAsync(
NotifyConstants.ActionLdapActivation,
null,
new[] { new DirectRecipient(ldapUserInfo.Email, null, new[] { ldapUserInfo.Email }, false) },
new[] { ASC.Core.Configuration.Constants.NotifyEMailSenderSysName },
null,
new TagValue(NotifyConstants.TagUserName, ldapUserInfo.DisplayUserName(_displayUserSettingsHelper)),
new TagValue(NotifyConstants.TagUserEmail, ldapUserInfo.Email),
new TagValue(NotifyConstants.TagMyStaffLink, _commonLinkUtility.GetFullAbsolutePath(_commonLinkUtility.GetMyStaff())),
NotifyConstants.TagGreenButton(_resource.NotifyButtonJoin, confirmLink),
new TagValue(NotifyCommonTags.WithoutUnsubscribe, true));
}
return result;
}
if (userByEmail.IsLDAP())
{
if (ldapUsers == null || ldapUsers.Any(u => u.Sid.Equals(userByEmail.Sid)))
{
if (onlyGetChanges)
{
changes.SetSkipUserChange(ldapUserInfo);
}
_logger.DebugSyncUserLdapFailedWithEmail(
ldapUserInfo.Sid, ldapUserInfo.UserName, ldapUserInfo.Email);
return Constants.LostUser;
}
}
userToUpdate = userByEmail;
}
else
{
userToUpdate = userBySid;
}
UpdateLdapUserContacts(ldapUserInfo, userToUpdate.ContactsList);
if (!NeedUpdateUser(userToUpdate, ldapUserInfo))
{
_logger.DebugSyncUserLdapSkipping(ldapUserInfo.Sid, ldapUserInfo.UserName);
if (onlyGetChanges)
{
changes.SetNoneUserChange(ldapUserInfo);
}
return userBySid;
}
_logger.DebugSyncUserLdapUpdaiting(ldapUserInfo.Sid, ldapUserInfo.UserName);
if (!TryUpdateUserWithLDAPInfo(userToUpdate, ldapUserInfo, onlyGetChanges, out result))
{
if (onlyGetChanges)
{
changes.SetSkipUserChange(ldapUserInfo);
}
return Constants.LostUser;
}
if (onlyGetChanges)
{
changes.SetUpdateUserChange(ldapUserInfo, result, _logger);
}
return result;
}
private const string EXT_MOB_PHONE = "extmobphone";
private const string EXT_MAIL = "extmail";
private const string EXT_PHONE = "extphone";
private const string EXT_SKYPE = "extskype";
private static void UpdateLdapUserContacts(UserInfo ldapUser, List<string> portalUserContacts)
{
if (portalUserContacts == null || !portalUserContacts.Any())
{
return;
}
var ldapUserContacts = ldapUser.Contacts;
var newContacts = new List<string>(ldapUser.ContactsList);
for (int i = 0; i < portalUserContacts.Count; i += 2)
{
if (portalUserContacts[i] == EXT_MOB_PHONE || portalUserContacts[i] == EXT_MAIL
|| portalUserContacts[i] == EXT_PHONE || portalUserContacts[i] == EXT_SKYPE)
{
continue;
}
if (i + 1 >= portalUserContacts.Count)
{
continue;
}
newContacts.Add(portalUserContacts[i]);
newContacts.Add(portalUserContacts[i + 1]);
}
ldapUser.ContactsList = newContacts;
}
private bool NeedUpdateUser(UserInfo portalUser, UserInfo ldapUser)
{
var needUpdate = false;
try
{
var settings = _settingsManager.Load<LdapSettings>();
Func<string, string, bool> notEqual =
(f1, f2) =>
f1 == null && f2 != null ||
f1 != null && !f1.Equals(f2, StringComparison.InvariantCultureIgnoreCase);
if (notEqual(portalUser.FirstName, ldapUser.FirstName))
{
_logger.DebugNeedUpdateUserByFirstName(portalUser.FirstName ?? "NULL",
ldapUser.FirstName ?? "NULL");
needUpdate = true;
}
if (notEqual(portalUser.LastName, ldapUser.LastName))
{
_logger.DebugNeedUpdateUserByLastName(portalUser.LastName ?? "NULL",
ldapUser.LastName ?? "NULL");
needUpdate = true;
}
if (notEqual(portalUser.UserName, ldapUser.UserName))
{
_logger.DebugNeedUpdateUserByUserName(portalUser.UserName ?? "NULL",
ldapUser.UserName ?? "NULL");
needUpdate = true;
}
if (notEqual(portalUser.Email, ldapUser.Email) &&
(ldapUser.ActivationStatus != EmployeeActivationStatus.AutoGenerated
|| ldapUser.ActivationStatus == EmployeeActivationStatus.AutoGenerated && portalUser.ActivationStatus == EmployeeActivationStatus.AutoGenerated))
{
_logger.DebugNeedUpdateUserByEmail(portalUser.Email ?? "NULL",
ldapUser.Email ?? "NULL");
needUpdate = true;
}
if (notEqual(portalUser.Sid, ldapUser.Sid))
{
_logger.DebugNeedUpdateUserBySid(portalUser.Sid ?? "NULL",
ldapUser.Sid ?? "NULL");
needUpdate = true;
}
if (settings.LdapMapping.ContainsKey(Mapping.TitleAttribute) && notEqual(portalUser.Title, ldapUser.Title))
{
_logger.DebugNeedUpdateUserByTitle(portalUser.Title ?? "NULL",
ldapUser.Title ?? "NULL");
needUpdate = true;
}
if (settings.LdapMapping.ContainsKey(Mapping.LocationAttribute) && notEqual(portalUser.Location, ldapUser.Location))
{
_logger.DebugNeedUpdateUserByLocation(portalUser.Location ?? "NULL",
ldapUser.Location ?? "NULL");
needUpdate = true;
}
if (portalUser.ActivationStatus != ldapUser.ActivationStatus &&
(!portalUser.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated) || portalUser.Email != ldapUser.Email) &&
ldapUser.ActivationStatus != EmployeeActivationStatus.AutoGenerated)
{
_logger.DebugNeedUpdateUserByActivationStatus(portalUser.ActivationStatus,
ldapUser.ActivationStatus);
needUpdate = true;
}
if (portalUser.Status != ldapUser.Status)
{
_logger.DebugNeedUpdateUserByStatus(portalUser.Status,
ldapUser.Status);
needUpdate = true;
}
if (portalUser.ContactsList == null && ldapUser.ContactsList.Count != 0 || portalUser.ContactsList != null && (ldapUser.ContactsList.Count != portalUser.ContactsList.Count ||
!ldapUser.Contacts.All(portalUser.Contacts.Contains)))
{
_logger.DebugNeedUpdateUserByContacts(string.Join("|", portalUser.Contacts),
string.Join("|", ldapUser.Contacts));
needUpdate = true;
}
if (settings.LdapMapping.ContainsKey(Mapping.MobilePhoneAttribute) && notEqual(portalUser.MobilePhone, ldapUser.MobilePhone))
{
_logger.DebugNeedUpdateUserByPrimaryPhone(portalUser.MobilePhone ?? "NULL",
ldapUser.MobilePhone ?? "NULL");
needUpdate = true;
}
if (settings.LdapMapping.ContainsKey(Mapping.BirthDayAttribute) && portalUser.BirthDate == null && ldapUser.BirthDate != null || portalUser.BirthDate != null && !portalUser.BirthDate.Equals(ldapUser.BirthDate))
{
_logger.DebugNeedUpdateUserByBirthDate(portalUser.BirthDate.ToString() ?? "NULL",
ldapUser.BirthDate.ToString() ?? "NULL");
needUpdate = true;
}
if (settings.LdapMapping.ContainsKey(Mapping.GenderAttribute) && portalUser.Sex == null && ldapUser.Sex != null || portalUser.Sex != null && !portalUser.Sex.Equals(ldapUser.Sex))
{
_logger.DebugNeedUpdateUserBySex(portalUser.Sex.ToString() ?? "NULL",
ldapUser.Sex.ToString() ?? "NULL");
needUpdate = true;
}
}
catch (Exception ex)
{
_logger.DebugNeedUpdateUser(ex);
}
return needUpdate;
}
private bool TryUpdateUserWithLDAPInfo(UserInfo userToUpdate, UserInfo updateInfo, bool onlyGetChanges, out UserInfo portlaUserInfo)
{
portlaUserInfo = Constants.LostUser;
try
{
_logger.DebugTryUpdateUserWithLdapInfo();
var settings = _settingsManager.Load<LdapSettings>();
if (!userToUpdate.UserName.Equals(updateInfo.UserName, StringComparison.InvariantCultureIgnoreCase)
&& !TryChangeExistingUserName(updateInfo.UserName, onlyGetChanges))
{
_logger.DebugUpdateUserUserNameAlredyExists(userToUpdate.Id, userToUpdate.UserName, updateInfo.UserName);
return false;
}
if (!userToUpdate.Email.Equals(updateInfo.Email, StringComparison.InvariantCultureIgnoreCase)
&& !CheckUniqueEmail(userToUpdate.Id, updateInfo.Email))
{
_logger.DebugUpdateUserEmailAlreadyExists(userToUpdate.Id, userToUpdate.Email, updateInfo.Email);
return false;
}
if (userToUpdate.Email != updateInfo.Email && !(updateInfo.ActivationStatus == EmployeeActivationStatus.AutoGenerated &&
userToUpdate.ActivationStatus == (EmployeeActivationStatus.AutoGenerated | EmployeeActivationStatus.Activated)))
{
userToUpdate.ActivationStatus = updateInfo.ActivationStatus;
userToUpdate.Email = updateInfo.Email;
}
userToUpdate.UserName = updateInfo.UserName;
userToUpdate.FirstName = updateInfo.FirstName;
userToUpdate.LastName = updateInfo.LastName;
userToUpdate.Sid = updateInfo.Sid;
userToUpdate.Contacts = updateInfo.Contacts;
if (settings.LdapMapping.ContainsKey(Mapping.TitleAttribute))
{
userToUpdate.Title = updateInfo.Title;
}
if (settings.LdapMapping.ContainsKey(Mapping.LocationAttribute))
{
userToUpdate.Location = updateInfo.Location;
}
if (settings.LdapMapping.ContainsKey(Mapping.GenderAttribute))
{
userToUpdate.Sex = updateInfo.Sex;
}
if (settings.LdapMapping.ContainsKey(Mapping.BirthDayAttribute))
{
userToUpdate.BirthDate = updateInfo.BirthDate;
}
if (settings.LdapMapping.ContainsKey(Mapping.MobilePhoneAttribute))
{
userToUpdate.MobilePhone = updateInfo.MobilePhone;
}
if (!userToUpdate.IsOwner(_tenantManager.GetCurrentTenant())) // Owner must never be terminated by LDAP!
{
userToUpdate.Status = updateInfo.Status;
}
if (!onlyGetChanges)
{
_logger.DebugSaveUserInfo(userToUpdate.GetUserInfoString());
portlaUserInfo = _userManager.SaveUserInfo(userToUpdate);
}
return true;
}
catch (Exception ex)
{
_logger.ErrorUpdateUserWithLDAPInfo(userToUpdate.Id, userToUpdate.UserName,
userToUpdate.Sid, ex);
}
return false;
}
public bool TryGetAndSyncLdapUserInfo(string login, string password, out UserInfo userInfo)
{
userInfo = Constants.LostUser;
try
{
var settings = _settingsManager.Load<LdapSettings>();
if (!settings.EnableLdapAuthentication)
{
return false;
}
_logger.DebugTryGetAndSyncLdapUserInfo(login);
_novellLdapUserImporter.Init(settings, _resource);
var ldapUserInfo = _novellLdapUserImporter.Login(login, password);
if (ldapUserInfo == null || ldapUserInfo.Item1.Equals(Constants.LostUser))
{
_logger.DebugNovellLdapUserImporterLoginFailed(login);
return false;
}
var portalUser = _userManager.GetUserBySid(ldapUserInfo.Item1.Sid);
if (portalUser.Status == EmployeeStatus.Terminated || portalUser.Equals(Constants.LostUser))
{
if (!ldapUserInfo.Item2.IsDisabled)
{
_logger.DebugTryCheckAndSyncToLdapUser(ldapUserInfo.Item1.UserName, ldapUserInfo.Item1.Email, ldapUserInfo.Item2.DistinguishedName);
if (!TryCheckAndSyncToLdapUser(ldapUserInfo, _novellLdapUserImporter, out userInfo))
{
_logger.DebugTryCheckAndSyncToLdapUserFailed();
return false;
}
}
else
{
return false;
}
}
else
{
_logger.DebugTryCheckAndSyncToLdapUser(ldapUserInfo.Item1.UserName, ldapUserInfo.Item1.Email, ldapUserInfo.Item2.DistinguishedName);
var tenant = _tenantManager.GetCurrentTenant();
new Task(() =>
{
using var scope = _serviceProvider.CreateScope();
var tenantManager = scope.ServiceProvider.GetRequiredService<TenantManager>();
var securityContext = scope.ServiceProvider.GetRequiredService<SecurityContext>();
var novellLdapUserImporter = scope.ServiceProvider.GetRequiredService<NovellLdapUserImporter>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager>();
var cookiesManager = scope.ServiceProvider.GetRequiredService<CookiesManager>();
var log = scope.ServiceProvider.GetRequiredService<ILogger<LdapUserManager>>();
tenantManager.SetCurrentTenant(tenant);
securityContext.AuthenticateMe(Core.Configuration.Constants.CoreSystem);
var uInfo = SyncLDAPUser(ldapUserInfo.Item1);
var newLdapUserInfo = new Tuple<UserInfo, LdapObject>(uInfo, ldapUserInfo.Item2);
if (novellLdapUserImporter.Settings.GroupMembership)
{
if (!novellLdapUserImporter.TrySyncUserGroupMembership(newLdapUserInfo))
{
log.DebugTryGetAndSyncLdapUserInfoDisablingUser(login, uInfo);
uInfo.Status = EmployeeStatus.Terminated;
uInfo.Sid = null;
userManager.SaveUserInfo(uInfo);
cookiesManager.ResetUserCookie(uInfo.Id);
}
}
}).Start();
if (ldapUserInfo.Item2.IsDisabled)
{
_logger.DebugTryGetAndSyncLdapUserInfo(login);
return false;
}
else
{
userInfo = portalUser;
}
}
return true;
}
catch (Exception ex)
{
_logger.ErrorTryGetLdapUserInfoFailed(login, ex);
userInfo = Constants.LostUser;
return false;
}
}
private bool TryCheckAndSyncToLdapUser(Tuple<UserInfo, LdapObject> ldapUserInfo, LdapUserImporter importer,
out UserInfo userInfo)
{
try
{
_securityContext.AuthenticateMe(Core.Configuration.Constants.CoreSystem);
userInfo = SyncLDAPUser(ldapUserInfo.Item1);
if (userInfo == null || userInfo.Equals(Constants.LostUser))
{
throw new Exception("The user did not pass the configuration check by ldap user settings");
}
var newLdapUserInfo = new Tuple<UserInfo, LdapObject>(userInfo, ldapUserInfo.Item2);
if (!importer.Settings.GroupMembership)
{
return true;
}
if (!importer.TrySyncUserGroupMembership(newLdapUserInfo))
{
userInfo.Sid = null;
userInfo.Status = EmployeeStatus.Terminated;
_userManager.SaveUserInfo(userInfo);
throw new Exception("The user did not pass the configuration check by ldap group settings");
}
return true;
}
catch (Exception ex)
{
_logger.ErrorTrySyncLdapUser(ldapUserInfo.Item1.Sid,
ldapUserInfo.Item1.Email, ex);
}
finally
{
_securityContext.Logout();
}
userInfo = Constants.LostUser;
return false;
}
}

View File

@ -0,0 +1,220 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Action = System.Action;
using Constants = ASC.Core.Users.Constants;
namespace ASC.ActiveDirectory;
public static class LdapUtils
{
private static readonly Regex _dcRegex = new Regex("dc=([^,]+)", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
public static string DistinguishedNameToDomain(string distinguishedName)
{
if (string.IsNullOrEmpty(distinguishedName))
{
return null;
}
var matchList = _dcRegex.Matches(distinguishedName);
var dcList = matchList.Cast<Match>().Select(match => match.Groups[1].Value).ToList();
return !dcList.Any() ? null : string.Join(".", dcList);
}
public static bool IsLoginAccepted(LdapLogin ldapLogin, UserInfo ldapUser, string ldapDomain)
{
if (ldapLogin == null
|| string.IsNullOrEmpty(ldapLogin.ToString())
|| string.IsNullOrEmpty(ldapDomain)
|| ldapUser == null
|| ldapUser.Equals(Constants.LostUser)
|| string.IsNullOrEmpty(ldapUser.Email)
|| string.IsNullOrEmpty(ldapUser.UserName))
{
return false;
}
var hasDomain = !string.IsNullOrEmpty(ldapLogin.Domain);
if (!hasDomain)
{
return ldapLogin.Username.Equals(ldapUser.UserName, StringComparison.InvariantCultureIgnoreCase);
}
var fullLogin = ldapLogin.ToString();
if (fullLogin.Equals(ldapUser.Email, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
if (!ldapDomain.StartsWith(ldapLogin.Domain))
{
return false;
}
var alterEmail = ldapUser.UserName.Contains("@")
? ldapUser.UserName
: string.Format("{0}@{1}", ldapUser.UserName, ldapDomain);
return IsLoginAndEmailSuitable(fullLogin, alterEmail);
}
private static string GetLdapAccessableEmail(string email)
{
try
{
if (string.IsNullOrEmpty(email))
{
return null;
}
var login = LdapLogin.ParseLogin(email);
if (string.IsNullOrEmpty(login.Domain))
{
return email;
}
var dotIndex = login.Domain.LastIndexOf(".", StringComparison.Ordinal);
var accessableEmail = dotIndex > -1 ? string.Format("{0}@{1}", login.Username, login.Domain.Remove(dotIndex)) : email;
return accessableEmail;
}
catch (Exception)
{
return null;
}
}
private static bool IsLoginAndEmailSuitable(string login, string email)
{
try
{
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(email))
{
return false;
}
var accessableLogin = GetLdapAccessableEmail(login);
if (string.IsNullOrEmpty(accessableLogin))
{
return false;
}
var accessableEmail = GetLdapAccessableEmail(email);
if (string.IsNullOrEmpty(accessableEmail))
{
return false;
}
return accessableLogin.Equals(accessableEmail, StringComparison.InvariantCultureIgnoreCase);
}
catch (Exception)
{
return false;
}
}
public static string GeneratePassword()
{
return Guid.NewGuid().ToString();
}
public static void SkipErrors(Action method, ILogger log = null)
{
try
{
method();
}
catch (Exception ex)
{
if (log != null)
{
log.ErrorSkipErrors(ex);
}
}
}
public static string GetContactsString(this UserInfo userInfo)
{
if (userInfo.ContactsList == null || userInfo.ContactsList.Count == 0)
{
return null;
}
var sBuilder = new StringBuilder();
foreach (var contact in userInfo.Contacts)
{
sBuilder.AppendFormat("{0}|", contact);
}
return sBuilder.ToString();
}
public static string GetUserInfoString(this UserInfo userInfo)
{
return string.Format(
"{{ ID: '{0}' SID: '{1}' Email '{2}' UserName: '{3}' FirstName: '{4}' LastName: '{5}' Title: '{6}' Location: '{7}' Contacts: '{8}' Status: '{9}' }}",
userInfo.Id,
userInfo.Sid,
userInfo.Email,
userInfo.UserName,
userInfo.FirstName,
userInfo.LastName,
userInfo.Title,
userInfo.Location,
userInfo.GetContactsString(),
Enum.GetName(typeof(EmployeeStatus), userInfo.Status));
}
public static string UnescapeLdapString(string ldapString)
{
var sb = new StringBuilder();
for (var i = 0; i < ldapString.Length; i++)
{
var ch = ldapString[i];
if (ch == '\\')
{
if (i + 1 < ldapString.Length && ldapString[i + 1] == ch)
{
sb.Append(ch);
i++;
}
}
else
{
sb.Append(ch);
}
}
return sb.ToString();
}
}

View File

@ -0,0 +1,39 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapCertificateConfirmRequestLogger
{
[LoggerMessage(Level = LogLevel.Warning, Message = "GetLdapCertProblems: {SslPolicyErrors}")]
public static partial void WarnGetLdapCertProblems(this ILogger logger, string SslPolicyErrors);
[LoggerMessage(Level = LogLevel.Error, Message = "GetLdapCertProblems() failed")]
public static partial void ErrorGetLdapCertProblems(this ILogger logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "LdapCertificateConfirmRequest.FromCert() failed")]
public static partial void ErrorLdapCertificateConfirmRequest(this ILogger logger, Exception exception);
}

View File

@ -0,0 +1,33 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapChangeCollectionLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "GetPropChange({propName})")]
public static partial void ErrorCanNotGetSidProperty(this ILogger logger, string propName, Exception exception);
}

View File

@ -0,0 +1,51 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapHelperLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "UserExistsInGroup() failed")]
public static partial void ErrorUserExistsInGroupFailed(this ILogger<LdapHelper> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Warning, Message = "NovellLdapHelper->SearchDomain() failed")]
public static partial void WarnSearchDomainFailed(this ILogger<LdapHelper> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "NovellLdapHelper->CheckUserDn(userDn: {userDn}) Wrong User DN parameter")]
public static partial void ErrorWrongUserDnParameter(this ILogger<LdapHelper> logger, string userDn);
[LoggerMessage(Level = LogLevel.Error, Message = "NovellLdapHelper->CheckGroupDn(groupDn: {groupDn}): Wrong Group DN parameter")]
public static partial void ErrorWrongGroupDnParameter(this ILogger<LdapHelper> logger, string groupDn);
[LoggerMessage(Level = LogLevel.Error, Message = "NovellLdapHelper->GetUsers(filter: '{filter}' limit: {limit}) failed")]
public static partial void ErrorGetUsersFailed(this ILogger<LdapHelper> logger, string filter, int limit, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "NovellLdapHelper->GetUserBySid(sid: '{sid}') failed")]
public static partial void ErrorGetUserBySidFailed(this ILogger<LdapHelper> logger, string sid, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "NovellLdapHelper->GetGroups(criteria: '{criteria}') failed")]
public static partial void ErrorGetGroupsFailed(this ILogger<LdapHelper> logger, Criteria criteria, Exception exception);
}

View File

@ -0,0 +1,37 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapObjectExtensionLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "Can't get attribute from ldap object (attr = {attribute}, dn = {dn})")]
public static partial void ErrorCanNotGetAttribute(this ILogger<LdapObjectExtension> logger, string attribute, string dn,Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Can't get attributes from ldap object (attr = {attribute}, dn = {dn})")]
public static partial void ErrorCanNotGetAttributes(this ILogger<LdapObjectExtension> logger, string attribute, string dn, Exception exception);
}

View File

@ -0,0 +1,160 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapOperationJobLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "Can't save default LDAP settings.")]
public static partial void ErrorSaveDefaultLdapSettings(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Information, Message = "Start '{operationtype}' operation")]
public static partial void InfoStartOperation(this ILogger<LdapOperationJob> logger, string operationtype);
[LoggerMessage(Level = LogLevel.Debug, Message = "PrepareSettings()")]
public static partial void DebugPrepareSettings(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "PrepareSettings() Error: {error}")]
public static partial void DebugPrepareSettingsError(this ILogger<LdapOperationJob> logger, string error);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapSettingsChecker.CheckSettings() Error: {error}")]
public static partial void DebugCheckSettingsError(this ILogger<LdapOperationJob> logger, string error);
[LoggerMessage(Level = LogLevel.Error, Message = "{error}")]
public static partial void ErrorAuthorizing(this ILogger<LdapOperationJob> logger, string error, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "TenantQuotaException")]
public static partial void ErrorTenantQuota(this ILogger<LdapOperationJob> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "FormatException")]
public static partial void ErrorFormatException(this ILogger<LdapOperationJob> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Internal server error")]
public static partial void ErrorInternal(this ILogger<LdapOperationJob> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "LdapOperation finalization problem")]
public static partial void ErrorLdapOperationFinalizationlProblem(this ILogger<LdapOperationJob> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Can't save LDAP settings.")]
public static partial void ErrorSaveLdapSettings(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "{setting}")]
public static partial void DebugLdapSettings(this ILogger<LdapOperationJob> logger, string setting);
[LoggerMessage(Level = LogLevel.Debug, Message = "TurnOffLDAP()")]
public static partial void DebugTurnOffLDAP(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(acceptCertificate={acceptCertificate}, cert thumbprint: {acceptCertificatehash})")]
public static partial void ErrorCheckSettings(this ILogger<LdapOperationJob> logger, bool acceptCertificate, string acceptCertificatehash, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "CoreContext.UserManager.SaveUserInfo({userInfo})")]
public static partial void DebugSaveUserInfo(this ILogger<LdapOperationJob> logger, string userInfo);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncLDAPUsers()")]
public static partial void DebugSyncLDAPUsers(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncLDAPUsersInGroups()")]
public static partial void DebugSyncLDAPUsersInGroups(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Information, Message = "SyncLdapAvatar() Removing photo for '{guid}'")]
public static partial void InfoSyncLdapAvatarsRemovingPhoto(this ILogger<LdapOperationJob> logger, Guid guid);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncLdapAvatar() Found photo for '{sid}'")]
public static partial void DebugSyncLdapAvatarsFoundPhoto(this ILogger<LdapOperationJob> logger, string sid);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncLdapAvatar() Same hash, skipping.")]
public static partial void DebugSyncLdapAvatarsSkipping(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncLdapAvatar() Couldn't save photo for '{guid}'")]
public static partial void DebugSyncLdapAvatarsCouldNotSavePhoto(this ILogger<LdapOperationJob> logger, Guid guid);
[LoggerMessage(Level = LogLevel.Debug, Message = "TakeUsersRights() CurrentAccessRights is empty, skipping")]
public static partial void DebugAccessRightsIsEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "TakeUsersRights() Attempting to take admin rights from yourself `{user}`, skipping")]
public static partial void DebugAttemptingTakeAdminRights(this ILogger<LdapOperationJob> logger, string user);
[LoggerMessage(Level = LogLevel.Debug, Message = "TakeUsersRights() Taking admin rights ({accessRight}) from '{user}'")]
public static partial void DebugTakingAdminRights(this ILogger<LdapOperationJob> logger, LdapSettings.AccessRight accessRight, string user);
[LoggerMessage(Level = LogLevel.Debug, Message = "GiveUsersRights() No ldap groups found for ({accessRight}) access rights, skipping")]
public static partial void DebugGiveUsersRightsNoLdapGroups(this ILogger<LdapOperationJob> logger, LdapSettings.AccessRight accessRight);
[LoggerMessage(Level = LogLevel.Debug, Message = "GiveUsersRights() Couldn't find portal group for '{sid}'")]
public static partial void DebugGiveUsersRightsCouldNotFindPortalGroup(this ILogger<LdapOperationJob> logger, string sid);
[LoggerMessage(Level = LogLevel.Debug, Message = "GiveUsersRights() Found '{countUsers}' users for group '{groupName}' ({groupId})")]
public static partial void DebugGiveUsersRightsFoundUsersForGroup(this ILogger<LdapOperationJob> logger, int countUsers,string groupName, Guid groupId);
[LoggerMessage(Level = LogLevel.Debug, Message = "GiveUsersRights() Cleared manually added user rights for '{userName}'")]
public static partial void DebugGiveUsersRightsClearedAndAddedRights(this ILogger<LdapOperationJob> logger, string userName);
[LoggerMessage(Level = LogLevel.Debug, Message = "Importer.GetDiscoveredUsersByAttributes() Success: Users count: {countUsers}")]
public static partial void DebugGetDiscoveredUsersByAttributes(this ILogger<LdapOperationJob> logger, int countUsers);
[LoggerMessage(Level = LogLevel.Debug, Message = "Importer.GetDiscoveredGroupsByAttributes() Success: Groups count: {countGroups}")]
public static partial void DebugGetDiscoveredGroupsByAttributes(this ILogger<LdapOperationJob> logger, int countGroups);
[LoggerMessage(Level = LogLevel.Debug, Message = "GetGroupsUsers() Success: Users count: {countUsers}")]
public static partial void DebugGetGroupsUsers(this ILogger<LdapOperationJob> logger, int countUsers);
[LoggerMessage(Level = LogLevel.Debug, Message = "RemoveOldDbUsers() Attempting to exclude yourself `{id}` from group or user filters, skipping.")]
public static partial void DebugRemoveOldDbUsersAttemptingExcludeYourself(this ILogger<LdapOperationJob> logger, Guid id);
[LoggerMessage(Level = LogLevel.Information, Message = "Progress: {percentage}% {status} {source}")]
public static partial void InfoProgress(this ILogger<LdapOperationJob> logger,double percentage, string status, string source);
[LoggerMessage(Level = LogLevel.Error, Message = "Wrong LDAP settings were received from client.")]
public static partial void ErrorWrongLdapSettings(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.Server is null or empty.")]
public static partial void ErrorServerIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.UserDN is null or empty.")]
public static partial void ErrorUserDnIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.LoginAttribute is null or empty.")]
public static partial void ErrorLoginAttributeIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.GroupDN is null or empty.")]
public static partial void ErrorGroupDnIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.GroupAttribute is null or empty.")]
public static partial void ErrorGroupAttributeIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.UserAttribute is null or empty.")]
public static partial void ErrorUserAttributeIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.Login is null or empty.")]
public static partial void ErrorloginIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.PasswordBytes is null.")]
public static partial void ErrorPasswordBytesIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "settings.Password is null or empty.")]
public static partial void ErrorPasswordIsNullOrEmpty(this ILogger<LdapOperationJob> logger);
}

View File

@ -0,0 +1,57 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapSettingsCheckerLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(acceptCertificate={acceptCertificate}): NovellLdapTlsCertificateRequestedException")]
public static partial void ErrorNovellLdapTlsCertificateRequestedException(this ILogger<LdapSettingsChecker> logger, bool acceptCertificate, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(): NotSupportedException")]
public static partial void ErrorNotSupportedException(this ILogger<LdapSettingsChecker> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(): SocketException")]
public static partial void ErrorSocketException(this ILogger<LdapSettingsChecker> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(): ArgumentException")]
public static partial void ErrorArgumentException(this ILogger<LdapSettingsChecker> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(): SecurityException")]
public static partial void ErrorSecurityException(this ILogger<LdapSettingsChecker> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(): SystemException")]
public static partial void ErrorSystemException(this ILogger<LdapSettingsChecker> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "CheckSettings(): Exception")]
public static partial void ErrorCheckSettingsException(this ILogger<LdapSettingsChecker> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Wrong User DN parameter: {userDn}")]
public static partial void ErrorWrongUserDn(this ILogger<LdapSettingsChecker> logger, string userDn, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Wrong Group DN parameter: {groupDn}")]
public static partial void ErrorWrongGroupDn(this ILogger<LdapSettingsChecker> logger, string groupDn, Exception exception);
}

View File

@ -0,0 +1,108 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapUserImporterLogger
{
[LoggerMessage(Level = LogLevel.Debug, Message = "LdapUserImporter.GetGroupUsers(Group name: {groupName})")]
public static partial void DebugGetGroupUsers(this ILogger<LdapUserImporter> logger, string groupName);
[LoggerMessage(Level = LogLevel.Debug, Message = "Found nested LDAP Group: {groupName}")]
public static partial void DebugFoundNestedLdapGroup(this ILogger<LdapUserImporter> logger, string groupName);
[LoggerMessage(Level = LogLevel.Debug, Message = "Skip already watched nested LDAP Group: {groupName}")]
public static partial void DebugSkipAlreadyWatched(this ILogger<LdapUserImporter> logger, string groupName);
[LoggerMessage(Level = LogLevel.Error, Message = "IsUserExistInGroups(login: '{login}' sid: '{sid}')")]
public static partial void ErrorIsUserExistInGroups(this ILogger<LdapUserImporter> logger, string login, string sid, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "GetAndCheckCurrentGroups(login: '{login}' sid: '{sid}')")]
public static partial void ErrorGetAndCheckCurrentGroups(this ILogger<LdapUserImporter> logger, string login, string sid, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "TrySyncUserGroupMembership(groupname: '{groupName}' sid: '{sid}') no portal group found, creating")]
public static partial void DebugTrySyncUserGroupMembershipCreatingPortalGroup(this ILogger<LdapUserImporter> logger, string groupName, string sid);
[LoggerMessage(Level = LogLevel.Debug, Message = "TrySyncUserGroupMembership(username: '{userName}' sid: '{userSid}') adding user to group (groupname: '{groupName}' sid: '{groupSid}')")]
public static partial void DebugTrySyncUserGroupMembershipAddingUserToGroup(this ILogger<LdapUserImporter> logger, string userName, string userSid, string groupName, string groupSid);
[LoggerMessage(Level = LogLevel.Debug, Message = "TrySyncUserGroupMembership(username: '{userName}' sid: '{userSid}') removing user from group (groupname: '{groupName}' sid: '{groupSid}')")]
public static partial void DebugTrySyncUserGroupMembershipRemovingUserFromGroup(this ILogger<LdapUserImporter> logger, string userName, string userSid, string groupName, string groupSid);
[LoggerMessage(Level = LogLevel.Error, Message = "TryLoadLDAPUsers(): Incorrect filter. userFilter = {userFilter}")]
public static partial void ErrorTryLoadLDAPUsersIncorrectUserFilter(this ILogger<LdapUserImporter> logger, string userFilter);
[LoggerMessage(Level = LogLevel.Error, Message = "TryLoadLDAPGroups(): Incorrect group filter. groupFilter = {groupFilter}")]
public static partial void ErrorTryLoadLDAPUsersIncorrectGroupFilter(this ILogger<LdapUserImporter> logger, string groupFilter);
[LoggerMessage(Level = LogLevel.Error, Message = "LoadLDAPDomain(): Error")]
public static partial void ErrorLoadLDAPDomain(this ILogger<LdapUserImporter> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "Login Attribute parameter ({loginAttributeParametr}) not found: DN = {distinguishedName}")]
public static partial void DebugLoginAttributeParameterNotFound(this ILogger<LdapUserImporter> logger, string loginAttributeParametr, string distinguishedName);
[LoggerMessage(Level = LogLevel.Error, Message = "Login Attribute parameter ({loginAttributeParametr}) not found: loginAttribute = {loginAttribute}")]
public static partial void ErrorLoginAttributeParameterNotFound(this ILogger<LdapUserImporter> logger, string loginAttributeParametr, string loginAttribute, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "User Attribute parameter ({userAttributeParametr}) not found: DN = {distinguishedName}")]
public static partial void DebugUserAttributeParameterNotFound(this ILogger<LdapUserImporter> logger, string userAttributeParametr, string distinguishedName);
[LoggerMessage(Level = LogLevel.Error, Message = "User Attribute parameter ({userAttributeParametr}) not found: userAttr = {userAttribute}")]
public static partial void ErrorUserAttributeParameterNotFound(this ILogger<LdapUserImporter> logger, string userAttributeParametr, string userAttribute, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Group Attribute parameter ({groupAttributeParametr}) not found: {groupAttribute}")]
public static partial void ErrorGroupAttributeParameterNotFound(this ILogger<LdapUserImporter> logger, string groupAttributeParametr, string groupAttribute, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "Group Name Attribute parameter ({groupNameAttributeParametr}) not found: {groupAttribute}")]
public static partial void DebugGroupNameAttributeParameterNotFound(this ILogger<LdapUserImporter> logger, string groupNameAttributeParametr, string groupAttribute);
[LoggerMessage(Level = LogLevel.Debug, Message = "LdapUserImporter.FindUsersByPrimaryGroup()")]
public static partial void DebugFindUsersByPrimaryGroup(this ILogger<LdapUserImporter> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "LdapUserImporter.FindUserByMember(user attr: {userAttribute})")]
public static partial void DebugFindUserByMember(this ILogger<LdapUserImporter> logger, string userAttribute);
[LoggerMessage(Level = LogLevel.Debug, Message = "LdapUserImporter.FindGroupByMember(member: {member})")]
public static partial void DebugFindGroupByMember(this ILogger<LdapUserImporter> logger, string member);
[LoggerMessage(Level = LogLevel.Error, Message = "FindLdapUser->ToUserInfo() failed")]
public static partial void ErrorToUserInfo(this ILogger<LdapUserImporter> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Warning, Message = "LDAP: DN: '{distinguishedName}' Login Attribute '{loginAttribute}' is empty")]
public static partial void WarnLoginAttributeIsEmpty(this ILogger<LdapUserImporter> logger, string distinguishedName, string loginAttribute);
[LoggerMessage(Level = LogLevel.Debug, Message = "FindLdapUsers(login '{login}') found: {usersCount} users")]
public static partial void DebugFindLdapUsers(this ILogger<LdapUserImporter> logger, string login, int usersCount);
[LoggerMessage(Level = LogLevel.Debug, Message = "LdapUserImporter->Login(login: '{login}', dn: '{sid}') failed. Error: missing DN or SID")]
public static partial void DebugLdapUserImporterFailed(this ILogger<LdapUserImporter> logger, string login, string sid);
[LoggerMessage(Level = LogLevel.Debug, Message = "LdapUserImporter.Login('{login}')")]
public static partial void DebugLdapUserImporterLogin(this ILogger<LdapUserImporter> logger, string login);
[LoggerMessage(Level = LogLevel.Error, Message = "LdapUserImporter->Login(login: '{login}') failed")]
public static partial void ErrorLdapUserImporterLoginFailed(this ILogger<LdapUserImporter> logger, string login, Exception exception);
}

View File

@ -0,0 +1,146 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapUserManagerLogger
{
[LoggerMessage(Level = LogLevel.Debug, Message = "TryAddLDAPUser(SID: {sid}): Email '{email}' UserName: {userName}")]
public static partial void DebugTryAddLdapUser(this ILogger<LdapUserManager> logger, string sid, string email, string userName);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryAddLDAPUser(SID: {sid}): Email '{email}' already exists.")]
public static partial void DebugUserAlredyExistsForEmail(this ILogger<LdapUserManager> logger, string sid, string email);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryAddLDAPUser(SID: {sid}): Username '{userName}' already exists.")]
public static partial void DebugUserAlredyExistsForUserName(this ILogger<LdapUserManager> logger, string sid, string userName);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryAddLDAPUser(SID: {sid}): Username '{userName}' adding this user would exceed quota.")]
public static partial void DebugExceedQuota(this ILogger<LdapUserManager> logger, string sid, string userName);
[LoggerMessage(Level = LogLevel.Debug, Message = "CoreContext.UserManager.SaveUserInfo({userInfo})")]
public static partial void DebugSaveUserInfo(this ILogger<LdapUserManager> logger, string userInfo);
[LoggerMessage(Level = LogLevel.Debug, Message = "SecurityContext.SetUserPassword(ID:{id})")]
public static partial void DebugSetUserPassword(this ILogger<LdapUserManager> logger, Guid id);
[LoggerMessage(Level = LogLevel.Error, Message = "TryAddLDAPUser(UserName='{userName}' Sid='{sid}')")]
public static partial void ErrorTryAddLdapUser(this ILogger<LdapUserManager> logger, string userName, string sid, Exception ex);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryChangeExistingUserName()")]
public static partial void DebugTryChangeExistingUserName(this ILogger<LdapUserManager> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "TryChangeOtherUserName({userName})")]
public static partial void ErrorTryChangeOtherUserName(this ILogger<LdapUserManager> logger, string userName, Exception ex);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncUserLDAP(SID: {sid}, Username: '{userName}') ADD failed: Status is {status}")]
public static partial void DebugSyncUserLdapFailedWithStatus(this ILogger<LdapUserManager> logger, string sid, string userName, string status);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncUserLDAP(SID: {sid}, Username: '{userName}') ADD failed: Another ldap user with email '{email}' already exists")]
public static partial void DebugSyncUserLdapFailedWithEmail(this ILogger<LdapUserManager> logger, string sid, string userName, string email);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncUserLDAP(SID: {sid}, Username: '{userName}') No need to update, skipping")]
public static partial void DebugSyncUserLdapSkipping(this ILogger<LdapUserManager> logger, string sid, string userName);
[LoggerMessage(Level = LogLevel.Debug, Message = "SyncUserLDAP(SID: {sid}, Username: '{userName}') Userinfo is outdated, updating")]
public static partial void DebugSyncUserLdapUpdaiting(this ILogger<LdapUserManager> logger, string sid, string userName);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by FirstName->portal: '{firstNamePortalUser}', ldap: '{firstNameLdapUser}'")]
public static partial void DebugNeedUpdateUserByFirstName(this ILogger<LdapUserManager> logger, string firstNamePortalUser, string firstNameLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by LastName -> portal: '{lastNamePortalUser}', ldap: '{lastNameLdapUser}'")]
public static partial void DebugNeedUpdateUserByLastName(this ILogger<LdapUserManager> logger, string lastNamePortalUser, string lastNameLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by UserName -> portal: '{userNamePorta}', ldap: '{userNameLdap}'")]
public static partial void DebugNeedUpdateUserByUserName(this ILogger<LdapUserManager> logger, string userNamePorta, string userNameLdap);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Email -> portal: '{emailPortalUser}', ldap: '{emailLdapUser}'")]
public static partial void DebugNeedUpdateUserByEmail(this ILogger<LdapUserManager> logger, string emailPortalUser, string emailLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Sid -> portal: '{sidPortalUser}', ldap: '{sidLdapUser}'")]
public static partial void DebugNeedUpdateUserBySid(this ILogger<LdapUserManager> logger, string sidPortalUser, string sidLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Title -> portal: '{titlePortalUser}', ldap: '{titleLdapUser}'")]
public static partial void DebugNeedUpdateUserByTitle(this ILogger<LdapUserManager> logger, string titlePortalUser, string titleLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Location -> portal: '{locationPortalUser}', ldap: '{locationLdapUser}'")]
public static partial void DebugNeedUpdateUserByLocation(this ILogger<LdapUserManager> logger, string locationPortalUser, string locationLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by ActivationStatus -> portal: '{activationStatusPortalUser}', ldap: '{activationStatusLdapUser}'")]
public static partial void DebugNeedUpdateUserByActivationStatus(this ILogger<LdapUserManager> logger, EmployeeActivationStatus activationStatusPortalUser, EmployeeActivationStatus activationStatusLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Status -> portal: '{statusPortalUser}', ldap: '{statusLdapUser}'")]
public static partial void DebugNeedUpdateUserByStatus(this ILogger<LdapUserManager> logger, EmployeeStatus statusPortalUser, EmployeeStatus statusLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Contacts -> portal: '{contactsPortalUser}', ldap: '{contactsLdapUser}'")]
public static partial void DebugNeedUpdateUserByContacts(this ILogger<LdapUserManager> logger, string contactsPortalUser, string contactsLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by PrimaryPhone -> portal: '{primaryPhonePortalUser}', ldap: '{primaryPhoneLdapUser}'")]
public static partial void DebugNeedUpdateUserByPrimaryPhone(this ILogger<LdapUserManager> logger, string primaryPhonePortalUser, string primaryPhoneLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by BirthDate -> portal: '{birthDatePortalUser}', ldap: '{birthDateLdapUser}'")]
public static partial void DebugNeedUpdateUserByBirthDate(this ILogger<LdapUserManager> logger, string birthDatePortalUser, string birthDateLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser by Sex -> portal: '{sexPortalUser}', ldap: '{sexDateLdapUser}'")]
public static partial void DebugNeedUpdateUserBySex(this ILogger<LdapUserManager> logger, string sexPortalUser, string sexDateLdapUser);
[LoggerMessage(Level = LogLevel.Debug, Message = "NeedUpdateUser")]
public static partial void DebugNeedUpdateUser(this ILogger<LdapUserManager> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryUpdateUserWithLDAPInfo()")]
public static partial void DebugTryUpdateUserWithLdapInfo(this ILogger<LdapUserManager> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "UpdateUserWithLDAPInfo(ID: {userId}): New username already exists. (Old: '{OldUserInfo})' New: '{NewUserInfo}'")]
public static partial void DebugUpdateUserUserNameAlredyExists(this ILogger<LdapUserManager> logger, Guid userId, string oldUserInfo, string newUserInfo);
[LoggerMessage(Level = LogLevel.Debug, Message = "UpdateUserWithLDAPInfo(ID: {userId}): New email already exists. (Old: '{oldEmail})' New: '{newEmail}'")]
public static partial void DebugUpdateUserEmailAlreadyExists(this ILogger<LdapUserManager> logger, Guid userId, string oldEmail, string newEmail);
[LoggerMessage(Level = LogLevel.Error, Message = "UpdateUserWithLDAPInfo(Id='{userId}' UserName='{userName}' Sid='{sid}')")]
public static partial void ErrorUpdateUserWithLDAPInfo(this ILogger<LdapUserManager> logger, Guid userId, string userName, string sid, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryGetAndSyncLdapUserInfo(login: \"{login}\")")]
public static partial void DebugTryGetAndSyncLdapUserInfo(this ILogger<LdapUserManager> logger, string login);
[LoggerMessage(Level = LogLevel.Debug, Message = "NovellLdapUserImporter.Login('{login}') failed.")]
public static partial void DebugNovellLdapUserImporterLoginFailed(this ILogger<LdapUserManager> logger, string login);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryCheckAndSyncToLdapUser(Username: '{userName}', Email: {email}, DN: {distinguishedName})")]
public static partial void DebugTryCheckAndSyncToLdapUser(this ILogger<LdapUserManager> logger, string userName, string email, string distinguishedName);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryCheckAndSyncToLdapUser() failed")]
public static partial void DebugTryCheckAndSyncToLdapUserFailed(this ILogger<LdapUserManager> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "TryGetLdapUserInfo(login: '{login}')")]
public static partial void ErrorTryGetLdapUserInfoFailed(this ILogger<LdapUserManager> logger, string login, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "TrySyncLdapUser(SID: '{sid}', Email: {email})")]
public static partial void ErrorTrySyncLdapUser(this ILogger<LdapUserManager> logger, string sid, string email, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "TryGetAndSyncLdapUserInfo(login: \"{login}\") disabling user {userInfo} due to not being included in any ldap group")]
public static partial void DebugTryGetAndSyncLdapUserInfoDisablingUser(this ILogger<LdapUserManager> logger, string login, UserInfo userInfo);
}

View File

@ -0,0 +1,33 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class LdapUtilsLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "SkipErrors() failed")]
public static partial void ErrorSkipErrors(this ILogger logger, Exception exception);
}

View File

@ -0,0 +1,36 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class NovellLdapObjectLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "Can't get LDAPObject Sid property")]
public static partial void ErrorCanNotGetSidProperty(this ILogger logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Can't get LDAPUser UserAccountControl property")]
public static partial void ErrorCanNotGetUserAccountControlProperty(this ILogger logger, Exception exception);
}

View File

@ -0,0 +1,87 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Log;
static internal partial class NovellLdapSearcherLogger
{
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.Connect(Server='{server}', PortNumber='{portNumber}');")]
public static partial void DebugldapConnection(this ILogger<NovellLdapSearcher> logger, string server, int portNumber);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.StartTls();")]
public static partial void DebugStartTls(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "LDAP certificate confirmation requested.")]
public static partial void DebugLdapCertificateConfirmationRequested(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.Bind(Anonymous)")]
public static partial void DebugBindAnonymous(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.Bind(Login: '{login}')")]
public static partial void DebugBind(this ILogger<NovellLdapSearcher> logger, string login);
[LoggerMessage(Level = LogLevel.Warning, Message = "ServerCertValidationHandler: sslPolicyErrors = {sslPolicyErrors}")]
public static partial void WarnSslPolicyErrors(this ILogger<NovellLdapSearcher> logger, SslPolicyErrors sslPolicyErrors);
[LoggerMessage(Level = LogLevel.Warning, Message = "The size of the search results is limited. Start TrySearchSimple()")]
public static partial void WarnStartTrySearchSimple(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "Search({searchFilter}) failed")]
public static partial void ErrorSearch(this ILogger<NovellLdapSearcher> logger, string searchFilter, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "TrySearchSimple() failed")]
public static partial void ErrorTrySearchSimple(this ILogger<NovellLdapSearcher> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "SearchSimple({searchFilter}) failed")]
public static partial void ErrorSearchSimple(this ILogger<NovellLdapSearcher> logger, string searchFilter, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "{i}. DN: {distinguishedName}")]
public static partial void DebugDnEnumeration(this ILogger<NovellLdapSearcher> logger, int i, string distinguishedName);
[LoggerMessage(Level = LogLevel.Debug, Message = "No controls returned")]
public static partial void DebugNoControlsReturned(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "GetCapabilities()->LoopResults failed")]
public static partial void ErrorGetCapabilitiesLoopResultsFailed(this ILogger<NovellLdapSearcher> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "GetCapabilities() failed")]
public static partial void ErrorGetCapabilitiesFailed(this ILogger<NovellLdapSearcher> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "GetLdapUniqueId()")]
public static partial void ErrorGetLdapUniqueId(this ILogger<NovellLdapSearcher> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.StopTls();")]
public static partial void DebugLdapConnectionStopTls(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.Disconnect();")]
public static partial void DebugLdapConnectionDisconnect(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "ldapConnection.Dispose();")]
public static partial void DebugLdapConnectionDispose(this ILogger<NovellLdapSearcher> logger);
[LoggerMessage(Level = LogLevel.Error, Message = "LDAP->Dispose() failed")]
public static partial void ErrorLdapDisposeFailed(this ILogger<NovellLdapSearcher> logger, Exception exception);
}

View File

@ -0,0 +1,139 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell.Data;
/// <summary>
/// Novell LDAP object class
/// </summary>
public class NovellLdapObject : LdapObject
{
private LdapEntry _ldapEntry;
private readonly ILogger _logger;
private string _sid;
private string _sidAttribute;
private readonly NovellLdapEntryExtension _novellLdapEntryExtension;
/// <summary>
/// Constructor
/// </summary>
/// <param name="ldapEntry">init ldap entry</param>
/// <param name="ldapUniqueIdAttribute"></param>
public NovellLdapObject(ILogger logger, NovellLdapEntryExtension novellLdapEntryExtension)
{
_novellLdapEntryExtension = novellLdapEntryExtension;
_logger = logger;
}
public void Init(LdapEntry ldapEntry, string ldapUniqueIdAttribute = null)
{
if (ldapEntry == null)
{
throw new ArgumentNullException("ldapEntry");
}
_ldapEntry = ldapEntry;
if (string.IsNullOrEmpty(ldapUniqueIdAttribute))
{
return;
}
try
{
_sid = GetValue(ldapUniqueIdAttribute) as string;
_sidAttribute = ldapUniqueIdAttribute;
}
catch (Exception e)
{
_logger.ErrorCanNotGetSidProperty(e);
}
}
#region .Public
public override string DistinguishedName
{
get { return _ldapEntry.Dn; }
}
public override string Sid
{
get { return _sid; }
}
public override string SidAttribute
{
get { return _sidAttribute; }
}
public override bool IsDisabled
{
get
{
var userAccauntControl = LdapConstants.UserAccountControl.EMPTY;
try
{
var uac = Convert.ToInt32(GetValue(LdapConstants.ADSchemaAttributes.USER_ACCOUNT_CONTROL));
userAccauntControl = (LdapConstants.UserAccountControl)uac;
}
catch (Exception e)
{
_logger.ErrorCanNotGetUserAccountControlProperty(e);
}
return (userAccauntControl & LdapConstants.UserAccountControl.ADS_UF_ACCOUNTDISABLE) > 0;
}
}
#endregion
/// <summary>
/// Get property object
/// </summary>
/// <param name="propertyName">property name</param>
/// <returns>value object</returns>
public sealed override object GetValue(string propertyName, bool getBytes = false)
{
return _novellLdapEntryExtension.GetAttributeValue(_ldapEntry, propertyName, getBytes);
}
/// <summary>
/// Get property values
/// </summary>
/// <param name="propertyName">property name</param>
/// <returns>list of values</returns>
public override List<string> GetValues(string propertyName)
{
var propertyValueArray = _novellLdapEntryExtension.GetAttributeArrayValue(_ldapEntry, propertyName);
if (propertyValueArray == null)
{
return new List<string>();
}
var properties = propertyValueArray.ToList();
return properties;
}
}

View File

@ -0,0 +1,33 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell.Exceptions;
[Serializable]
public class NovellLdapTlsCertificateRequestedException : Exception
{
public LdapCertificateConfirmRequest CertificateConfirmRequest { get; set; }
}

View File

@ -0,0 +1,155 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell.Extensions;
[Singletone]
public class NovellLdapEntryExtension
{
private readonly ILogger<NovellLdapEntryExtension> _logger;
public NovellLdapEntryExtension(ILogger<NovellLdapEntryExtension> logger)
{
_logger = logger;
}
public object GetAttributeValue(LdapEntry ldapEntry, string attributeName, bool getBytes = false)
{
try
{
var attribute = ldapEntry.GetAttribute(attributeName);
if (attribute == null)
{
return null;
}
if (!(string.Equals(attributeName, LdapConstants.ADSchemaAttributes.OBJECT_SID,
StringComparison.OrdinalIgnoreCase) || getBytes))
{
return attribute.StringValue;
}
if (attribute.ByteValue == null)
{
return null;
}
var value = new byte[attribute.ByteValue.Length];
Buffer.BlockCopy(attribute.ByteValue, 0, value, 0, attribute.ByteValue.Length);
if (getBytes)
{
return value;
}
return DecodeSid(value);
}
catch (Exception)
{
return null;
}
}
public string[] GetAttributeArrayValue(LdapEntry ldapEntry, string attributeName)
{
var attribute = ldapEntry.GetAttribute(attributeName);
return attribute == null ? null : attribute.StringValueArray;
}
private string DecodeSid(byte[] sid)
{
var strSid = new StringBuilder("S-");
// get version
int revision = sid[0];
strSid.Append(revision.ToString(CultureInfo.InvariantCulture));
//next byte is the count of sub-authorities
var countSubAuths = sid[1] & 0xFF;
//get the authority
long authority = 0;
//String rid = "";
for (var i = 2; i <= 7; i++)
{
authority |= ((long)sid[i]) << (8 * (5 - (i - 2)));
}
strSid.Append("-");
strSid.Append(authority);
//iterate all the sub-auths
var offset = 8;
const int size = 4; //4 bytes for each sub auth
for (var j = 0; j < countSubAuths; j++)
{
long subAuthority = 0;
for (var k = 0; k < size; k++)
{
subAuthority |= (long)(sid[offset + k] & 0xFF) << (8 * k);
}
strSid.Append("-");
strSid.Append(subAuthority);
offset += size;
}
return strSid.ToString();
}
/// <summary>
/// Create LDAPObject by LdapEntry
/// </summary>
/// <param name="ldapEntry">init ldapEntry</param>
/// <param name="ldapUniqueIdAttribute"></param>
/// <returns>LDAPObject</returns>
public LdapObject ToLdapObject(LdapEntry ldapEntry, string ldapUniqueIdAttribute = null)
{
if (ldapEntry == null)
{
throw new ArgumentNullException("ldapEntry");
}
var novellLdapObject = new NovellLdapObject(_logger, this);
novellLdapObject.Init(ldapEntry, ldapUniqueIdAttribute);
return novellLdapObject;
}
/// <summary>
/// Create lis of LDAPObject by LdapEntry list
/// </summary>
/// <param name="entries">list of LdapEntry</param>
/// <param name="ldapUniqueIdAttribute"></param>
/// <returns>list of LDAPObjects</returns>
public List<LdapObject> ToLdapObjects(IEnumerable<LdapEntry> entries, string ldapUniqueIdAttribute = null)
{
return entries.Select(e => ToLdapObject(e, ldapUniqueIdAttribute)).ToList();
}
}

View File

@ -0,0 +1,295 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell;
[Scope]
public class NovellLdapHelper : LdapHelper
{
private readonly NovellLdapSearcher _lDAPSearcher;
private readonly IConfiguration _configuration;
private readonly IServiceProvider _serviceProvider;
private readonly LdapObjectExtension _ldapObjectExtension;
public NovellLdapHelper(IServiceProvider serviceProvider, ILogger<LdapHelper> logger, InstanceCrypto instanceCrypto, IConfiguration configuration, NovellLdapSearcher novellLdapSearcher, LdapObjectExtension ldapObjectExtension) :
base(logger, instanceCrypto)
{
_lDAPSearcher = novellLdapSearcher;
_configuration = configuration;
_serviceProvider = serviceProvider;
_ldapObjectExtension = ldapObjectExtension;
}
public new void Init(LdapSettings settings)
{
var password = string.IsNullOrEmpty(settings.Password)
? GetPassword(settings.PasswordBytes)
: settings.Password;
_lDAPSearcher.Init(settings.Login, password, settings.Server, settings.PortNumber,
settings.StartTls, settings.Ssl, settings.AcceptCertificate, settings.AcceptCertificateHash);
base.Init(settings);
}
public override bool IsConnected
{
get { return _lDAPSearcher.IsConnected; }
}
public override void Connect()
{
_lDAPSearcher.Connect();
Settings.AcceptCertificate = _lDAPSearcher.AcceptCertificate;
Settings.AcceptCertificateHash = _lDAPSearcher.AcceptCertificateHash;
}
public override Dictionary<string, string[]> GetCapabilities()
{
return _lDAPSearcher.GetCapabilities();
}
public override string SearchDomain()
{
try
{
var capabilities = GetCapabilities();
if (capabilities.Count > 0)
{
if (capabilities.ContainsKey("defaultNamingContext"))
{
var dnList = capabilities["defaultNamingContext"];
var dn = dnList.FirstOrDefault(dc =>
!string.IsNullOrEmpty(dc) &&
dc.IndexOf("dc=", StringComparison.InvariantCultureIgnoreCase) != -1);
var domain = LdapUtils.DistinguishedNameToDomain(dn);
if (!string.IsNullOrEmpty(domain))
{
return domain;
}
}
if (capabilities.ContainsKey("rootDomainNamingContext"))
{
var dnList = capabilities["rootDomainNamingContext"];
var dn = dnList.FirstOrDefault(dc =>
!string.IsNullOrEmpty(dc) &&
dc.IndexOf("dc=", StringComparison.InvariantCultureIgnoreCase) != -1);
var domain = LdapUtils.DistinguishedNameToDomain(dn);
if (!string.IsNullOrEmpty(domain))
{
return domain;
}
}
if (capabilities.ContainsKey("namingContexts"))
{
var dnList = capabilities["namingContexts"];
var dn = dnList.FirstOrDefault(dc =>
!string.IsNullOrEmpty(dc) &&
dc.IndexOf("dc=", StringComparison.InvariantCultureIgnoreCase) != -1);
var domain = LdapUtils.DistinguishedNameToDomain(dn);
if (!string.IsNullOrEmpty(domain))
{
return domain;
}
}
}
}
catch (Exception e)
{
_logger.WarnSearchDomainFailed(e);
}
try
{
var searchResult =
_lDAPSearcher.Search(Settings.UserDN, NovellLdapSearcher.LdapScope.Sub, Settings.UserFilter, limit: 1)
.FirstOrDefault();
return searchResult != null ? _ldapObjectExtension.GetDomainFromDn(searchResult) : null;
}
catch (Exception e)
{
_logger.WarnSearchDomainFailed(e);
}
return null;
}
public override void CheckCredentials(string login, string password, string server, int portNumber,
bool startTls, bool ssl, bool acceptCertificate, string acceptCertificateHash)
{
using var novellLdapSearcher = _serviceProvider.GetRequiredService<NovellLdapSearcher>();
novellLdapSearcher.Init(login, password, server, portNumber, startTls, ssl, acceptCertificate, acceptCertificateHash);
novellLdapSearcher.Connect();
}
public override bool CheckUserDn(string userDn)
{
string[] attributes = { LdapConstants.ADSchemaAttributes.OBJECT_CLASS };
var searchResult = _lDAPSearcher.Search(userDn, NovellLdapSearcher.LdapScope.Base,
LdapConstants.OBJECT_FILTER, attributes, 1);
if (searchResult.Any())
{
return true;
}
_logger.ErrorWrongUserDnParameter(userDn);
return false;
}
public override bool CheckGroupDn(string groupDn)
{
string[] attributes = { LdapConstants.ADSchemaAttributes.OBJECT_CLASS };
var searchResult = _lDAPSearcher.Search(groupDn, NovellLdapSearcher.LdapScope.Base,
LdapConstants.OBJECT_FILTER, attributes, 1);
if (searchResult.Any())
{
return true;
}
_logger.ErrorWrongGroupDnParameter(groupDn);
return false;
}
public override List<LdapObject> GetUsers(string filter = null, int limit = -1)
{
var list = new List<LdapObject>();
try
{
if (!string.IsNullOrEmpty(Settings.UserFilter) && !Settings.UserFilter.StartsWith("(") &&
!Settings.UserFilter.EndsWith(")"))
{
Settings.UserFilter = string.Format("({0})", Settings.UserFilter);
}
if (!string.IsNullOrEmpty(filter) && !filter.StartsWith("(") &&
!filter.EndsWith(")"))
{
filter = string.Format("({0})", Settings.UserFilter);
}
var searchfilter = string.IsNullOrEmpty(filter)
? Settings.UserFilter
: string.Format("(&{0}{1})", Settings.UserFilter, filter);
list = _lDAPSearcher.Search(Settings.UserDN, NovellLdapSearcher.LdapScope.Sub, searchfilter, limit: limit);
return list;
}
catch (Exception e)
{
_logger.ErrorGetUsersFailed(filter, limit, e);
}
return list;
}
public override LdapObject GetUserBySid(string sid)
{
try
{
var ldapUniqueIdAttribute = _configuration["ldap:unique:id"];
Criteria criteria;
if (ldapUniqueIdAttribute == null)
{
criteria = Criteria.Any(
Expression.Equal(LdapConstants.RfcLDAPAttributes.ENTRY_UUID, sid),
Expression.Equal(LdapConstants.RfcLDAPAttributes.NS_UNIQUE_ID, sid),
Expression.Equal(LdapConstants.RfcLDAPAttributes.GUID, sid),
Expression.Equal(LdapConstants.ADSchemaAttributes.OBJECT_SID, sid)
);
}
else
{
criteria = Criteria.All(Expression.Equal(ldapUniqueIdAttribute, sid));
}
var searchfilter = string.Format("(&{0}{1})", Settings.UserFilter, criteria);
var list = _lDAPSearcher.Search(Settings.UserDN, NovellLdapSearcher.LdapScope.Sub, searchfilter, limit: 1);
return list.FirstOrDefault();
}
catch (Exception e)
{
_logger.ErrorGetUserBySidFailed(sid, e);
}
return null;
}
public override List<LdapObject> GetGroups(Criteria criteria = null)
{
var list = new List<LdapObject>();
try
{
if (!string.IsNullOrEmpty(Settings.GroupFilter) && !Settings.GroupFilter.StartsWith("(") &&
!Settings.GroupFilter.EndsWith(")"))
{
Settings.GroupFilter = string.Format("({0})", Settings.GroupFilter);
}
var searchfilter = criteria == null
? Settings.GroupFilter
: string.Format("(&{0}{1})", Settings.GroupFilter, criteria);
list = _lDAPSearcher.Search(Settings.GroupDN, NovellLdapSearcher.LdapScope.Sub, searchfilter);
}
catch (Exception e)
{
_logger.ErrorGetGroupsFailed(criteria, e);
}
return list;
}
public override void Dispose()
{
_lDAPSearcher.Dispose();
}
}

View File

@ -0,0 +1,652 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell;
[Scope]
public class NovellLdapSearcher : IDisposable
{
protected readonly ILogger<NovellLdapSearcher> _logger;
private LdapCertificateConfirmRequest _certificateConfirmRequest;
private static readonly object _rootSync = new object();
private readonly IConfiguration _configuration;
private readonly NovellLdapEntryExtension _novellLdapEntryExtension;
private LdapConnection _ldapConnection;
public string Login { get; private set; }
public string Password { get; private set; }
public string Server { get; private set; }
public int PortNumber { get; private set; }
public bool StartTls { get; private set; }
public bool Ssl { get; private set; }
public bool AcceptCertificate { get; private set; }
public string AcceptCertificateHash { get; private set; }
public string LdapUniqueIdAttribute { get; set; }
private Dictionary<string, string[]> _capabilities;
public bool IsConnected
{
get { return _ldapConnection != null && _ldapConnection.Connected; }
}
public NovellLdapSearcher(
IConfiguration configuration,
ILogger<NovellLdapSearcher> logger,
NovellLdapEntryExtension novellLdapEntryExtension)
{
_logger = logger;
_configuration = configuration;
_novellLdapEntryExtension = novellLdapEntryExtension;
LdapUniqueIdAttribute = configuration["ldap:unique:id"];
}
public void Init(string login,
string password,
string server,
int portNumber,
bool startTls,
bool ssl,
bool acceptCertificate,
string acceptCertificateHash = null)
{
Login = login;
Password = password;
Server = server;
PortNumber = portNumber;
StartTls = startTls;
Ssl = ssl;
AcceptCertificate = acceptCertificate;
AcceptCertificateHash = acceptCertificateHash;
}
public void Connect()
{
if (Server.StartsWith("LDAP://"))
{
Server = Server.Substring("LDAP://".Length);
}
LdapConnection ldapConnection;
if (StartTls || Ssl)
{
var ldapConnectionOptions = new LdapConnectionOptions();
ldapConnectionOptions.ConfigureRemoteCertificateValidationCallback(ServerCertValidationHandler);
ldapConnection = new LdapConnection(ldapConnectionOptions);
}
else
{
ldapConnection = new LdapConnection();
}
if (Ssl)
{
ldapConnection.SecureSocketLayer = true;
}
try
{
ldapConnection.ConnectionTimeout = 30000; // 30 seconds
_logger.DebugldapConnection(Server, PortNumber);
ldapConnection.Connect(Server, PortNumber);
if (StartTls)
{
_logger.DebugStartTls();
ldapConnection.StartTls();
}
}
catch (Exception ex)
{
if (_certificateConfirmRequest == null)
{
if (ex.Message.StartsWith("Connect Error"))
{
throw new SocketException();
}
if (ex.Message.StartsWith("Unavailable"))
{
throw new NotSupportedException(ex.Message);
}
throw;
}
_logger.DebugLdapCertificateConfirmationRequested();
ldapConnection.Disconnect();
var exception = new NovellLdapTlsCertificateRequestedException
{
CertificateConfirmRequest = _certificateConfirmRequest
};
throw exception;
}
if (string.IsNullOrEmpty(Login) || string.IsNullOrEmpty(Password))
{
_logger.DebugBindAnonymous();
ldapConnection.Bind(null, null);
}
else
{
_logger.DebugBind(Login);
ldapConnection.Bind(Login, Password);
}
if (!ldapConnection.Bound)
{
throw new Exception("Bind operation wasn't completed successfully.");
}
_ldapConnection = ldapConnection;
}
private bool ServerCertValidationHandler(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
{
return true;
}
lock (_rootSync)
{
var certHash = certificate.GetCertHashString();
if (AcceptCertificate)
{
if (AcceptCertificateHash == null || AcceptCertificateHash.Equals(certHash))
{
return true;
}
AcceptCertificate = false;
AcceptCertificateHash = null;
}
_logger.WarnSslPolicyErrors(sslPolicyErrors);
_certificateConfirmRequest = LdapCertificateConfirmRequest.FromCert(certificate, chain, sslPolicyErrors, false, true, _logger);
}
return false;
}
public enum LdapScope
{
Base = LdapConnection.ScopeBase,
One = LdapConnection.ScopeOne,
Sub = LdapConnection.ScopeSub
}
public List<LdapObject> Search(LdapScope scope, string searchFilter,
string[] attributes = null, int limit = -1, LdapSearchConstraints searchConstraints = null)
{
return Search("", scope, searchFilter, attributes, limit, searchConstraints);
}
public List<LdapObject> Search(string searchBase, LdapScope scope, string searchFilter,
string[] attributes = null, int limit = -1, LdapSearchConstraints searchConstraints = null)
{
if (!IsConnected)
{
Connect();
}
if (searchBase == null)
{
searchBase = "";
}
var entries = new List<LdapEntry>();
if (string.IsNullOrEmpty(searchFilter))
{
return new List<LdapObject>();
}
if (attributes == null)
{
if (string.IsNullOrEmpty(LdapUniqueIdAttribute))
{
attributes = new[]
{
"*", LdapConstants.RfcLDAPAttributes.ENTRY_DN, LdapConstants.RfcLDAPAttributes.ENTRY_UUID,
LdapConstants.RfcLDAPAttributes.NS_UNIQUE_ID, LdapConstants.RfcLDAPAttributes.GUID
};
}
else
{
attributes = new[] { "*", LdapUniqueIdAttribute };
}
}
var ldapSearchConstraints = searchConstraints ?? new LdapSearchConstraints
{
// Maximum number of search results to return.
// The value 0 means no limit. The default is 1000.
MaxResults = limit == -1 ? 0 : limit,
// Returns the number of results to block on during receipt of search results.
// This should be 0 if intermediate results are not needed, and 1 if results are to be processed as they come in.
//BatchSize = 0,
// The maximum number of referrals to follow in a sequence during automatic referral following.
// The default value is 10. A value of 0 means no limit.
HopLimit = 0,
// Specifies whether referrals are followed automatically
// Referrals of any type other than to an LDAP server (for example, a referral URL other than ldap://something) are ignored on automatic referral following.
// The default is false.
ReferralFollowing = true,
// The number of seconds to wait for search results.
// Sets the maximum number of seconds that the server is to wait when returning search results.
//ServerTimeLimit = 600000, // 10 minutes
// Sets the maximum number of milliseconds the client waits for any operation under these constraints to complete.
// If the value is 0, there is no maximum time limit enforced by the API on waiting for the operation results.
//TimeLimit = 600000 // 10 minutes
};
var queue = _ldapConnection.Search(searchBase,
(int)scope, searchFilter, attributes, false, ldapSearchConstraints);
while (queue.HasMore())
{
LdapEntry nextEntry;
try
{
nextEntry = queue.Next();
if (nextEntry == null)
{
continue;
}
}
catch (LdapException ex)
{
if (!string.IsNullOrEmpty(ex.Message) && ex.Message.Contains("Sizelimit Exceeded"))
{
if (!string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password) && limit == -1)
{
_logger.WarnStartTrySearchSimple();
List<LdapObject> simpleResults;
if (TrySearchSimple(searchBase, scope, searchFilter, out simpleResults, attributes, limit,
searchConstraints))
{
if (entries.Count >= simpleResults.Count)
{
break;
}
return simpleResults;
}
}
break;
}
_logger.ErrorSearch( searchFilter, ex);
continue;
}
entries.Add(nextEntry);
if (string.IsNullOrEmpty(LdapUniqueIdAttribute))
{
LdapUniqueIdAttribute = GetLdapUniqueId(nextEntry);
}
}
var result = _novellLdapEntryExtension.ToLdapObjects(entries, LdapUniqueIdAttribute);
return result;
}
private bool TrySearchSimple(string searchBase, LdapScope scope, string searchFilter, out List<LdapObject> results,
string[] attributes = null, int limit = -1, LdapSearchConstraints searchConstraints = null)
{
try
{
results = SearchSimple(searchBase, scope, searchFilter, attributes, limit, searchConstraints);
return true;
}
catch (Exception ex)
{
_logger.ErrorTrySearchSimple(ex);
}
results = null;
return false;
}
public List<LdapObject> SearchSimple(string searchBase, LdapScope scope, string searchFilter,
string[] attributes = null, int limit = -1, LdapSearchConstraints searchConstraints = null)
{
if (!IsConnected)
{
Connect();
}
if (searchBase == null)
{
searchBase = "";
}
var entries = new List<LdapEntry>();
if (string.IsNullOrEmpty(searchFilter))
{
return new List<LdapObject>();
}
if (attributes == null)
{
if (string.IsNullOrEmpty(LdapUniqueIdAttribute))
{
attributes = new[]
{
"*", LdapConstants.RfcLDAPAttributes.ENTRY_DN, LdapConstants.RfcLDAPAttributes.ENTRY_UUID,
LdapConstants.RfcLDAPAttributes.NS_UNIQUE_ID, LdapConstants.RfcLDAPAttributes.GUID
};
}
else
{
attributes = new[] { "*", LdapUniqueIdAttribute };
}
}
var ldapSearchConstraints = searchConstraints ?? new LdapSearchConstraints
{
// Maximum number of search results to return.
// The value 0 means no limit. The default is 1000.
MaxResults = limit == -1 ? 0 : limit,
// Returns the number of results to block on during receipt of search results.
// This should be 0 if intermediate results are not needed, and 1 if results are to be processed as they come in.
//BatchSize = 0,
// The maximum number of referrals to follow in a sequence during automatic referral following.
// The default value is 10. A value of 0 means no limit.
HopLimit = 0,
// Specifies whether referrals are followed automatically
// Referrals of any type other than to an LDAP server (for example, a referral URL other than ldap://something) are ignored on automatic referral following.
// The default is false.
ReferralFollowing = true,
// The number of seconds to wait for search results.
// Sets the maximum number of seconds that the server is to wait when returning search results.
//ServerTimeLimit = 600000, // 10 minutes
// Sets the maximum number of milliseconds the client waits for any operation under these constraints to complete.
// If the value is 0, there is no maximum time limit enforced by the API on waiting for the operation results.
//TimeLimit = 600000 // 10 minutes
};
// initially, cookie must be set to an empty string
var pageSize = 2;
var cookie = Array.ConvertAll(Encoding.ASCII.GetBytes(""), b => unchecked(b));
var i = 0;
do
{
var requestControls = new LdapControl[1];
requestControls[0] = new SimplePagedResultsControl(pageSize, cookie);
ldapSearchConstraints.SetControls(requestControls);
_ldapConnection.Constraints = ldapSearchConstraints;
var res = _ldapConnection.Search(searchBase,
(int)scope, searchFilter, attributes, false, (LdapSearchConstraints)null);
while (res.HasMore())
{
LdapEntry nextEntry;
try
{
nextEntry = res.Next();
if (nextEntry == null)
{
continue;
}
}
catch (LdapException ex)
{
if (ex is LdapReferralException)
{
continue;
}
if (!string.IsNullOrEmpty(ex.Message) && ex.Message.Contains("Sizelimit Exceeded"))
{
break;
}
_logger.ErrorSearchSimple(searchFilter, ex);
continue;
}
_logger.DebugDnEnumeration(++i, nextEntry.Dn);
entries.Add(nextEntry);
if (string.IsNullOrEmpty(LdapUniqueIdAttribute))
{
LdapUniqueIdAttribute = GetLdapUniqueId(nextEntry);
}
}
// Server should send back a control irrespective of the
// status of the search request
var controls = res.ResponseControls;
if (controls == null)
{
_logger.DebugNoControlsReturned();
cookie = null;
}
else
{
// Multiple controls could have been returned
foreach (var control in controls)
{
/* Is this the LdapPagedResultsResponse control? */
if (!(control is SimplePagedResultsControl))
{
continue;
}
var response = new SimplePagedResultsControl(control.Id,
control.Critical, control.GetValue());
cookie = response.Cookie;
}
}
// if cookie is empty, we are done.
} while (cookie != null && cookie.Length > 0);
var result = _novellLdapEntryExtension.ToLdapObjects(entries, LdapUniqueIdAttribute);
return result;
}
public Dictionary<string, string[]> GetCapabilities()
{
if (_capabilities != null)
{
return _capabilities;
}
_capabilities = new Dictionary<string, string[]>();
try
{
var ldapSearchConstraints = new LdapSearchConstraints
{
MaxResults = int.MaxValue,
HopLimit = 0,
ReferralFollowing = true
};
var ldapSearchResults = _ldapConnection.Search("", LdapConnection.ScopeBase, LdapConstants.OBJECT_FILTER,
new[] { "*", "supportedControls", "supportedCapabilities" }, false, ldapSearchConstraints);
while (ldapSearchResults.HasMore())
{
LdapEntry nextEntry;
try
{
nextEntry = ldapSearchResults.Next();
if (nextEntry == null)
{
continue;
}
}
catch (LdapException ex)
{
_logger.ErrorGetCapabilitiesLoopResultsFailed(ex);
continue;
}
var attributeSet = nextEntry.GetAttributeSet();
var ienum = attributeSet.GetEnumerator();
while (ienum.MoveNext())
{
var attribute = (LdapAttribute)ienum.Current;
if (attribute == null)
{
continue;
}
var attributeName = attribute.Name;
var attributeVals = attribute.StringValueArray
.ToList()
.Select(s =>
{
if (Base64.IsLdifSafe(s))
{
return s;
}
s = Base64.Encode(s);
return s;
}).ToArray();
_capabilities.Add(attributeName, attributeVals);
}
}
}
catch (Exception ex)
{
_logger.ErrorGetCapabilitiesFailed(ex);
}
return _capabilities;
}
private string GetLdapUniqueId(LdapEntry ldapEntry)
{
try
{
var ldapUniqueIdAttribute = _configuration["ldap:unique:id"];
if (ldapUniqueIdAttribute != null)
{
return ldapUniqueIdAttribute;
}
if (!string.IsNullOrEmpty(
_novellLdapEntryExtension.GetAttributeValue(ldapEntry, LdapConstants.ADSchemaAttributes.OBJECT_SID) as string))
{
ldapUniqueIdAttribute = LdapConstants.ADSchemaAttributes.OBJECT_SID;
}
else if (!string.IsNullOrEmpty(
_novellLdapEntryExtension.GetAttributeValue(ldapEntry, LdapConstants.RfcLDAPAttributes.ENTRY_UUID) as string))
{
ldapUniqueIdAttribute = LdapConstants.RfcLDAPAttributes.ENTRY_UUID;
}
else if (!string.IsNullOrEmpty(
_novellLdapEntryExtension.GetAttributeValue(ldapEntry, LdapConstants.RfcLDAPAttributes.NS_UNIQUE_ID) as string))
{
ldapUniqueIdAttribute = LdapConstants.RfcLDAPAttributes.NS_UNIQUE_ID;
}
else if (!string.IsNullOrEmpty(
_novellLdapEntryExtension.GetAttributeValue(ldapEntry, LdapConstants.RfcLDAPAttributes.GUID) as string))
{
ldapUniqueIdAttribute = LdapConstants.RfcLDAPAttributes.GUID;
}
return ldapUniqueIdAttribute;
}
catch (Exception ex)
{
_logger.ErrorGetLdapUniqueId(ex);
}
return null;
}
public void Dispose()
{
if (!IsConnected)
{
return;
}
try
{
_ldapConnection.Constraints.TimeLimit = 10000;
_ldapConnection.SearchConstraints.ServerTimeLimit = 10000;
_ldapConnection.SearchConstraints.TimeLimit = 10000;
_ldapConnection.ConnectionTimeout = 10000;
if (_ldapConnection.Tls)
{
_logger.DebugLdapConnectionStopTls();
_ldapConnection.StopTls();
}
_logger.DebugLdapConnectionDisconnect();
_ldapConnection.Disconnect();
_logger.DebugLdapConnectionDispose();
_ldapConnection.Dispose();
_ldapConnection = null;
}
catch (Exception ex)
{
_logger.ErrorLdapDisposeFailed(ex);
}
}
}

View File

@ -0,0 +1,222 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell;
[Scope]
public class NovellLdapSettingsChecker : LdapSettingsChecker
{
public LdapCertificateConfirmRequest CertificateConfirmRequest { get; set; }
public LdapHelper LdapHelper
{
get { return LdapImporter.LdapHelper; }
}
public NovellLdapSettingsChecker(ILogger<LdapSettingsChecker> logger) :
base(logger)
{
}
public new void Init(LdapUserImporter importer)
{
base.Init(importer);
}
public override LdapSettingsStatus CheckSettings()
{
if (!Settings.EnableLdapAuthentication)
{
return LdapSettingsStatus.Ok;
}
if (Settings.Server.Equals("LDAP://", StringComparison.InvariantCultureIgnoreCase))
{
return LdapSettingsStatus.WrongServerOrPort;
}
if (!LdapHelper.IsConnected)
{
try
{
LdapHelper.Connect();
}
catch (NovellLdapTlsCertificateRequestedException ex)
{
_logger.ErrorNovellLdapTlsCertificateRequestedException(Settings.AcceptCertificate, ex);
CertificateConfirmRequest = ex.CertificateConfirmRequest;
return LdapSettingsStatus.CertificateRequest;
}
catch (NotSupportedException ex)
{
_logger.ErrorNotSupportedException(ex);
return LdapSettingsStatus.TlsNotSupported;
}
catch (SocketException ex)
{
_logger.ErrorSocketException(ex);
return LdapSettingsStatus.ConnectError;
}
catch (ArgumentException ex)
{
_logger.ErrorArgumentException( ex);
return LdapSettingsStatus.WrongServerOrPort;
}
catch (SecurityException ex)
{
_logger.ErrorSecurityException(ex);
return LdapSettingsStatus.StrongAuthRequired;
}
catch (SystemException ex)
{
_logger.ErrorSystemException(ex);
return LdapSettingsStatus.WrongServerOrPort;
}
catch (Exception ex)
{
_logger.ErrorCheckSettingsException(ex);
return LdapSettingsStatus.CredentialsNotValid;
}
}
if (!CheckUserDn(Settings.UserDN))
{
return LdapSettingsStatus.WrongUserDn;
}
if (Settings.GroupMembership)
{
if (!CheckGroupDn(Settings.GroupDN))
{
return LdapSettingsStatus.WrongGroupDn;
}
try
{
new RfcFilter(Settings.GroupFilter);
}
catch
{
return LdapSettingsStatus.IncorrectGroupLDAPFilter;
}
if (!LdapImporter.TryLoadLDAPGroups())
{
if (!LdapImporter.AllSkipedDomainGroups.Any())
{
return LdapSettingsStatus.IncorrectGroupLDAPFilter;
}
if (LdapImporter.AllSkipedDomainGroups.All(kv => kv.Value == LdapSettingsStatus.WrongSidAttribute))
{
return LdapSettingsStatus.WrongSidAttribute;
}
if (LdapImporter.AllSkipedDomainGroups.All(kv => kv.Value == LdapSettingsStatus.WrongGroupAttribute))
{
return LdapSettingsStatus.WrongGroupAttribute;
}
if (LdapImporter.AllSkipedDomainGroups.All(kv => kv.Value == LdapSettingsStatus.WrongGroupNameAttribute))
{
return LdapSettingsStatus.WrongGroupNameAttribute;
}
}
if (!LdapImporter.AllDomainGroups.Any())
{
return LdapSettingsStatus.GroupsNotFound;
}
}
try
{
new RfcFilter(Settings.UserFilter);
}
catch
{
return LdapSettingsStatus.IncorrectLDAPFilter;
}
if (!LdapImporter.TryLoadLDAPUsers())
{
if (!LdapImporter.AllSkipedDomainUsers.Any())
{
return LdapSettingsStatus.IncorrectLDAPFilter;
}
if (LdapImporter.AllSkipedDomainUsers.All(kv => kv.Value == LdapSettingsStatus.WrongSidAttribute))
{
return LdapSettingsStatus.WrongSidAttribute;
}
if (LdapImporter.AllSkipedDomainUsers.All(kv => kv.Value == LdapSettingsStatus.WrongLoginAttribute))
{
return LdapSettingsStatus.WrongLoginAttribute;
}
if (LdapImporter.AllSkipedDomainUsers.All(kv => kv.Value == LdapSettingsStatus.WrongUserAttribute))
{
return LdapSettingsStatus.WrongUserAttribute;
}
}
if (!LdapImporter.AllDomainUsers.Any())
{
return LdapSettingsStatus.UsersNotFound;
}
return string.IsNullOrEmpty(LdapImporter.LDAPDomain)
? LdapSettingsStatus.DomainNotFound
: LdapSettingsStatus.Ok;
}
private bool CheckUserDn(string userDn)
{
try
{
return LdapHelper.CheckUserDn(userDn);
}
catch (Exception e)
{
_logger.ErrorWrongUserDn(userDn, e);
return false;
}
}
private bool CheckGroupDn(string groupDn)
{
try
{
return LdapHelper.CheckGroupDn(groupDn);
}
catch (Exception e)
{
_logger.ErrorWrongGroupDn(groupDn, e);
return false;
}
}
}

View File

@ -0,0 +1,36 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.ActiveDirectory.Novell;
[Scope]
public class NovellLdapUserImporter : LdapUserImporter
{
public NovellLdapUserImporter(ILogger<LdapUserImporter> logger, UserManager userManager, IConfiguration configuration, NovellLdapHelper novellLdapHelper, LdapObjectExtension ldapObjectExtension)
: base(logger, userManager, configuration, novellLdapHelper, ldapObjectExtension)
{
}
}

View File

@ -60,7 +60,7 @@ public class InstanceCrypto
public string Decrypt(string data) => Decrypt(Convert.FromBase64String(data));
public string Decrypt(byte[] data)
public string Decrypt(byte[] data, Encoding encoding = null)
{
using var hasher = Aes.Create();
hasher.Key = _eKey;
@ -68,7 +68,7 @@ public class InstanceCrypto
using var msDecrypt = new MemoryStream(data);
using var csDecrypt = new CryptoStream(msDecrypt, hasher.CreateDecryptor(), CryptoStreamMode.Read);
using var srDecrypt = new StreamReader(csDecrypt);
using var srDecrypt = new StreamReader(csDecrypt, encoding);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.

View File

@ -664,7 +664,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
}
}
[Scope]
[Singletone]
public class NotifyEngineQueue
{
private readonly NotifyEngine _notifyEngine;

View File

@ -20,7 +20,8 @@
<Compile Remove="Api\SsoSettingsV2Controller.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\ASC.Api.Core\ASC.Api.Core.csproj" />
<ProjectReference Include="..\..\common\ASC.Api.Core\ASC.Api.Core.csproj" />
<ProjectReference Include="..\..\common\ASC.ActiveDirectory\ASC.ActiveDirectory.csproj" />
<ProjectReference Include="..\..\common\ASC.Core.Common\ASC.Core.Common.csproj" />
<ProjectReference Include="..\..\common\ASC.Data.Backup.Core\ASC.Data.Backup.Core.csproj" />
<ProjectReference Include="..\..\common\services\ASC.AuditTrail\ASC.AuditTrail.csproj" />

View File

@ -0,0 +1,321 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.Controllers.Settings;
public class LdapController : BaseSettingsController
{
private Tenant Tenant { get { return ApiContext.Tenant; } }
private readonly SettingsManager _settingsManager;
private readonly TenantManager _tenantManager;
private readonly LdapNotifyService _ldapNotifyHelper;
private readonly LdapSaveSyncOperation _ldapSaveSyncOperation;
private readonly AuthContext _authContext;
private readonly PermissionContext _permissionContext;
private readonly CoreBaseSettings _coreBaseSettings;
private readonly TenantExtra _tenantExtra;
private readonly IMapper _mapper;
public LdapController(
ApiContext apiContext,
WebItemManager webItemManager,
IMemoryCache memoryCache,
SettingsManager settingsManager,
TenantManager tenantManager,
LdapNotifyService ldapNotifyHelper,
LdapSaveSyncOperation ldapSaveSyncOperation,
AuthContext authContext,
PermissionContext permissionContext,
CoreBaseSettings coreBaseSettings,
TenantExtra tenantExtra,
IHttpContextAccessor httpContextAccessor,
IMapper mapper) : base(apiContext, memoryCache, webItemManager, httpContextAccessor)
{
_settingsManager = settingsManager;
_tenantManager = tenantManager;
_ldapNotifyHelper = ldapNotifyHelper;
_ldapSaveSyncOperation = ldapSaveSyncOperation;
_authContext = authContext;
_permissionContext = permissionContext;
_coreBaseSettings = coreBaseSettings;
_tenantExtra = tenantExtra;
_mapper = mapper;
}
/// <summary>
/// Returns the current portal LDAP settings.
/// </summary>
/// <short>
/// Get the LDAP settings
/// </short>
/// <category>LDAP</category>
/// <returns>LDAP settings</returns>
[HttpGet("ldap")]
public LdapSettingsDto GetLdapSettings()
{
CheckLdapPermissions();
var settings = _settingsManager.Load<LdapSettings>();
settings = settings.Clone() as LdapSettings; // clone LdapSettings object for clear password (potencial AscCache.Memory issue)
if (settings == null)
{
settings = new LdapSettings().GetDefault();
return _mapper.Map<LdapSettings, LdapSettingsDto>(settings);
}
settings.Password = null;
settings.PasswordBytes = null;
if (settings.IsDefault)
return _mapper.Map<LdapSettings, LdapSettingsDto>(settings); ;
var defaultSettings = settings.GetDefault();
if (settings.Equals(defaultSettings))
settings.IsDefault = true;
return _mapper.Map<LdapSettings, LdapSettingsDto>(settings);
}
/// <summary>
/// Returns the LDAP autosynchronous cron expression of the current portal if it exists.
/// </summary>
/// <short>
/// Get the LDAP cron expression
/// </short>
/// <category>LDAP</category>
/// <returns>Cron expression or null</returns>
[HttpGet("ldap/cron")]
public LdapCronSettingsDto GetLdapCronSettings()
{
CheckLdapPermissions();
var settings = _settingsManager.Load<LdapCronSettings>();
if (settings == null)
settings = new LdapCronSettings().GetDefault();
if (string.IsNullOrEmpty(settings.Cron))
return null;
return _mapper.Map<LdapCronSettings, LdapCronSettingsDto>(settings);
}
/// <summary>
/// Sets the LDAP autosynchronous cron expression of the current portal.
/// </summary>
/// <short>
/// Set the LDAP cron expression
/// </short>
/// <category>LDAP</category>
/// <param name="cron">Cron expression</param>
///
[HttpPost("ldap/cron")]
public void SetLdapCronSettingsFromBody(LdapCronRequestDto ldapCronRequest)
{
SetLdapCronSettings(ldapCronRequest);
}
private void SetLdapCronSettings(LdapCronRequestDto ldapCronRequest)
{
CheckLdapPermissions();
var cron = ldapCronRequest.Cron;
if (!string.IsNullOrEmpty(cron))
{
new CronExpression(cron); // validate
if (!_settingsManager.Load<LdapSettings>().EnableLdapAuthentication)
{
throw new Exception(Resource.LdapSettingsErrorCantSaveLdapSettings);
}
}
var settings = _settingsManager.Load<LdapCronSettings>();
if (settings == null)
settings = new LdapCronSettings();
settings.Cron = cron;
_settingsManager.Save(settings);
var t = _tenantManager.GetCurrentTenant();
if (!string.IsNullOrEmpty(cron))
{
_ldapNotifyHelper.UnregisterAutoSync(t);
_ldapNotifyHelper.RegisterAutoSync(t, cron);
}
else
{
_ldapNotifyHelper.UnregisterAutoSync(t);
}
}
/// <summary>
/// Starts synchronizing users and groups by LDAP.
/// </summary>
/// <short>
/// Synchronize by LDAP
/// </short>
/// <category>LDAP</category>
/// <returns>Operation status</returns>
[HttpGet("ldap/sync")]
public LdapStatusDto SyncLdap()
{
CheckLdapPermissions();
var ldapSettings = _settingsManager.Load<LdapSettings>();
var userId = _authContext.CurrentAccount.ID.ToString();
var result = _ldapSaveSyncOperation.SyncLdap(ldapSettings, Tenant, userId);
return _mapper.Map<LdapOperationStatus, LdapStatusDto>(result);
}
/// <summary>
/// Starts the process of collecting preliminary changes on the portal during the synchronization process according to the selected LDAP settings.
/// </summary>
/// <short>
/// Test the LDAP synchronization
/// </short>
/// <category>LDAP</category>
/// <returns>Operation status</returns>
[HttpGet("ldap/sync/test")]
public LdapStatusDto TestLdapSync()
{
CheckLdapPermissions();
var ldapSettings = _settingsManager.Load<LdapSettings>();
var result = _ldapSaveSyncOperation.TestLdapSync(ldapSettings, Tenant);
return _mapper.Map<LdapOperationStatus, LdapStatusDto>(result);
}
/// <summary>
/// Saves the LDAP settings specified in the request and starts importing/synchronizing users and groups by LDAP.
/// </summary>
/// <short>
/// Save the LDAP settings
/// </short>
/// <category>LDAP</category>
/// <param name="settings">LDAP settings in the serialized string format</param>
/// <param name="acceptCertificate">Specifies if the errors of checking certificates are allowed (true) or not (false)</param>
/// <returns>Operation status</returns>
[HttpPost("ldap")]
public LdapStatusDto SaveLdapSettings(LdapRequestsDto ldapRequestsDto)
{
var ldapSettings = _mapper.Map<LdapRequestsDto, LdapSettings>(ldapRequestsDto);
CheckLdapPermissions();
if (!ldapSettings.EnableLdapAuthentication)
{
SetLdapCronSettings(null);
}
var userId = _authContext.CurrentAccount.ID.ToString();
var result = _ldapSaveSyncOperation.SaveLdapSettings(ldapSettings, Tenant, userId);
return _mapper.Map<LdapOperationStatus, LdapStatusDto>(result);
}
/// <summary>
/// Starts the process of collecting preliminary changes on the portal during the saving process according to the LDAP settings.
/// </summary>
/// <short>
/// Test the LDAP saving process
/// </short>
/// <category>LDAP</category>
/// <param name="settings">LDAP settings in the serialized string format</param>
/// <param name="acceptCertificate">Specifies if the errors of checking certificates are allowed (true) or not (false)</param>
/// <returns>Operation status</returns>
[HttpPost("ldap/save/test")]
public LdapStatusDto TestLdapSave(LdapSettings ldapSettings)
{
CheckLdapPermissions();
var userId = _authContext.CurrentAccount.ID.ToString();
var result = _ldapSaveSyncOperation.TestLdapSave(ldapSettings, Tenant, userId);
return _mapper.Map<LdapOperationStatus, LdapStatusDto>(result);
}
/// <summary>
/// Returns the LDAP synchronization process status.
/// </summary>
/// <short>
/// Get the LDAP synchronization process status
/// </short>
/// <category>LDAP</category>
/// <returns>Operation status</returns>
[HttpGet("ldap/status")]
public LdapStatusDto GetLdapOperationStatus()
{
CheckLdapPermissions();
var result = _ldapSaveSyncOperation.ToLdapOperationStatus(Tenant.Id);
return _mapper.Map<LdapOperationStatus, LdapStatusDto>(result);
}
/// <summary>
/// Returns the LDAP default settings.
/// </summary>
/// <short>
/// Get the LDAP default settings
/// </short>
/// <category>LDAP</category>
/// <returns>LDAP default settings</returns>
[HttpGet("ldap/default")]
public LdapSettingsDto GetDefaultLdapSettings()
{
CheckLdapPermissions();
var settings = new LdapSettings().GetDefault();
return _mapper.Map<LdapSettings, LdapSettingsDto>(settings);
}
private void CheckLdapPermissions()
{
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
if (!_coreBaseSettings.Standalone
&& (!SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString())
|| !_tenantExtra.GetTenantQuota().Ldap))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Ldap");
}
}
}

View File

@ -0,0 +1,32 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.ApiModels.RequestsDto;
public class LdapCronRequestDto
{
public string Cron { get; set; }
}

View File

@ -0,0 +1,81 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.ApiModels.RequestsDto;
public class LdapRequestsDto : IMapFrom<LdapSettings>
{
public bool EnableLdapAuthentication { get; set; }
public bool StartTls { get; set; }
public bool Ssl { get; set; }
public bool SendWelcomeEmail { get; set; }
public string Server { get; set; }
// ReSharper disable once InconsistentNaming
public string UserDN { get; set; }
public int PortNumber { get; set; }
public string UserFilter { get; set; }
public string LoginAttribute { get; set; }
public Dictionary<MappingFields, string> LdapMapping { get; set; }
//ToDo: use SId instead of group name
public Dictionary<AccessRight, string> AccessRights { get; set; }
public bool GroupMembership { get; set; }
// ReSharper disable once InconsistentNaming
public string GroupDN { get; set; }
public string UserAttribute { get; set; }
public string GroupFilter { get; set; }
public string GroupAttribute { get; set; }
public string GroupNameAttribute { get; set; }
public bool Authentication { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public bool AcceptCertificate { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<LdapRequestsDto, LdapSettings>();
}
}

View File

@ -0,0 +1,36 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.ApiModels.ResponseDto;
public class LdapCronSettingsDto : IMapFrom<LdapCronSettings>
{
public string Cron { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<LdapCronSettings, LdapCronSettingsDto>();
}
}

View File

@ -0,0 +1,81 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.ApiModels.ResponseDto;
public class LdapSettingsDto : IMapFrom<LdapSettings>
{
public bool EnableLdapAuthentication { get; set; }
public bool StartTls { get; set; }
public bool Ssl { get; set; }
public bool SendWelcomeEmail { get; set; }
public string Server { get; set; }
// ReSharper disable once InconsistentNaming
public string UserDN { get; set; }
public int PortNumber { get; set; }
public string UserFilter { get; set; }
public string LoginAttribute { get; set; }
public Dictionary<MappingFields, string> LdapMapping { get; set; }
//ToDo: use SId instead of group name
public Dictionary<AccessRight, string> AccessRights { get; set; }
public bool GroupMembership { get; set; }
// ReSharper disable once InconsistentNaming
public string GroupDN { get; set; }
public string UserAttribute { get; set; }
public string GroupFilter { get; set; }
public string GroupAttribute { get; set; }
public string GroupNameAttribute { get; set; }
public bool Authentication { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public bool AcceptCertificate { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<LdapSettings, LdapSettingsDto>();
}
}

View File

@ -0,0 +1,53 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.ApiModels.ResponseDto;
public class LdapStatusDto : IMapFrom<LdapOperationStatus>
{
public bool Completed { get; set; }
public string Id { get; set; }
public string Status { get; set; }
public string Error { get; set; }
public string Warning { get; set; }
public int Percents { get; set; }
public string CertificateConfirmRequest { get; set; }
public string Source { get; set; }
public string OperationType { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<LdapOperationStatus, LdapStatusDto>();
}
}

View File

@ -37,17 +37,20 @@ global using System.Text.Json.Serialization;
global using System.Text.RegularExpressions;
global using System.Web;
global using ASC.ActiveDirectory.Base;
global using ASC.ActiveDirectory.Base.Settings;
global using ASC.ActiveDirectory.ComplexOperations;
global using ASC.Api.Collections;
global using ASC.Api.Core;
global using ASC.Api.Core.Convention;
global using ASC.Api.Core.Extensions;
global using ASC.Api.Core.Extensions;
global using ASC.Api.Core.Security;
global using ASC.Api.Settings;
global using ASC.Api.Settings.Smtp;
global using ASC.Api.Utils;
global using ASC.AuditTrail;
global using ASC.AuditTrail.Mappers;
global using ASC.AuditTrail.Models;
global using ASC.AuditTrail.Models;
global using ASC.AuditTrail.Repositories;
global using ASC.AuditTrail.Types;
global using ASC.Common;
@ -85,11 +88,13 @@ global using ASC.FederatedLogin.Profile;
global using ASC.IPSecurity;
global using ASC.MessagingSystem.Core;
global using ASC.MessagingSystem.Models;
global using ASC.Notify.Cron;
global using ASC.Security.Cryptography;
global using ASC.Web.Api;
global using ASC.Web.Api.ApiModel.RequestsDto;
global using ASC.Web.Api.ApiModel.ResponseDto;
global using ASC.Web.Api.ApiModels.RequestsDto;
global using ASC.Web.Api.ApiModels.ResponseDto;
global using ASC.Web.Api.Core;
global using ASC.Web.Api.Log;
global using ASC.Web.Api.Models;
@ -137,6 +142,7 @@ global using Microsoft.Extensions.Options;
global using MimeKit;
global using static ASC.ActiveDirectory.Base.Settings.LdapSettings;
global using static ASC.Security.Cryptography.EmailValidationKeyProvider;
global using SecurityContext = ASC.Core.SecurityContext;

View File

@ -25,14 +25,19 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
var options = new WebApplicationOptions
{
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
var builder = WebApplication.CreateBuilder(options);
builder.Host.ConfigureDefault(args, configureServices: (hostContext, services, diHelper) =>
{
services.AddHostedService<LdapNotifyService>();
diHelper.TryAdd<LdapNotifyService>();
});
builder.Host.ConfigureDefault(args);
builder.WebHost.ConfigureDefaultKestrel();
var startup = new Startup(builder.Configuration, builder.Environment);

View File

@ -1,38 +1,38 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api;
public class Startup : BaseStartup
{
protected override bool ConfirmAddScheme { get => true; }
public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment) : base(configuration, hostEnvironment)
{
namespace ASC.Web.Api;
public class Startup : BaseStartup
{
protected override bool ConfirmAddScheme { get => true; }
public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment) : base(configuration, hostEnvironment)
{
}
}
}