Merge branch 'develop' into feature/create-from-modal

This commit is contained in:
TimofeyBoyko 2022-07-11 14:51:45 +03:00
commit 91ca312871
958 changed files with 28659 additions and 24794 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -39,20 +39,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Textile", "common\ASC.T
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.VoipService", "common\ASC.VoipService\ASC.VoipService.csproj", "{664031A4-1652-4B68-8168-FD18998700EE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Thumbnails.Svc", "common\services\ASC.Thumbnails.Svc\ASC.Thumbnails.Svc.csproj", "{920A59BF-8EFC-4E0F-82D8-935CC6FD570A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Studio.Notify", "common\services\ASC.Studio.Notify\ASC.Studio.Notify.csproj", "{C024C35A-D0F0-42D6-86B2-64ABF7513C4A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Notify", "common\services\ASC.Notify\ASC.Notify.csproj", "{B30A0D35-7B32-4E13-9F37-B8BC59F839E5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Feed.Aggregator", "common\services\ASC.Feed.Aggregator\ASC.Feed.Aggregator.csproj", "{8ACDEBBD-12DD-43DC-86CF-D66E37528ACC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Storage.Migration", "common\services\ASC.Data.Storage.Migration\ASC.Data.Storage.Migration.csproj", "{1E2A4FE7-5B61-4E76-B62A-3E9CC9FA647C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Backup", "common\services\ASC.Data.Backup\ASC.Data.Backup.csproj", "{630E2649-71B6-4C07-A2FC-C0BC05D77A78}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ApiSystem", "common\services\ASC.ApiSystem\ASC.ApiSystem.csproj", "{053AFC13-8EF6-43B6-9514-ED9DBBDC3093}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Web.Api", "web\ASC.Web.Api\ASC.Web.Api.csproj", "{D7C5E8A0-0A5E-4BC4-9946-B43D6682D421}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Web.Studio", "web\ASC.Web.Studio\ASC.Web.Studio.csproj", "{9BF17F6E-04A9-4597-9273-21AD09600329}"
@ -160,10 +154,6 @@ Global
{664031A4-1652-4B68-8168-FD18998700EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{664031A4-1652-4B68-8168-FD18998700EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{664031A4-1652-4B68-8168-FD18998700EE}.Release|Any CPU.Build.0 = Release|Any CPU
{920A59BF-8EFC-4E0F-82D8-935CC6FD570A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{920A59BF-8EFC-4E0F-82D8-935CC6FD570A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{920A59BF-8EFC-4E0F-82D8-935CC6FD570A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{920A59BF-8EFC-4E0F-82D8-935CC6FD570A}.Release|Any CPU.Build.0 = Release|Any CPU
{C024C35A-D0F0-42D6-86B2-64ABF7513C4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C024C35A-D0F0-42D6-86B2-64ABF7513C4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C024C35A-D0F0-42D6-86B2-64ABF7513C4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -176,18 +166,10 @@ Global
{8ACDEBBD-12DD-43DC-86CF-D66E37528ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8ACDEBBD-12DD-43DC-86CF-D66E37528ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8ACDEBBD-12DD-43DC-86CF-D66E37528ACC}.Release|Any CPU.Build.0 = Release|Any CPU
{1E2A4FE7-5B61-4E76-B62A-3E9CC9FA647C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E2A4FE7-5B61-4E76-B62A-3E9CC9FA647C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E2A4FE7-5B61-4E76-B62A-3E9CC9FA647C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E2A4FE7-5B61-4E76-B62A-3E9CC9FA647C}.Release|Any CPU.Build.0 = Release|Any CPU
{630E2649-71B6-4C07-A2FC-C0BC05D77A78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{630E2649-71B6-4C07-A2FC-C0BC05D77A78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{630E2649-71B6-4C07-A2FC-C0BC05D77A78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{630E2649-71B6-4C07-A2FC-C0BC05D77A78}.Release|Any CPU.Build.0 = Release|Any CPU
{053AFC13-8EF6-43B6-9514-ED9DBBDC3093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{053AFC13-8EF6-43B6-9514-ED9DBBDC3093}.Debug|Any CPU.Build.0 = Debug|Any CPU
{053AFC13-8EF6-43B6-9514-ED9DBBDC3093}.Release|Any CPU.ActiveCfg = Release|Any CPU
{053AFC13-8EF6-43B6-9514-ED9DBBDC3093}.Release|Any CPU.Build.0 = Release|Any CPU
{D7C5E8A0-0A5E-4BC4-9946-B43D6682D421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7C5E8A0-0A5E-4BC4-9946-B43D6682D421}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7C5E8A0-0A5E-4BC4-9946-B43D6682D421}.Release|Any CPU.ActiveCfg = Release|Any CPU

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,38 @@
const { join } = require("path");
const { readdirSync, readFileSync, writeFileSync } = require("fs");
const minifyJson = require("../../packages/asc-web-common/utils/minifyJson.js");
const localesDir = join(
__dirname,
"../../build",
"deploy",
"public",
"locales"
);
const getFileList = (dirName) => {
let files = [];
const items = readdirSync(dirName, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory()) {
files = [...files, ...getFileList(`${dirName}/${item.name}`)];
} else {
files.push(`${dirName}/${item.name}`);
}
}
return files;
};
const files = getFileList(localesDir);
files.forEach((filePath) => {
try {
let content = readFileSync(filePath);
writeFileSync(filePath, minifyJson(content, filePath));
//console.log(`File '${filePath}' minified`);
} catch (e) {
console.error("Unable to minify file ", filePath, e);
}
});

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

@ -203,8 +203,8 @@ public static class LogNLogConfigureExtenstion
if (!string.IsNullOrEmpty(settings.Dir))
{
loggerConfiguration.Variables["dir"] = CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, settings.Dir)
.TrimEnd('/').TrimEnd('\\') + Path.DirectorySeparatorChar;
var dir = Path.IsPathRooted(settings.Dir) ? settings.Dir : CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, settings.Dir);
loggerConfiguration.Variables["dir"] = dir.TrimEnd('/').TrimEnd('\\') + Path.DirectorySeparatorChar;
}
return loggerConfiguration;

View File

@ -61,8 +61,8 @@ public class CustomEndpointDataSource : EndpointDataSource
void AddEndpoints(IReadOnlyDictionary<string, object> defaults = null, RouteValueDictionary policies = null)
{
var order = constraintRouteAttr != null ? r.Order : r.Order + 2;
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order, r.Metadata, r.DisplayName));
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order - 1, r.Metadata, r.DisplayName));
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order + 1, r.Metadata, r.DisplayName));
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order, r.Metadata, r.DisplayName));
}
}).ToList();

View File

@ -24,6 +24,7 @@
// 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.Globalization;
global using System.Linq.Expressions;
@ -47,7 +48,8 @@ global using ASC.Api.Core.Core;
global using ASC.Api.Core.Extensions;
global using ASC.Api.Core.Log;
global using ASC.Api.Core.Middleware;
global using ASC.Api.Core.Routing;
global using ASC.Api.Core.Routing;
global using ASC.Api.Core.Security;
global using ASC.Common;
global using ASC.Common.Caching;
global using ASC.Common.DependencyInjection;
@ -67,7 +69,10 @@ global using ASC.Core.Users;
global using ASC.EventBus;
global using ASC.EventBus.Abstractions;
global using ASC.EventBus.RabbitMQ;
global using ASC.IPSecurity;
global using ASC.IPSecurity;
global using ASC.MessagingSystem.Core;
global using ASC.MessagingSystem.Data;
global using ASC.MessagingSystem.Models;
global using ASC.Security.Cryptography;
global using ASC.Web.Api.Routing;
global using ASC.Web.Core;
@ -79,6 +84,8 @@ global using ASC.Webhooks.Core;
global using Autofac;
global using Autofac.Extensions.DependencyInjection;
global using AutoMapper;
global using Confluent.Kafka;
global using HealthChecks.UI.Client;
@ -100,7 +107,8 @@ global using Microsoft.AspNetCore.Mvc.Routing;
global using Microsoft.AspNetCore.Routing;
global using Microsoft.AspNetCore.Routing.Constraints;
global using Microsoft.AspNetCore.Routing.Patterns;
global using Microsoft.AspNetCore.Server.Kestrel.Core;
global using Microsoft.AspNetCore.Server.Kestrel.Core;
global using Microsoft.AspNetCore.WebUtilities;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Diagnostics.HealthChecks;
@ -116,7 +124,7 @@ global using NLog;
global using NLog.Config;
global using NLog.Extensions.Logging;
global using RabbitMQ.Client;
global using RabbitMQ.Client;
global using StackExchange.Redis.Extensions.Core.Configuration;
global using StackExchange.Redis.Extensions.Newtonsoft;

View File

@ -43,7 +43,7 @@ public class PaymentFilter : IResourceFilter
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor
&& !controllerActionDescriptor.EndpointMetadata.OfType<AllowNotPaymentAttribute>().Any())
&& controllerActionDescriptor.EndpointMetadata.OfType<AllowNotPaymentAttribute>().Any())
{
_logger.DebugPaymentIsNotRequired();

View File

@ -55,6 +55,7 @@ public class EmployeeDtoHelper
private readonly ApiContext _httpContext;
private readonly DisplayUserSettingsHelper _displayUserSettingsHelper;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly ConcurrentDictionary<Guid, EmployeeDto> _concurrentDictionary;
public EmployeeDtoHelper(
ApiContext httpContext,
@ -67,12 +68,13 @@ public class EmployeeDtoHelper
_userManager = userManager;
_httpContext = httpContext;
_displayUserSettingsHelper = displayUserSettingsHelper;
_commonLinkUtility = commonLinkUtility;
_commonLinkUtility = commonLinkUtility;
_concurrentDictionary = new ConcurrentDictionary<Guid, EmployeeDto>();
}
public EmployeeDto Get(UserInfo userInfo)
{
return Init(new EmployeeDto(), userInfo);
return _concurrentDictionary.GetOrAdd(userInfo.Id, (id) => Init(new EmployeeDto(), userInfo));
}
public EmployeeDto Get(Guid userId)

View File

@ -0,0 +1,175 @@
// (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 static ASC.Security.Cryptography.EmailValidationKeyProvider;
namespace ASC.Api.Core.Security;
[Transient]
public class EmailValidationKeyModelHelper
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly EmailValidationKeyProvider _provider;
private readonly AuthContext _authContext;
private readonly UserManager _userManager;
private readonly AuthManager _authentication;
private readonly RoomInvitationLinksService _roomLinksService;
public EmailValidationKeyModelHelper(
IHttpContextAccessor httpContextAccessor,
EmailValidationKeyProvider provider,
AuthContext authContext,
UserManager userManager,
AuthManager authentication,
RoomInvitationLinksService roomLinksService)
{
_httpContextAccessor = httpContextAccessor;
_provider = provider;
_authContext = authContext;
_userManager = userManager;
_authentication = authentication;
_roomLinksService = roomLinksService;
}
public EmailValidationKeyModel GetModel()
{
var request = QueryHelpers.ParseQuery(_httpContextAccessor.HttpContext.Request.Headers["confirm"]);
request.TryGetValue("type", out var type);
ConfirmType? cType = null;
if (ConfirmTypeExtensions.TryParse(type, out var confirmType))
{
cType = confirmType;
}
request.TryGetValue("key", out var key);
request.TryGetValue("emplType", out var emplType);
EmployeeTypeExtensions.TryParse(emplType, out var employeeType);
request.TryGetValue("email", out var _email);
request.TryGetValue("uid", out var userIdKey);
Guid.TryParse(userIdKey, out var userId);
request.TryGetValue("access", out var fileShareRaw);
int.TryParse(fileShareRaw, out var fileShare);
request.TryGetValue("roomId", out var roomId);
return new EmailValidationKeyModel
{
Email = _email,
EmplType = employeeType,
Key = key,
Type = cType,
UiD = userId,
RoomAccess = fileShare,
RoomId = roomId
};
}
public ValidationResult Validate(EmailValidationKeyModel inDto)
{
var (key, emplType, email, uiD, type, fileShare, roomId) = inDto;
ValidationResult checkKeyResult;
switch (type)
{
case ConfirmType.EmpInvite:
checkKeyResult = _provider.ValidateEmailKey(email + type + (int)emplType, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.LinkInvite:
if (fileShare != default && !string.IsNullOrEmpty(roomId))
{
checkKeyResult = _provider.ValidateEmailKey(email + type + ((int)emplType + (int)fileShare + roomId), key, _provider.ValidEmailKeyInterval);
if (checkKeyResult == ValidationResult.Ok &&
!_roomLinksService.VisitProcess(roomId, email, key, _provider.ValidVisitLinkInterval))
{
checkKeyResult = ValidationResult.Expired;
}
break;
}
checkKeyResult = _provider.ValidateEmailKey(type.ToString() + (int)emplType, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.PortalOwnerChange:
checkKeyResult = _provider.ValidateEmailKey(email + type + uiD.HasValue, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.EmailChange:
checkKeyResult = _provider.ValidateEmailKey(email + type + _authContext.CurrentAccount.ID, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.PasswordChange:
var hash = _authentication.GetUserPasswordStamp(_userManager.GetUserByEmail(email).Id).ToString("s");
checkKeyResult = _provider.ValidateEmailKey(email + type + hash, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.Activation:
checkKeyResult = _provider.ValidateEmailKey(email + type + uiD, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.ProfileRemove:
// validate UiD
var user = _userManager.GetUsers(uiD.GetValueOrDefault());
if (user == null || user.Status == EmployeeStatus.Terminated || _authContext.IsAuthenticated && _authContext.CurrentAccount.ID != uiD)
{
return ValidationResult.Invalid;
}
checkKeyResult = _provider.ValidateEmailKey(email + type + uiD, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.Wizard:
checkKeyResult = _provider.ValidateEmailKey("" + type, key, _provider.ValidEmailKeyInterval);
break;
case ConfirmType.PhoneActivation:
case ConfirmType.PhoneAuth:
case ConfirmType.TfaActivation:
case ConfirmType.TfaAuth:
case ConfirmType.Auth:
checkKeyResult = _provider.ValidateEmailKey(email + type, key, _provider.ValidAuthKeyInterval);
break;
case ConfirmType.PortalContinue:
checkKeyResult = _provider.ValidateEmailKey(email + type, key);
break;
default:
checkKeyResult = _provider.ValidateEmailKey(email + type, key, _provider.ValidEmailKeyInterval);
break;
}
return checkKeyResult;
}
}

View File

@ -0,0 +1,124 @@
// (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.Api.Core.Security;
[Scope]
public class RoomInvitationLinksService
{
private readonly CommonLinkUtility _commonLinkUtility;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly MessageTarget _messageTarget;
private readonly UserManager _userManager;
private readonly Lazy<MessagesContext> _messagesContext;
private readonly MessageService _messageService;
public RoomInvitationLinksService(
CommonLinkUtility commonLinkUtility,
IHttpContextAccessor httpContextAccessor,
MessageTarget messageTarget,
UserManager userManager,
DbContextManager<MessagesContext> dbContextManager,
MessageService messageService)
{
_commonLinkUtility = commonLinkUtility;
_httpContextAccessor = httpContextAccessor;
_messageTarget = messageTarget;
_userManager = userManager;
_messagesContext = new Lazy<MessagesContext>(() => dbContextManager.Value);
_messageService = messageService;
}
public string GenerateLink<T>(T id, int fileShare, EmployeeType employeeType, Guid guid)
{
return GenerateLink(id, string.Empty, fileShare, employeeType, guid);
}
public string GenerateLink<T>(T id, string email, int fileShare, EmployeeType employeeType, Guid guid)
{
var user = _userManager.GetUserByEmail(email);
if (user != ASC.Core.Users.Constants.LostUser)
{
throw new Exception("The user with this email already exists");
}
var postifx = (int)employeeType + fileShare + id.ToString();
var link = _commonLinkUtility.GetConfirmationUrl(email, ConfirmType.LinkInvite, postifx, guid)
+ $"&emplType={employeeType:d}&roomId={id}&access={fileShare}";
return link;
}
public bool VisitProcess(string id, string email, string key, TimeSpan interval)
{
if (!string.IsNullOrEmpty(email))
{
var user = _userManager.GetUserByEmail(email);
if (user != ASC.Core.Users.Constants.LostUser)
{
return false;
}
}
var message = GetLinkInfo(id, email, key);
if (message == null)
{
SaveVisitLinkInfo(id, email, key);
return true;
}
return message.Date + interval > DateTime.UtcNow;
}
private void SaveVisitLinkInfo(string id, string email, string key)
{
var headers = _httpContextAccessor?.HttpContext?.Request?.Headers;
var target = _messageTarget.CreateFromGroupValues(email != null ? new[] { id, email } : new[] { id });
_messageService.Send(headers, MessageAction.RoomInviteLinkUsed, target, key);
}
private AuditEvent GetLinkInfo(string id, string email, string key)
{
var context = _messagesContext.Value;
var target = _messageTarget.CreateFromGroupValues(email != null ? new[] { id, email } : new[] { id });
var description = JsonConvert.SerializeObject(new[] { key },
new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc
});
var message = context.AuditEvents.Where(a => a.Target == target.ToString() &&
a.DescriptionRaw == description).FirstOrDefault();
return message;
}
}

View File

@ -45,6 +45,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="6.0.0" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
<PackageReference Include="EtaEmre.NetEscapades.EnumGenerators" Version="1.0.0-beta07" />
<!-- <PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="2.9.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -253,7 +253,7 @@ public class KafkaCacheNotify<T> : IDisposable, ICacheNotify<T> where T : IMessa
private string GetChannelName(CacheNotifyAction notifyAction)
{
return $"ascchannel{notifyAction}{typeof(T).FullName}".ToLower();
return $"ascchannel{notifyAction}{typeof(T).FullName}".ToLowerInvariant();
}
}

View File

@ -31,7 +31,7 @@ public class TempPath
{
private readonly string _tempFolder;
public TempPath(IConfiguration configuration)
public TempPath(IHostEnvironment hostEnvironment, IConfiguration configuration)
{
var rootFolder = AppContext.BaseDirectory;
if (string.IsNullOrEmpty(rootFolder))
@ -39,7 +39,7 @@ public class TempPath
rootFolder = Assembly.GetEntryAssembly().Location;
}
_tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
_tempFolder = configuration["web:temp"] ?? CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, "temp");
if (!Path.IsPathRooted(_tempFolder))
{
_tempFolder = Path.GetFullPath(Path.Combine(rootFolder, _tempFolder));
@ -56,7 +56,7 @@ public class TempPath
return _tempFolder;
}
public string GetTempFileName()
public string GetTempFileName(string ext = "")
{
FileStream f = null;
string path;
@ -66,6 +66,11 @@ public class TempPath
{
path = Path.Combine(_tempFolder, Path.GetRandomFileName());
if (!string.IsNullOrEmpty(ext))
{
path = Path.ChangeExtension(path, ext);
}
try
{
using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))

View File

@ -54,7 +54,12 @@ public class TempStream
public Stream Create()
{
return new FileStream(_tempPath.GetTempFileName(), FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
return Create(out _);
}
public Stream Create(out string path, string ext = "")
{
path = _tempPath.GetTempFileName(ext);
return new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
}

View File

@ -36,7 +36,7 @@ global using System.Runtime.CompilerServices;
global using System.Runtime.Loader;
global using System.Runtime.Serialization;
global using System.Security.Cryptography;
global using System.Security.Principal;
global using System.Security.Principal;
global using System.ServiceModel;
global using System.Text;
global using System.Text.RegularExpressions;
@ -86,11 +86,14 @@ global using Microsoft.Extensions.Caching.Memory;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using Microsoft.Extensions.Primitives;
global using Microsoft.Net.Http.Headers;
global using NetEscapades.EnumGenerators;
global using Newtonsoft.Json;
global using Newtonsoft.Json.Serialization;

View File

@ -29,11 +29,11 @@ namespace ASC.Common.Logging;
[Singletone]
public class EFLoggerFactory : ILoggerFactory
{
private readonly ILoggerProvider _loggerProvider;
private readonly ILogger _logger;
public EFLoggerFactory(ILoggerProvider loggerProvider)
{
_loggerProvider = loggerProvider;
_logger = new EFLogger(loggerProvider.CreateLogger("ASC.SQL"));
}
public void AddProvider(ILoggerProvider provider)
@ -42,7 +42,7 @@ public class EFLoggerFactory : ILoggerFactory
public ILogger CreateLogger(string categoryName)
{
return new EFLogger(_loggerProvider.CreateLogger("ASC.SQL"));
return _logger;
}
public void Dispose() { }

View File

@ -26,6 +26,7 @@
namespace ASC.Common.Security.Authorizing;
[EnumExtensions]
public enum AceType
{
Allow,

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

@ -181,7 +181,7 @@ public static class HttpRequestExtensions
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress?.ToString();
}
private static Uri ParseRewriterUrl(string s)

View File

@ -33,6 +33,7 @@ public class CoreBaseSettings
private string _basedomain;
private bool? _personal;
private bool? _customMode;
private bool? _disableDocSpace;
private IConfiguration Configuration { get; }
@ -61,6 +62,8 @@ public class CoreBaseSettings
_personal ?? (bool)(_personal = string.Equals(Configuration["core:personal"], "true", StringComparison.OrdinalIgnoreCase));
public bool CustomMode => _customMode ?? (bool)(_customMode = string.Equals(Configuration["core:custom-mode"], "true", StringComparison.OrdinalIgnoreCase));
public bool DisableDocSpace => _disableDocSpace ?? (bool)(_disableDocSpace = string.Equals(Configuration["core:disableDocspace"], "true", StringComparison.OrdinalIgnoreCase));
}
class ConfigureCoreSettings : IConfigureNamedOptions<CoreSettings>

View File

@ -718,6 +718,11 @@ public class UserManager
group = ToGroup(Constants.BuildinGroups.FirstOrDefault(r => r.ID == groupID) ?? Constants.LostGroupInfo);
}
if (group == null)
{
return Constants.LostGroupInfo;
}
return new GroupInfo
{
ID = group.Id,

View File

@ -70,7 +70,7 @@ public class AzRecord : IMapFrom<Acl>
result.Object = cache.ObjectId;
if (Enum.TryParse<AceType>(cache.Reaction, out var reaction))
if (AceTypeExtensions.TryParse(cache.Reaction, out var reaction))
{
result.AceType = reaction;
}

View File

@ -31,6 +31,7 @@ namespace ASC.Core.Users;
[Flags]
[JsonConverter(typeof(JsonStringEnumConverter))]
[EnumExtensions]
public enum EmployeeType
{
All = 0,

View File

@ -73,7 +73,7 @@ public class UserGroupRef : IMapFrom<UserGroup>
GroupId = new Guid(cache.GroupId)
};
if (Enum.TryParse<UserGroupRefType>(cache.RefType, out var refType))
if (UserGroupRefTypeExtensions.TryParse(cache.RefType, out var refType))
{
result.RefType = refType;
}

View File

@ -26,6 +26,7 @@
namespace ASC.Core;
[EnumExtensions]
public enum UserGroupRefType
{
Contains,

View File

@ -34,7 +34,7 @@ global using System.Diagnostics;
global using System.Globalization;
global using System.Linq;
global using System.Linq.Expressions;
global using System.Net;
global using System.Net;
global using System.Net.Http.Headers;
global using System.Reflection;
global using System.Resources;
@ -148,6 +148,8 @@ global using Microsoft.Extensions.Options;
global using MimeKit;
global using NetEscapades.EnumGenerators;
global using Newtonsoft.Json;
global using NVelocity;

View File

@ -32,17 +32,26 @@ public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHos
private readonly ILogger _logger;
private readonly IHostApplicationLifetime _applicationLifetime;
private readonly IServiceProvider _serviceProvider;
private readonly int _intervalCheckRegisterInstanceInSeconds;
public static readonly string InstanceId =
$"{typeof(T).GetFormattedName()}_{DateTime.UtcNow.Ticks}";
public RegisterInstanceWorkerService(
ILogger<RegisterInstanceWorkerService<T>> logger,
IServiceProvider serviceProvider,
IHostApplicationLifetime applicationLifetime)
IHostApplicationLifetime applicationLifetime,
IConfiguration configuration)
{
_logger = logger;
_serviceProvider = serviceProvider;
_applicationLifetime = applicationLifetime;
_applicationLifetime = applicationLifetime;
if (!int.TryParse(configuration["core:hosting:intervalCheckRegisterInstanceInSeconds"], out _intervalCheckRegisterInstanceInSeconds))
{
_intervalCheckRegisterInstanceInSeconds = 1;
}
_intervalCheckRegisterInstanceInSeconds = _intervalCheckRegisterInstanceInSeconds*1000;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
@ -50,7 +59,7 @@ public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHos
while (!stoppingToken.IsCancellationRequested)
{
try
{
{
using var scope = _serviceProvider.CreateScope();
var registerInstanceService = scope.ServiceProvider.GetService<IRegisterInstanceManager<T>>();
@ -60,7 +69,7 @@ public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHos
_logger.TraceWorkingRunnging(DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
await Task.Delay(_intervalCheckRegisterInstanceInSeconds, stoppingToken);
}
catch (Exception ex)
{

View File

@ -33,6 +33,7 @@ public class AuditEvent : MessageEvent, IMapFrom<EventMessage>
public void Mapping(Profile profile)
{
profile.CreateMap<MessageEvent, AuditEvent>();
profile.CreateMap<EventMessage, AuditEvent>()
.ConvertUsing<EventTypeConverter>();
}

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@ public class MessageTarget
};
}
public MessageTarget Create(IEnumerable<string> value)
public MessageTarget CreateFromGroupValues(IEnumerable<string> value)
{
var res = new MessageTarget(_option)
{

View File

@ -74,7 +74,7 @@ public class DispatchEngine
}
else if (response.Result == SendResult.Impossible)
{
_logger.LogErrorResponceWithException( message.Subject, message.Recipient, senderName, response.Result, response.Exception);
_logger.LogErrorResponceWithException(message.Subject, message.Recipient, senderName, response.Result, response.Exception);
}
else
{

View File

@ -281,6 +281,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
catch (Exception exc)
{
directresponses.Add(new SendResponse(request.NotifyAction, request.Recipient, exc));
_logger.ErrorWithException(exc);
}
responces.AddRange(directresponses);
@ -312,6 +313,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
catch (Exception exc)
{
responces.Add(new SendResponse(request.NotifyAction, request.Recipient, exc));
_logger.ErrorWithException(exc);
}
}
}
@ -349,10 +351,10 @@ public class NotifyEngine : INotifyEngine, IDisposable
}
try
{
{
PrepareRequestFillSenders(request, serviceScope);
PrepareRequestFillPatterns(request, serviceScope);
PrepareRequestFillTags(request, serviceScope);
PrepareRequestFillTags(request, serviceScope);
}
catch (Exception ex)
{
@ -369,11 +371,12 @@ public class NotifyEngine : INotifyEngine, IDisposable
{
try
{
response = SendDirectNotify(request, channel, serviceScope);
response = SendDirectNotify(request, channel, serviceScope);
}
catch (Exception exc)
{
response = new SendResponse(request.NotifyAction, channel.SenderName, request.Recipient, exc);
_logger.ErrorWithException(exc);
}
}
else
@ -410,11 +413,11 @@ public class NotifyEngine : INotifyEngine, IDisposable
request.CurrentMessage = noticeMessage;
var preventresponse = CheckPreventInterceptors(request, InterceptorPlace.MessageSend, serviceScope, channel.SenderName);
if (preventresponse != null)
{
return preventresponse;
}
if (preventresponse != null)
{
return preventresponse;
}
channel.SendAsync(noticeMessage);
return new SendResponse(noticeMessage, channel.SenderName, SendResult.Inprogress);
@ -661,7 +664,7 @@ public class NotifyEngine : INotifyEngine, IDisposable
}
}
[Scope]
[Singletone]
public class NotifyEngineQueue
{
private readonly NotifyEngine _notifyEngine;

View File

@ -35,11 +35,13 @@ public class EmailValidationKeyProvider
Invalid,
Expired
}
public TimeSpan ValidEmailKeyInterval { get; }
public TimeSpan ValidAuthKeyInterval { get; }
public TimeSpan ValidVisitLinkInterval { get; }
private readonly ILogger<EmailValidationKeyProvider> _logger;
private static readonly DateTime _from = new DateTime(2010, 01, 01, 0, 0, 0, DateTimeKind.Utc);
internal readonly TimeSpan _validEmailKeyInterval;
internal readonly TimeSpan _validAuthKeyInterval;
private readonly MachinePseudoKeys _machinePseudoKeys;
private readonly TenantManager _tenantManager;
@ -55,9 +57,13 @@ public class EmailValidationKeyProvider
{
authValidInterval = TimeSpan.FromHours(1);
}
_validEmailKeyInterval = validInterval;
_validAuthKeyInterval = authValidInterval;
if (!TimeSpan.TryParse(configuration["visit:validinterval"], out var validVisitLinkInterval))
{
ValidVisitLinkInterval = TimeSpan.FromMinutes(15);
}
ValidEmailKeyInterval = validInterval;
ValidAuthKeyInterval = authValidInterval;
_logger = logger;
}
@ -162,133 +168,11 @@ public class EmailValidationKeyModel
public string Email { get; set; }
public Guid? UiD { get; set; }
public ConfirmType? Type { get; set; }
public int RoomAccess { get; set; }
public string RoomId { get; set; }
public void Deconstruct(out string key, out EmployeeType? emplType, out string email, out Guid? uiD, out ConfirmType? type)
public void Deconstruct(out string key, out EmployeeType? emplType, out string email, out Guid? uiD, out ConfirmType? type, out int roomAccess, out string roomId)
{
(key, emplType, email, uiD, type) = (Key, EmplType, Email, UiD, Type);
(key, emplType, email, uiD, type, roomAccess, roomId) = (Key, EmplType, Email, UiD, Type, RoomAccess, RoomId);
}
}
[Transient]
public class EmailValidationKeyModelHelper
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly EmailValidationKeyProvider _provider;
private readonly AuthContext _authContext;
private readonly UserManager _userManager;
private readonly AuthManager _authentication;
public EmailValidationKeyModelHelper(
IHttpContextAccessor httpContextAccessor,
EmailValidationKeyProvider provider,
AuthContext authContext,
UserManager userManager,
AuthManager authentication)
{
_httpContextAccessor = httpContextAccessor;
_provider = provider;
_authContext = authContext;
_userManager = userManager;
_authentication = authentication;
}
public EmailValidationKeyModel GetModel()
{
var request = QueryHelpers.ParseQuery(_httpContextAccessor.HttpContext.Request.Headers["confirm"]);
request.TryGetValue("type", out var type);
ConfirmType? cType = null;
if (Enum.TryParse<ConfirmType>(type, out var confirmType))
{
cType = confirmType;
}
request.TryGetValue("key", out var key);
request.TryGetValue("emplType", out var emplType);
Enum.TryParse<EmployeeType>(emplType, out var employeeType);
request.TryGetValue("email", out var _email);
request.TryGetValue("uid", out var userIdKey);
Guid.TryParse(userIdKey, out var userId);
return new EmailValidationKeyModel
{
Email = _email,
EmplType = employeeType,
Key = key,
Type = cType,
UiD = userId
};
}
public ValidationResult Validate(EmailValidationKeyModel inDto)
{
var (key, emplType, email, uiD, type) = inDto;
ValidationResult checkKeyResult;
switch (type)
{
case ConfirmType.EmpInvite:
checkKeyResult = _provider.ValidateEmailKey(email + type + (int)emplType, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.LinkInvite:
checkKeyResult = _provider.ValidateEmailKey(type.ToString() + (int)emplType, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.PortalOwnerChange:
checkKeyResult = _provider.ValidateEmailKey(email + type + uiD.HasValue, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.EmailChange:
checkKeyResult = _provider.ValidateEmailKey(email + type + _authContext.CurrentAccount.ID, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.PasswordChange:
var hash = _authentication.GetUserPasswordStamp(_userManager.GetUserByEmail(email).Id).ToString("s");
checkKeyResult = _provider.ValidateEmailKey(email + type + hash, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.Activation:
checkKeyResult = _provider.ValidateEmailKey(email + type + uiD, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.ProfileRemove:
// validate UiD
var user = _userManager.GetUsers(uiD.GetValueOrDefault());
if (user == null || user.Status == EmployeeStatus.Terminated || _authContext.IsAuthenticated && _authContext.CurrentAccount.ID != uiD)
{
return ValidationResult.Invalid;
}
checkKeyResult = _provider.ValidateEmailKey(email + type + uiD, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.Wizard:
checkKeyResult = _provider.ValidateEmailKey("" + type, key, _provider._validEmailKeyInterval);
break;
case ConfirmType.PhoneActivation:
case ConfirmType.PhoneAuth:
case ConfirmType.TfaActivation:
case ConfirmType.TfaAuth:
case ConfirmType.Auth:
checkKeyResult = _provider.ValidateEmailKey(email + type, key, _provider._validAuthKeyInterval);
break;
case ConfirmType.PortalContinue:
checkKeyResult = _provider.ValidateEmailKey(email + type, key);
break;
default:
checkKeyResult = _provider.ValidateEmailKey(email + type, key, _provider._validEmailKeyInterval);
break;
}
return checkKeyResult;
}
}
}

View File

@ -35,6 +35,7 @@ namespace ASC.Web.Studio.Utility;
// portal-remove - confirm portal deletation - Tenant.SetStatus(TenantStatus.RemovePending)
// DnsChange - change Portal Address and/or Custom domain name
[JsonConverter(typeof(JsonStringEnumConverter))]
[EnumExtensions]
public enum ConfirmType
{
EmpInvite,
@ -54,5 +55,5 @@ public enum ConfirmType
Auth,
TfaActivation,
TfaAuth,
Wizard
Wizard,
}

View File

@ -41,7 +41,7 @@ public class DarkThemeSettings : ISettings<DarkThemeSettings>
{
return new DarkThemeSettings
{
Theme = DarkThemeSettingsEnum.Base,
Theme = DarkThemeSettingsEnum.System,
};
}
}

View File

@ -51,5 +51,8 @@
<EmbeddedResource Update="BackupResource.tr.resx">
<DependentUpon>BackupResource.resx</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="BackupResource.az.resx">
<DependentUpon>BackupResource.resx</DependentUpon>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -22,7 +22,7 @@ namespace ASC.Data.Backup.Core {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class BackupResource {
public class BackupResource {
private static global::System.Resources.ResourceManager resourceMan;
@ -36,7 +36,7 @@ namespace ASC.Data.Backup.Core {
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Data.Backup.Core.BackupResource", typeof(BackupResource).Assembly);
@ -51,7 +51,7 @@ namespace ASC.Data.Backup.Core {
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@ -63,7 +63,7 @@ namespace ASC.Data.Backup.Core {
/// <summary>
/// Looks up a localized string similar to The backup file is invalid. Please, use a file created in ONLYOFFICE v11.5 or later..
/// </summary>
internal static string BackupNotFound {
public static string BackupNotFound {
get {
return ResourceManager.GetString("BackupNotFound", resourceCulture);
}
@ -72,7 +72,7 @@ namespace ASC.Data.Backup.Core {
/// <summary>
/// Looks up a localized string similar to Set Password.
/// </summary>
internal static string ButtonSetPassword {
public static string ButtonSetPassword {
get {
return ResourceManager.GetString("ButtonSetPassword", resourceCulture);
}

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BackupNotFound" xml:space="preserve">
<value>Yedək faylı etibarsızdır. ONLYOFFICE v11.5 və ya daha yeni versiyada yaradılmış fayldan istifadə edin.</value>
</data>
</root>

View File

@ -1,67 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BackupNotFound" xml:space="preserve">
<value>The backup file is invalid. Please, use a file created in ONLYOFFICE v11.5 or later.</value>
</data>
<data name="ButtonSetPassword" xml:space="preserve">
<value>Set Password</value>
</data>
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BackupNotFound" xml:space="preserve">
<value>The backup file is invalid. Please, use a file created in ONLYOFFICE v11.5 or later.</value>
</data>
<data name="ButtonSetPassword" xml:space="preserve">
<value>Set Password</value>
</data>
</root>

View File

@ -43,7 +43,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="openstack.net" Version="1.8.0" />
<PackageReference Include="Rackspace" Version="1.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -77,21 +77,21 @@ public class CommonChunkedUploadSession : ICloneable
public T GetItemOrDefault<T>(string key)
{
if (Items.ContainsKey(key) && Items[key] != null)
{
if (Items[key] is T)
{
return (T)Items[key];
}
var jToken = Items[key] as Newtonsoft.Json.Linq.JToken;
if (jToken != null)
{
var item = jToken.ToObject<T>();
Items[key] = item;
return item;
}
}
if (Items.ContainsKey(key) && Items[key] != null)
{
if (Items[key] is T)
{
return (T)Items[key];
}
var jToken = Items[key] as Newtonsoft.Json.Linq.JToken;
if (jToken != null)
{
var item = jToken.ToObject<T>();
Items[key] = item;
return item;
}
}
return default(T);
}
@ -111,17 +111,21 @@ public class CommonChunkedUploadSession : ICloneable
if (item.Value is JsonElement)
{
var value = (JsonElement)item.Value;
if (value.ValueKind == JsonValueKind.String)
switch (value.ValueKind)
{
case JsonValueKind.String:
newItems.Add(item.Key, item.Value.ToString());
}
if (value.ValueKind == JsonValueKind.Number)
{
newItems.Add(item.Key, Int32.Parse(item.Value.ToString()));
}
if (value.ValueKind == JsonValueKind.Array)
{
break;
case JsonValueKind.Number:
newItems.Add(item.Key, Int32.Parse(item.Value.ToString()));
break;
case JsonValueKind.Array:
newItems.Add(item.Key, value.EnumerateArray().Select(o => o.ToString()).ToList());
break;
default:
newItems.Add(item.Key, item.Value);
break;
}
}
else

View File

@ -140,13 +140,18 @@ public class DiscDataStore : BaseStorage
{
return SaveAsync(domain, path, stream);
}
private bool EnableQuotaCheck(string domain)
{
return (QuotaController != null) && !domain.EndsWith("_temp");
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream)
{
Logger.DebugSavePath(path);
var buffered = _tempStream.GetBuffered(stream);
if (QuotaController != null)
if (EnableQuotaCheck(domain))
{
QuotaController.QuotaUsedCheck(buffered.Length);
}

View File

@ -27,6 +27,7 @@
global using System.Collections.Concurrent;
global using System.Globalization;
global using System.Net;
global using System.Net.Http.Headers;
global using System.Runtime.Serialization;
global using System.Security.Cryptography;
global using System.ServiceModel;
@ -89,4 +90,4 @@ global using ProtoBuf;
global using static Google.Cloud.Storage.V1.UrlSigner;
global using MimeMapping = ASC.Common.Web.MimeMapping;
global using MimeMapping = ASC.Common.Web.MimeMapping;

Some files were not shown because too many files have changed in this diff Show More