DocSpace-buildtools/common/ASC.ActiveDirectory/ComplexOperations/LdapOperationJob.cs
2022-04-26 17:03:41 +03:00

1401 lines
50 KiB
C#

using Constants = ASC.Core.Users.Constants;
using SecurityContext = ASC.Core.SecurityContext;
namespace ASC.ActiveDirectory.ComplexOperations;
[Transient(Additional = typeof(LdapOperationExtension))]
public class LdapOperationJob : DistributedTaskProgress
{
private string _culture;
public LdapSettings LDAPSettings { get; private set; }
protected DistributedTask TaskInfo { get; private set; }
protected string Source { get; private set; }
protected new string Status { get; set; }
protected string Error { get; set; }
protected string Warning { get; set; }
private int? _tenantId;
public int TenantId
{
get
{
return _tenantId ?? GetProperty<int>(nameof(_tenantId));
}
set
{
_tenantId = value;
SetProperty(nameof(_tenantId), value);
}
}
public LdapOperationType OperationType { get; private set; }
public static LdapLocalization Resource { get; private set; }
private readonly TenantManager _tenantManager;
private readonly SecurityContext _securityContext;
private readonly LdapUserManager _lDAPUserManager;
private readonly NovellLdapHelper _novellLdapHelper;
private readonly LdapUserImporter _ldapUserImporter;
private readonly LdapChangeCollection _ldapChanges;
private readonly UserFormatter _userFormatter;
private readonly SettingsManager _settingsManager;
private readonly UserPhotoManager _userPhotoManager;
private readonly WebItemSecurity _webItemSecurity;
private readonly UserManager _userManager;
private readonly DisplayUserSettingsHelper _displayUserSettingsHelper;
private readonly NovellLdapSettingsChecker _novellLdapSettingsChecker;
private readonly ILog _log;
private UserInfo _currentUser;
public LdapOperationJob(
TenantManager tenantManager,
SecurityContext securityContext,
LdapUserManager ldapUserManager,
NovellLdapHelper novellLdapHelper,
NovellLdapUserImporter novellLdapUserImporter,
LdapChangeCollection ldapChanges,
UserFormatter userFormatter,
SettingsManager settingsManager,
UserPhotoManager userPhotoManager,
WebItemSecurity webItemSecurity,
UserManager userManager,
DisplayUserSettingsHelper displayUserSettingsHelper,
NovellLdapSettingsChecker novellLdapSettingsChecker,
IOptionsMonitor<ILog> options)
{
_tenantManager = tenantManager;
_securityContext = securityContext;
_lDAPUserManager = ldapUserManager;
_novellLdapHelper = novellLdapHelper;
_ldapUserImporter = novellLdapUserImporter;
_ldapChanges = ldapChanges;
_userFormatter = userFormatter;
_settingsManager = settingsManager;
_userPhotoManager = userPhotoManager;
_webItemSecurity = webItemSecurity;
_userManager = userManager;
_displayUserSettingsHelper = displayUserSettingsHelper;
_novellLdapSettingsChecker = novellLdapSettingsChecker;
_log = options.Get("ASC");
}
public void InitJob(
LdapSettings settings,
Tenant tenant,
LdapOperationType operationType,
LdapLocalization resource,
string userId)
{
_currentUser = userId != null ? _userManager.GetUsers(Guid.Parse(userId)) : null;
_tenantId = tenant.TenantId;
_tenantManager.SetCurrentTenant(tenant);
_ldapChanges.Tenant = tenant;
OperationType = operationType;
_culture = Thread.CurrentThread.CurrentCulture.Name;
LDAPSettings = settings;
Source = "";
Percentage = 0;
Status = "";
Error = "";
Warning = "";
Source = "";
Resource = resource ?? new LdapLocalization();
_lDAPUserManager.Init(Resource);
}
protected override void DoJob()
{
try
{
FillDistributedTask();
_securityContext.AuthenticateMe(Core.Configuration.Constants.CoreSystem);
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(_culture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(_culture);
if (LDAPSettings == null)
{
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
_log.Error("Can't save default LDAP settings.");
return;
}
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.SaveTest:
_log.InfoFormat("Start '{0}' operation",
Enum.GetName(typeof(LdapOperationType), OperationType));
SetProgress(1, Resource.LdapSettingsStatusCheckingLdapSettings);
_log.Debug("PrepareSettings()");
PrepareSettings(LDAPSettings);
if (!string.IsNullOrEmpty(Error))
{
_log.DebugFormat("PrepareSettings() Error: {0}", Error);
return;
}
_ldapUserImporter.Init(LDAPSettings, Resource);
if (LDAPSettings.EnableLdapAuthentication)
{
_novellLdapSettingsChecker.Init(_ldapUserImporter);
SetProgress(5, Resource.LdapSettingsStatusLoadingBaseInfo);
var result = _novellLdapSettingsChecker.CheckSettings();
if (result != LdapSettingsStatus.Ok)
{
if (result == LdapSettingsStatus.CertificateRequest)
{
SetProperty(LdapTaskProperty.CERT_REQUEST,
_novellLdapSettingsChecker.CertificateConfirmRequest);
}
Error = GetError(result);
_log.DebugFormat("ldapSettingsChecker.CheckSettings() Error: {0}", Error);
return;
}
}
break;
case LdapOperationType.Sync:
case LdapOperationType.SyncTest:
_log.InfoFormat("Start '{0}' operation",
Enum.GetName(typeof(LdapOperationType), OperationType));
_ldapUserImporter.Init(LDAPSettings, Resource);
break;
default:
throw new ArgumentOutOfRangeException();
}
Do();
}
catch (AuthorizingException authError)
{
Error = Resource.ErrorAccessDenied;
_log.Error(Error, new SecurityException(Error, authError));
}
catch (AggregateException ae)
{
ae.Flatten().Handle(e => e is TaskCanceledException || e is OperationCanceledException);
}
catch (TenantQuotaException e)
{
Error = Resource.LdapSettingsTenantQuotaSettled;
_log.ErrorFormat("TenantQuotaException. {0}", e);
}
catch (FormatException e)
{
Error = Resource.LdapSettingsErrorCantCreateUsers;
_log.ErrorFormat("FormatException error. {0}", e);
}
catch (Exception e)
{
Error = Resource.LdapSettingsInternalServerError;
_log.ErrorFormat("Internal server error. {0}", e);
}
finally
{
try
{
SetProperty(LdapTaskProperty.FINISHED, true);
PublishChanges();
_securityContext.Logout();
}
catch (Exception ex)
{
_log.ErrorFormat("LdapOperation finalization problem. {0}", ex);
}
}
}
private void Do()
{
try
{
if (OperationType == LdapOperationType.Save)
{
SetProgress(10, Resource.LdapSettingsStatusSavingSettings);
LDAPSettings.IsDefault = LDAPSettings.Equals(LDAPSettings.GetDefault(null));
if (!_settingsManager.Save(LDAPSettings))
{
_log.Error("Can't save LDAP settings.");
Error = Resource.LdapSettingsErrorCantSaveLdapSettings;
return;
}
}
if (LDAPSettings.EnableLdapAuthentication)
{
if (_log.IsDebugEnabled)
{
var sb = new StringBuilder();
sb.AppendLine("SyncLDAP()");
sb.AppendLine(string.Format("Server: {0}:{1}", LDAPSettings.Server, LDAPSettings.PortNumber));
sb.AppendLine("UserDN: " + LDAPSettings.UserDN);
sb.AppendLine("LoginAttr: " + LDAPSettings.LoginAttribute);
sb.AppendLine("UserFilter: " + LDAPSettings.UserFilter);
sb.AppendLine("Groups: " + LDAPSettings.GroupMembership);
if (LDAPSettings.GroupMembership)
{
sb.AppendLine("GroupDN: " + LDAPSettings.GroupDN);
sb.AppendLine("UserAttr: " + LDAPSettings.UserAttribute);
sb.AppendLine("GroupFilter: " + LDAPSettings.GroupFilter);
sb.AppendLine("GroupName: " + LDAPSettings.GroupNameAttribute);
sb.AppendLine("GroupMember: " + LDAPSettings.GroupAttribute);
}
_log.Debug(sb.ToString());
}
SyncLDAP();
if (!string.IsNullOrEmpty(Error))
return;
}
else
{
_log.Debug("TurnOffLDAP()");
TurnOffLDAP();
var ldapCurrentUserPhotos = _settingsManager.Load<LdapCurrentUserPhotos>().GetDefault(null);
_settingsManager.Save(ldapCurrentUserPhotos);
var ldapCurrentAcccessSettings = _settingsManager.Load<LdapCurrentAcccessSettings>().GetDefault(null);
_settingsManager.Save(ldapCurrentAcccessSettings);
//не снимать права при выключении
//var rights = new List<LdapSettings.AccessRight>();
//TakeUsersRights(rights);
//if (rights.Count > 0)
//{
// Warning = Resource.LdapSettingsErrorLostRights;
//}
}
}
catch (NovellLdapTlsCertificateRequestedException ex)
{
_log.ErrorFormat(
"CheckSettings(acceptCertificate={0}, cert thumbprint: {1}): NovellLdapTlsCertificateRequestedException: {2}",
LDAPSettings.AcceptCertificate, LDAPSettings.AcceptCertificateHash, ex.ToString());
Error = Resource.LdapSettingsStatusCertificateVerification;
//TaskInfo.SetProperty(CERT_REQUEST, ex.CertificateConfirmRequest);
}
catch (TenantQuotaException e)
{
_log.ErrorFormat("TenantQuotaException. {0}", e.ToString());
Error = Resource.LdapSettingsTenantQuotaSettled;
}
catch (FormatException e)
{
_log.ErrorFormat("FormatException error. {0}", e.ToString());
Error = Resource.LdapSettingsErrorCantCreateUsers;
}
catch (Exception e)
{
_log.ErrorFormat("Internal server error. {0}", e.ToString());
Error = Resource.LdapSettingsInternalServerError;
}
finally
{
SetProgress(99, Resource.LdapSettingsStatusDisconnecting, "");
}
SetProgress(100, OperationType == LdapOperationType.SaveTest ||
OperationType == LdapOperationType.SyncTest
? JsonSerializer.Serialize(_ldapChanges)
: "", "");
}
private void TurnOffLDAP()
{
const double percents = 48;
SetProgress((int)percents, Resource.LdapSettingsModifyLdapUsers);
var existingLDAPUsers = _userManager.GetUsers(EmployeeStatus.All).Where(u => u.Sid != null).ToList();
var step = percents / existingLDAPUsers.Count;
var percentage = GetProgress();
var index = 0;
var count = existingLDAPUsers.Count;
foreach (var existingLDAPUser in existingLDAPUsers)
{
SetProgress(Convert.ToInt32(percentage),
currentSource:
string.Format("({0}/{1}): {2}", ++index, count,
_userFormatter.GetUserName(existingLDAPUser, DisplayUserNameFormat.Default)));
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
existingLDAPUser.Sid = null;
existingLDAPUser.ConvertExternalContactsToOrdinary();
_log.DebugFormat("CoreContext.UserManager.SaveUserInfo({0})", existingLDAPUser.GetUserInfoString());
_userManager.SaveUserInfo(existingLDAPUser);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
_ldapChanges.SetSaveAsPortalUserChange(existingLDAPUser);
break;
default:
throw new ArgumentOutOfRangeException();
}
percentage += step;
}
}
private void SyncLDAP()
{
var currentDomainSettings = _settingsManager.Load<LdapCurrentDomain>();
if (string.IsNullOrEmpty(currentDomainSettings.CurrentDomain) || currentDomainSettings.CurrentDomain != _ldapUserImporter.LDAPDomain)
{
currentDomainSettings.CurrentDomain = _ldapUserImporter.LDAPDomain;
_settingsManager.Save(currentDomainSettings);
}
if (!LDAPSettings.GroupMembership)
{
_log.Debug("SyncLDAPUsers()");
SyncLDAPUsers();
}
else
{
_log.Debug("SyncLDAPUsersInGroups()");
SyncLDAPUsersInGroups();
}
SyncLdapAvatar();
SyncLdapAccessRights();
}
private void SyncLdapAvatar()
{
SetProgress(90, Resource.LdapSettingsStatusUpdatingUserPhotos);
if (!LDAPSettings.LdapMapping.ContainsKey(LdapSettings.MappingFields.AvatarAttribute))
{
var ph = _settingsManager.Load<LdapCurrentUserPhotos>();
if (ph.CurrentPhotos == null || !ph.CurrentPhotos.Any())
{
return;
}
foreach (var guid in ph.CurrentPhotos.Keys)
{
_log.InfoFormat("SyncLdapAvatar() Removing photo for '{0}'", guid);
_userPhotoManager.RemovePhoto(guid);
_userPhotoManager.ResetThumbnailSettings(guid);
}
ph.CurrentPhotos = null;
_settingsManager.Save(ph);
return;
}
var photoSettings = _settingsManager.Load<LdapCurrentUserPhotos>();
if (photoSettings.CurrentPhotos == null)
{
photoSettings.CurrentPhotos = new Dictionary<Guid, string>();
}
var ldapUsers = _ldapUserImporter.AllDomainUsers.Where(x => !x.IsDisabled);
var step = 5.0 / ldapUsers.Count();
var currentPercent = 90.0;
foreach (var ldapUser in ldapUsers)
{
var image = ldapUser.GetValue(LDAPSettings.LdapMapping[LdapSettings.MappingFields.AvatarAttribute], true);
if (image == null || image.GetType() != typeof(byte[]))
{
continue;
}
string hash;
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
hash = Convert.ToBase64String(md5.ComputeHash((byte[])image));
}
var user = _userManager.GetUserBySid(ldapUser.Sid);
_log.DebugFormat("SyncLdapAvatar() Found photo for '{0}'", ldapUser.Sid);
if (photoSettings.CurrentPhotos.ContainsKey(user.ID) && photoSettings.CurrentPhotos[user.ID] == hash)
{
_log.Debug("SyncLdapAvatar() Same hash, skipping.");
continue;
}
try
{
SetProgress((int)(currentPercent += step),
string.Format("{0}: {1}", Resource.LdapSettingsStatusSavingUserPhoto, _userFormatter.GetUserName(user, DisplayUserNameFormat.Default)));
_userPhotoManager.SyncPhoto(user.ID, (byte[])image);
if (photoSettings.CurrentPhotos.ContainsKey(user.ID))
{
photoSettings.CurrentPhotos[user.ID] = hash;
}
else
{
photoSettings.CurrentPhotos.Add(user.ID, hash);
}
}
catch
{
_log.DebugFormat("SyncLdapAvatar() Couldn't save photo for '{0}'", user.ID);
if (photoSettings.CurrentPhotos.ContainsKey(user.ID))
{
photoSettings.CurrentPhotos.Remove(user.ID);
}
}
}
_settingsManager.Save(photoSettings);
}
private void SyncLdapAccessRights()
{
SetProgress(95, Resource.LdapSettingsStatusUpdatingAccessRights);
var currentUserRights = new List<LdapSettings.AccessRight>();
TakeUsersRights(_currentUser != null ? currentUserRights : null);
if (LDAPSettings.GroupMembership && LDAPSettings.AccessRights != null && LDAPSettings.AccessRights.Count > 0)
{
GiveUsersRights(LDAPSettings.AccessRights, _currentUser != null ? currentUserRights : null);
}
if (currentUserRights.Count > 0)
{
Warning = Resource.LdapSettingsErrorLostRights;
}
_settingsManager.Save(LDAPSettings);
}
private void TakeUsersRights(List<LdapSettings.AccessRight> currentUserRights)
{
var current = _settingsManager.Load<LdapCurrentAcccessSettings>();
if (current.CurrentAccessRights == null || !current.CurrentAccessRights.Any())
{
_log.Debug("TakeUsersRights() CurrentAccessRights is empty, skipping");
return;
}
SetProgress(95, Resource.LdapSettingsStatusRemovingOldRights);
foreach (var right in current.CurrentAccessRights)
{
foreach (var user in right.Value)
{
var userId = Guid.Parse(user);
if (_currentUser != null && _currentUser.ID == userId)
{
_log.DebugFormat("TakeUsersRights() Attempting to take admin rights from yourself `{0}`, skipping", user);
if (currentUserRights != null)
{
currentUserRights.Add(right.Key);
}
}
else
{
_log.DebugFormat("TakeUsersRights() Taking admin rights ({0}) from '{1}'", right.Key, user);
_webItemSecurity.SetProductAdministrator(LdapSettings.AccessRightsGuids[right.Key], userId, false);
}
}
}
current.CurrentAccessRights = null;
_settingsManager.Save(current);
}
private void GiveUsersRights(Dictionary<LdapSettings.AccessRight, string> accessRightsSettings, List<LdapSettings.AccessRight> currentUserRights)
{
var current = _settingsManager.Load<LdapCurrentAcccessSettings>();
var currentAccessRights = new Dictionary<LdapSettings.AccessRight, List<string>>();
var usersWithRightsFlat = current.CurrentAccessRights == null ? new List<string>() : current.CurrentAccessRights.SelectMany(x => x.Value).Distinct().ToList();
var step = 3.0 / accessRightsSettings.Count;
var currentPercent = 95.0;
foreach (var access in accessRightsSettings)
{
currentPercent += step;
var ldapGroups = _ldapUserImporter.FindGroupsByAttribute(LDAPSettings.GroupNameAttribute, access.Value.Split(',').Select(x => x.Trim()));
if (!ldapGroups.Any())
{
_log.DebugFormat("GiveUsersRights() No ldap groups found for ({0}) access rights, skipping", access.Key);
continue;
}
foreach (var ldapGr in ldapGroups)
{
var gr = _userManager.GetGroupInfoBySid(ldapGr.Sid);
if (gr == null)
{
_log.DebugFormat("GiveUsersRights() Couldn't find portal group for '{0}'", ldapGr.Sid);
continue;
}
var users = _userManager.GetUsersByGroup(gr.ID);
_log.DebugFormat("GiveUsersRights() Found '{0}' users for group '{1}' ({2})", users.Count(), gr.Name, gr.ID);
foreach (var user in users)
{
if (!user.Equals(Constants.LostUser) && !user.IsVisitor(_userManager))
{
if (!usersWithRightsFlat.Contains(user.ID.ToString()))
{
usersWithRightsFlat.Add(user.ID.ToString());
var cleared = false;
foreach (var r in Enum.GetValues(typeof(LdapSettings.AccessRight)).Cast<LdapSettings.AccessRight>())
{
var prodId = LdapSettings.AccessRightsGuids[r];
if (_webItemSecurity.IsProductAdministrator(prodId, user.ID))
{
cleared = true;
_webItemSecurity.SetProductAdministrator(prodId, user.ID, false);
}
}
if (cleared)
{
_log.DebugFormat("GiveUsersRights() Cleared manually added user rights for '{0}'", user.DisplayUserName(_displayUserSettingsHelper));
}
}
if (!currentAccessRights.ContainsKey(access.Key))
{
currentAccessRights.Add(access.Key, new List<string>());
}
currentAccessRights[access.Key].Add(user.ID.ToString());
SetProgress((int)currentPercent,
string.Format(Resource.LdapSettingsStatusGivingRights, _userFormatter.GetUserName(user, DisplayUserNameFormat.Default), access.Key));
_webItemSecurity.SetProductAdministrator(LdapSettings.AccessRightsGuids[access.Key], user.ID, true);
if (currentUserRights != null && currentUserRights.Contains(access.Key))
{
currentUserRights.Remove(access.Key);
}
}
}
}
}
current.CurrentAccessRights = currentAccessRights;
_settingsManager.Save(current);
}
private void SyncLDAPUsers()
{
SetProgress(15, Resource.LdapSettingsStatusGettingUsersFromLdap);
var ldapUsers = _ldapUserImporter.GetDiscoveredUsersByAttributes();
if (!ldapUsers.Any())
{
Error = Resource.LdapSettingsErrorUsersNotFound;
return;
}
_log.DebugFormat("Importer.GetDiscoveredUsersByAttributes() Success: Users count: {0}",
_ldapUserImporter.AllDomainUsers.Count);
SetProgress(20, Resource.LdapSettingsStatusRemovingOldUsers, "");
ldapUsers = RemoveOldDbUsers(ldapUsers);
SetProgress(30,
OperationType == LdapOperationType.Save || OperationType == LdapOperationType.SaveTest
? Resource.LdapSettingsStatusSavingUsers
: Resource.LdapSettingsStatusSyncingUsers,
"");
SyncDbUsers(ldapUsers);
SetProgress(70, Resource.LdapSettingsStatusRemovingOldGroups, "");
RemoveOldDbGroups(new List<GroupInfo>()); // Remove all db groups with sid
}
private void SyncLDAPUsersInGroups()
{
SetProgress(15, Resource.LdapSettingsStatusGettingGroupsFromLdap);
var ldapGroups = _ldapUserImporter.GetDiscoveredGroupsByAttributes();
if (!ldapGroups.Any())
{
Error = Resource.LdapSettingsErrorGroupsNotFound;
return;
}
_log.DebugFormat("Importer.GetDiscoveredGroupsByAttributes() Success: Groups count: {0}",
_ldapUserImporter.AllDomainGroups.Count);
SetProgress(20, Resource.LdapSettingsStatusGettingUsersFromLdap);
//Get All found groups users
List<UserInfo> uniqueLdapGroupUsers;
var ldapGroupsUsers = GetGroupsUsers(ldapGroups, out uniqueLdapGroupUsers);
if (!uniqueLdapGroupUsers.Any())
{
Error = Resource.LdapSettingsErrorUsersNotFound;
return;
}
_log.DebugFormat("GetGroupsUsers() Success: Users count: {0}",
_ldapUserImporter.AllDomainUsers.Count);
SetProgress(30,
OperationType == LdapOperationType.Save || OperationType == LdapOperationType.SaveTest
? Resource.LdapSettingsStatusSavingUsers
: Resource.LdapSettingsStatusSyncingUsers,
"");
var newUniqueLdapGroupUsers = SyncGroupsUsers(uniqueLdapGroupUsers);
SetProgress(60, Resource.LdapSettingsStatusSavingGroups, "");
SyncDbGroups(ldapGroupsUsers);
SetProgress(80, Resource.LdapSettingsStatusRemovingOldGroups, "");
RemoveOldDbGroups(ldapGroups);
SetProgress(90, Resource.LdapSettingsStatusRemovingOldUsers, "");
RemoveOldDbUsers(newUniqueLdapGroupUsers);
}
private void SyncDbGroups(Dictionary<GroupInfo, List<UserInfo>> ldapGroupsWithUsers)
{
const double percents = 20;
var step = percents / ldapGroupsWithUsers.Count;
var percentage = GetProgress();
if (!ldapGroupsWithUsers.Any())
return;
var gIndex = 0;
var gCount = ldapGroupsWithUsers.Count;
foreach (var ldapGroupWithUsers in ldapGroupsWithUsers)
{
var ldapGroup = ldapGroupWithUsers.Key;
var ldapGroupUsers = ldapGroupWithUsers.Value;
++gIndex;
SetProgress(Convert.ToInt32(percentage),
currentSource:
string.Format("({0}/{1}): {2}", gIndex,
gCount, ldapGroup.Name));
var dbLdapGroup = _userManager.GetGroupInfoBySid(ldapGroup.Sid);
if (Equals(dbLdapGroup, Constants.LostGroupInfo))
{
AddNewGroup(ldapGroup, ldapGroupUsers, gIndex, gCount);
}
else
{
UpdateDbGroup(dbLdapGroup, ldapGroup, ldapGroupUsers, gIndex, gCount);
}
percentage += step;
}
}
private void AddNewGroup(GroupInfo ldapGroup, List<UserInfo> ldapGroupUsers, int gIndex, int gCount)
{
if (!ldapGroupUsers.Any()) // Skip empty groups
{
if (OperationType == LdapOperationType.SaveTest ||
OperationType == LdapOperationType.SyncTest)
{
_ldapChanges.SetSkipGroupChange(ldapGroup);
}
return;
}
var groupMembersToAdd =
ldapGroupUsers.Select(ldapGroupUser => SearchDbUserBySid(ldapGroupUser.Sid))
.Where(userBySid => !Equals(userBySid, Constants.LostUser))
.ToList();
if (groupMembersToAdd.Any())
{
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
ldapGroup = _userManager.SaveGroupInfo(ldapGroup);
var index = 0;
var count = groupMembersToAdd.Count;
foreach (var userBySid in groupMembersToAdd)
{
SetProgress(
currentSource:
string.Format("({0}/{1}): {2}, {3} ({4}/{5}): {6}", gIndex,
gCount, ldapGroup.Name,
Resource.LdapSettingsStatusAddingGroupUser,
++index, count,
_userFormatter.GetUserName(userBySid, DisplayUserNameFormat.Default)));
_userManager.AddUserIntoGroup(userBySid.ID, ldapGroup.ID);
}
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
_ldapChanges.SetAddGroupChange(ldapGroup);
_ldapChanges.SetAddGroupMembersChange(ldapGroup, groupMembersToAdd);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
else
{
if (OperationType == LdapOperationType.SaveTest ||
OperationType == LdapOperationType.SyncTest)
{
_ldapChanges.SetSkipGroupChange(ldapGroup);
}
}
}
private static bool NeedUpdateGroup(GroupInfo portalGroup, GroupInfo ldapGroup)
{
var needUpdate =
!portalGroup.Name.Equals(ldapGroup.Name, StringComparison.InvariantCultureIgnoreCase) ||
!portalGroup.Sid.Equals(ldapGroup.Sid, StringComparison.InvariantCultureIgnoreCase);
return needUpdate;
}
private void UpdateDbGroup(GroupInfo dbLdapGroup, GroupInfo ldapGroup, List<UserInfo> ldapGroupUsers, int gIndex,
int gCount)
{
SetProgress(currentSource:
string.Format("({0}/{1}): {2}", gIndex, gCount, ldapGroup.Name));
var dbGroupMembers =
_userManager.GetUsersByGroup(dbLdapGroup.ID, EmployeeStatus.All)
.Where(u => u.Sid != null)
.ToList();
var groupMembersToRemove =
dbGroupMembers.Where(
dbUser => ldapGroupUsers.FirstOrDefault(lu => dbUser.Sid.Equals(lu.Sid)) == null).ToList();
var groupMembersToAdd = (from ldapGroupUser in ldapGroupUsers
let dbUser = dbGroupMembers.FirstOrDefault(u => u.Sid.Equals(ldapGroupUser.Sid))
where dbUser == null
select SearchDbUserBySid(ldapGroupUser.Sid)
into userBySid
where !Equals(userBySid, Constants.LostUser)
select userBySid)
.ToList();
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
if (NeedUpdateGroup(dbLdapGroup, ldapGroup))
{
dbLdapGroup.Name = ldapGroup.Name;
dbLdapGroup.Sid = ldapGroup.Sid;
dbLdapGroup = _userManager.SaveGroupInfo(dbLdapGroup);
}
var index = 0;
var count = groupMembersToRemove.Count;
foreach (var dbUser in groupMembersToRemove)
{
SetProgress(
currentSource:
string.Format("({0}/{1}): {2}, {3} ({4}/{5}): {6}", gIndex, gCount,
dbLdapGroup.Name,
Resource.LdapSettingsStatusRemovingGroupUser,
++index, count,
_userFormatter.GetUserName(dbUser, DisplayUserNameFormat.Default)));
_userManager.RemoveUserFromGroup(dbUser.ID, dbLdapGroup.ID);
}
index = 0;
count = groupMembersToAdd.Count;
foreach (var userInfo in groupMembersToAdd)
{
SetProgress(
currentSource:
string.Format("({0}/{1}): {2}, {3} ({4}/{5}): {6}", gIndex, gCount,
ldapGroup.Name,
Resource.LdapSettingsStatusAddingGroupUser,
++index, count,
_userFormatter.GetUserName(userInfo, DisplayUserNameFormat.Default)));
_userManager.AddUserIntoGroup(userInfo.ID, dbLdapGroup.ID);
}
if (dbGroupMembers.All(dbUser => groupMembersToRemove.Exists(u => u.ID.Equals(dbUser.ID)))
&& !groupMembersToAdd.Any())
{
SetProgress(currentSource:
string.Format("({0}/{1}): {2}", gIndex, gCount, dbLdapGroup.Name));
_userManager.DeleteGroup(dbLdapGroup.ID);
}
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
if (NeedUpdateGroup(dbLdapGroup, ldapGroup))
_ldapChanges.SetUpdateGroupChange(ldapGroup);
if (groupMembersToRemove.Any())
_ldapChanges.SetRemoveGroupMembersChange(dbLdapGroup, groupMembersToRemove);
if (groupMembersToAdd.Any())
_ldapChanges.SetAddGroupMembersChange(dbLdapGroup, groupMembersToAdd);
if (dbGroupMembers.All(dbUser => groupMembersToRemove.Exists(u => u.ID.Equals(dbUser.ID)))
&& !groupMembersToAdd.Any())
{
_ldapChanges.SetRemoveGroupChange(dbLdapGroup, _log);
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private UserInfo SearchDbUserBySid(string sid)
{
if (string.IsNullOrEmpty(sid))
return Constants.LostUser;
var foundUser = _userManager.GetUserBySid(sid);
return foundUser;
}
private void SyncDbUsers(List<UserInfo> ldapUsers)
{
const double percents = 35;
var step = percents / ldapUsers.Count;
var percentage = GetProgress();
if (!ldapUsers.Any())
return;
var index = 0;
var count = ldapUsers.Count;
foreach (var userInfo in ldapUsers)
{
SetProgress(Convert.ToInt32(percentage),
currentSource:
string.Format("({0}/{1}): {2}", ++index, count,
_userFormatter.GetUserName(userInfo, DisplayUserNameFormat.Default)));
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
_lDAPUserManager.SyncLDAPUser(userInfo, ldapUsers);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
LdapChangeCollection changes;
_lDAPUserManager.GetLDAPSyncUserChange(userInfo, ldapUsers, out changes);
_ldapChanges.AddRange(changes);
break;
default:
throw new ArgumentOutOfRangeException();
}
percentage += step;
}
}
/// <summary>
/// Remove old LDAP users from db
/// </summary>
/// <param name="ldapUsers">list of actual LDAP users</param>
/// <returns>New list of actual LDAP users</returns>
private List<UserInfo> RemoveOldDbUsers(List<UserInfo> ldapUsers)
{
var dbLdapUsers = _userManager.GetUsers(EmployeeStatus.All).Where(u => u.Sid != null).ToList();
if (!dbLdapUsers.Any())
return ldapUsers;
var removedUsers =
dbLdapUsers.Where(u => ldapUsers.FirstOrDefault(lu => u.Sid.Equals(lu.Sid)) == null).ToList();
if (!removedUsers.Any())
return ldapUsers;
const double percents = 8;
var step = percents / removedUsers.Count;
var percentage = GetProgress();
var index = 0;
var count = removedUsers.Count;
foreach (var removedUser in removedUsers)
{
SetProgress(Convert.ToInt32(percentage),
currentSource:
string.Format("({0}/{1}): {2}", ++index, count,
_userFormatter.GetUserName(removedUser, DisplayUserNameFormat.Default)));
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
removedUser.Sid = null;
if (!removedUser.IsOwner(_tenantManager.GetCurrentTenant()) && !(_currentUser != null && _currentUser.ID == removedUser.ID && removedUser.IsAdmin(_userManager)))
{
removedUser.Status = EmployeeStatus.Terminated; // Disable user on portal
}
else
{
Warning = Resource.LdapSettingsErrorRemovedYourself;
_log.DebugFormat("RemoveOldDbUsers() Attempting to exclude yourself `{0}` from group or user filters, skipping.", removedUser.ID);
}
removedUser.ConvertExternalContactsToOrdinary();
_log.DebugFormat("CoreContext.UserManager.SaveUserInfo({0})", removedUser.GetUserInfoString());
_userManager.SaveUserInfo(removedUser);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
_ldapChanges.SetSaveAsPortalUserChange(removedUser);
break;
default:
throw new ArgumentOutOfRangeException();
}
percentage += step;
}
dbLdapUsers.RemoveAll(removedUsers.Contains);
var newLdapUsers = ldapUsers.Where(u => !removedUsers.Exists(ru => ru.ID.Equals(u.ID))).ToList();
return newLdapUsers;
}
private void RemoveOldDbGroups(List<GroupInfo> ldapGroups)
{
var percentage = GetProgress();
var removedDbLdapGroups =
_userManager.GetGroups()
.Where(g => g.Sid != null && ldapGroups.FirstOrDefault(lg => g.Sid.Equals(lg.Sid)) == null)
.ToList();
if (!removedDbLdapGroups.Any())
return;
const double percents = 10;
var step = percents / removedDbLdapGroups.Count;
var index = 0;
var count = removedDbLdapGroups.Count;
foreach (var groupInfo in removedDbLdapGroups)
{
SetProgress(Convert.ToInt32(percentage),
currentSource: string.Format("({0}/{1}): {2}", ++index, count, groupInfo.Name));
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
_userManager.DeleteGroup(groupInfo.ID);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
_ldapChanges.SetRemoveGroupChange(groupInfo);
break;
default:
throw new ArgumentOutOfRangeException();
}
percentage += step;
}
}
private List<UserInfo> SyncGroupsUsers(List<UserInfo> uniqueLdapGroupUsers)
{
const double percents = 30;
var step = percents / uniqueLdapGroupUsers.Count;
var percentage = GetProgress();
var newUniqueLdapGroupUsers = new List<UserInfo>();
var index = 0;
var count = uniqueLdapGroupUsers.Count;
int i, len;
for (i = 0, len = uniqueLdapGroupUsers.Count; i < len; i++)
{
var ldapGroupUser = uniqueLdapGroupUsers[i];
SetProgress(Convert.ToInt32(percentage),
currentSource:
string.Format("({0}/{1}): {2}", ++index, count,
_userFormatter.GetUserName(ldapGroupUser, DisplayUserNameFormat.Default)));
UserInfo user;
switch (OperationType)
{
case LdapOperationType.Save:
case LdapOperationType.Sync:
user = _lDAPUserManager.SyncLDAPUser(ldapGroupUser, uniqueLdapGroupUsers);
if (!Equals(user, Constants.LostUser))
newUniqueLdapGroupUsers.Add(user);
break;
case LdapOperationType.SaveTest:
case LdapOperationType.SyncTest:
LdapChangeCollection changes;
user = _lDAPUserManager.GetLDAPSyncUserChange(ldapGroupUser, uniqueLdapGroupUsers, out changes);
if (!Equals(user, Constants.LostUser))
{
newUniqueLdapGroupUsers.Add(user);
}
_ldapChanges.AddRange(changes);
break;
default:
throw new ArgumentOutOfRangeException();
}
percentage += step;
}
return newUniqueLdapGroupUsers;
}
private Dictionary<GroupInfo, List<UserInfo>> GetGroupsUsers(List<GroupInfo> ldapGroups,
out List<UserInfo> uniqueLdapGroupUsers)
{
uniqueLdapGroupUsers = new List<UserInfo>();
var listGroupsUsers = new Dictionary<GroupInfo, List<UserInfo>>();
foreach (var ldapGroup in ldapGroups)
{
var ldapGroupUsers = _ldapUserImporter.GetGroupUsers(ldapGroup);
listGroupsUsers.Add(ldapGroup, ldapGroupUsers);
foreach (var ldapGroupUser in ldapGroupUsers)
{
if (!uniqueLdapGroupUsers.Any(u => u.Sid.Equals(ldapGroupUser.Sid)))
{
uniqueLdapGroupUsers.Add(ldapGroupUser);
}
}
}
return listGroupsUsers;
}
private double GetProgress()
{
return Percentage;
}
const string PROGRESS_STRING = "Progress: {0}% {1} {2}";
private void SetProgress(int? currentPercent = null, string currentStatus = null, string currentSource = null)
{
if (!currentPercent.HasValue && currentStatus == null && currentSource == null)
return;
if (currentPercent.HasValue)
Percentage = currentPercent.Value;
if (currentStatus != null)
Status = currentStatus;
if (currentSource != null)
Source = currentSource;
_log.InfoFormat(PROGRESS_STRING, Percentage, Status, Source);
PublishChanges();
}
private void FillDistributedTask()
{
SetProperty(LdapTaskProperty.SOURCE, Source);
SetProperty(LdapTaskProperty.OPERATION_TYPE, OperationType);
SetProperty(LdapTaskProperty.OWNER, _tenantId);
SetProperty(LdapTaskProperty.PROGRESS, Percentage < 100 ? Percentage : 100);
SetProperty(LdapTaskProperty.RESULT, Status);
SetProperty(LdapTaskProperty.ERROR, Error);
SetProperty(LdapTaskProperty.WARNING, Warning);
//SetProperty(PROCESSED, successProcessed);
}
private void PrepareSettings(LdapSettings settings)
{
if (settings == null)
{
_log.Error("Wrong LDAP settings were received from client.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (!settings.EnableLdapAuthentication)
{
settings.Password = string.Empty;
return;
}
if (!string.IsNullOrWhiteSpace(settings.Server))
settings.Server = settings.Server.Trim();
else
{
_log.Error("settings.Server is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (!settings.Server.StartsWith("LDAP://"))
settings.Server = "LDAP://" + settings.Server.Trim();
if (!string.IsNullOrWhiteSpace(settings.UserDN))
settings.UserDN = settings.UserDN.Trim();
else
{
_log.Error("settings.UserDN is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (!string.IsNullOrWhiteSpace(settings.LoginAttribute))
settings.LoginAttribute = settings.LoginAttribute.Trim();
else
{
_log.Error("settings.LoginAttribute is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (!string.IsNullOrWhiteSpace(settings.UserFilter))
settings.UserFilter = settings.UserFilter.Trim();
if (!string.IsNullOrWhiteSpace(settings.FirstNameAttribute))
settings.FirstNameAttribute = settings.FirstNameAttribute.Trim();
if (!string.IsNullOrWhiteSpace(settings.SecondNameAttribute))
settings.SecondNameAttribute = settings.SecondNameAttribute.Trim();
if (!string.IsNullOrWhiteSpace(settings.MailAttribute))
settings.MailAttribute = settings.MailAttribute.Trim();
if (!string.IsNullOrWhiteSpace(settings.TitleAttribute))
settings.TitleAttribute = settings.TitleAttribute.Trim();
if (!string.IsNullOrWhiteSpace(settings.MobilePhoneAttribute))
settings.MobilePhoneAttribute = settings.MobilePhoneAttribute.Trim();
if (settings.GroupMembership)
{
if (!string.IsNullOrWhiteSpace(settings.GroupDN))
settings.GroupDN = settings.GroupDN.Trim();
else
{
_log.Error("settings.GroupDN is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (!string.IsNullOrWhiteSpace(settings.GroupFilter))
settings.GroupFilter = settings.GroupFilter.Trim();
if (!string.IsNullOrWhiteSpace(settings.GroupAttribute))
settings.GroupAttribute = settings.GroupAttribute.Trim();
else
{
_log.Error("settings.GroupAttribute is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (!string.IsNullOrWhiteSpace(settings.UserAttribute))
settings.UserAttribute = settings.UserAttribute.Trim();
else
{
_log.Error("settings.UserAttribute is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
}
if (!settings.Authentication)
{
settings.Password = string.Empty;
return;
}
if (!string.IsNullOrWhiteSpace(settings.Login))
settings.Login = settings.Login.Trim();
else
{
_log.Error("settings.Login is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
if (settings.PasswordBytes == null || !settings.PasswordBytes.Any())
{
if (!string.IsNullOrEmpty(settings.Password))
{
settings.PasswordBytes = _novellLdapHelper.GetPasswordBytes(settings.Password);
if (settings.PasswordBytes == null)
{
_log.Error("settings.PasswordBytes is null.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
}
else
{
_log.Error("settings.Password is null or empty.");
Error = Resource.LdapSettingsErrorCantGetLdapSettings;
return;
}
}
settings.Password = string.Empty;
}
private static string GetError(LdapSettingsStatus result)
{
switch (result)
{
case LdapSettingsStatus.Ok:
return string.Empty;
case LdapSettingsStatus.WrongServerOrPort:
return Resource.LdapSettingsErrorWrongServerOrPort;
case LdapSettingsStatus.WrongUserDn:
return Resource.LdapSettingsErrorWrongUserDn;
case LdapSettingsStatus.IncorrectLDAPFilter:
return Resource.LdapSettingsErrorIncorrectLdapFilter;
case LdapSettingsStatus.UsersNotFound:
return Resource.LdapSettingsErrorUsersNotFound;
case LdapSettingsStatus.WrongLoginAttribute:
return Resource.LdapSettingsErrorWrongLoginAttribute;
case LdapSettingsStatus.WrongGroupDn:
return Resource.LdapSettingsErrorWrongGroupDn;
case LdapSettingsStatus.IncorrectGroupLDAPFilter:
return Resource.LdapSettingsErrorWrongGroupFilter;
case LdapSettingsStatus.GroupsNotFound:
return Resource.LdapSettingsErrorGroupsNotFound;
case LdapSettingsStatus.WrongGroupAttribute:
return Resource.LdapSettingsErrorWrongGroupAttribute;
case LdapSettingsStatus.WrongUserAttribute:
return Resource.LdapSettingsErrorWrongUserAttribute;
case LdapSettingsStatus.WrongGroupNameAttribute:
return Resource.LdapSettingsErrorWrongGroupNameAttribute;
case LdapSettingsStatus.CredentialsNotValid:
return Resource.LdapSettingsErrorCredentialsNotValid;
case LdapSettingsStatus.ConnectError:
return Resource.LdapSettingsConnectError;
case LdapSettingsStatus.StrongAuthRequired:
return Resource.LdapSettingsStrongAuthRequired;
case LdapSettingsStatus.WrongSidAttribute:
return Resource.LdapSettingsWrongSidAttribute;
case LdapSettingsStatus.TlsNotSupported:
return Resource.LdapSettingsTlsNotSupported;
case LdapSettingsStatus.DomainNotFound:
return Resource.LdapSettingsErrorDomainNotFound;
case LdapSettingsStatus.CertificateRequest:
return Resource.LdapSettingsStatusCertificateVerification;
default:
return Resource.LdapSettingsErrorUnknownError;
}
}
public static class LdapOperationExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<NovellLdapSettingsChecker>();
services.TryAdd<LdapChangeCollection>();
}
}
}