Align NTFS ensure traverse handling
This commit is contained in:
@@ -55,6 +55,7 @@ namespace C4IT.LIAM
|
|||||||
public static Guid nftsModuleId = new Guid("77e213a1-6517-ea11-4881-000c2980fd94");
|
public static Guid nftsModuleId = new Guid("77e213a1-6517-ea11-4881-000c2980fd94");
|
||||||
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
|
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
|
||||||
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
|
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
|
||||||
|
private const string AdditionalConfigurationTraverseBoundaryPathKey = "NtfsTraverseBoundaryPath";
|
||||||
public readonly cNtfsBase ntfsBase = new cNtfsBase();
|
public readonly cNtfsBase ntfsBase = new cNtfsBase();
|
||||||
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||||
private readonly Dictionary<string, HashSet<string>> publishedShareCache = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, HashSet<string>> publishedShareCache = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
||||||
@@ -996,8 +997,10 @@ namespace C4IT.LIAM
|
|||||||
groupDLTag = requiresDomainLocalTag ? GetRequiredCustomTag("Filesystem_GroupDomainLocalTag") : string.Empty,
|
groupDLTag = requiresDomainLocalTag ? GetRequiredCustomTag("Filesystem_GroupDomainLocalTag") : string.Empty,
|
||||||
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
|
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
|
||||||
CanManagePermissionsForPath = IsPermissionManagedFolderPath,
|
CanManagePermissionsForPath = IsPermissionManagedFolderPath,
|
||||||
|
CanManageTraversePermissionsForPath = IsTraversePermissionManagedPath,
|
||||||
forceStrictAdGroupNames = IsAdditionalConfigurationEnabled("ForceStrictAdGroupNames")
|
forceStrictAdGroupNames = IsAdditionalConfigurationEnabled("ForceStrictAdGroupNames")
|
||||||
};
|
};
|
||||||
|
engine.traverseBoundaryPath = GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey);
|
||||||
|
|
||||||
foreach (var template in BuildSecurityGroupTemplates())
|
foreach (var template in BuildSecurityGroupTemplates())
|
||||||
engine.templates.Add(template);
|
engine.templates.Add(template);
|
||||||
@@ -1018,6 +1021,17 @@ namespace C4IT.LIAM
|
|||||||
|| rawValue.Equals("yes", StringComparison.OrdinalIgnoreCase);
|
|| rawValue.Equals("yes", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetAdditionalConfigurationValue(string key)
|
||||||
|
{
|
||||||
|
if (AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
if (!AdditionalConfiguration.TryGetValue(key, out var rawValue) || string.IsNullOrWhiteSpace(rawValue))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return rawValue.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsPermissionManagedFolderPath(string path)
|
public bool IsPermissionManagedFolderPath(string path)
|
||||||
{
|
{
|
||||||
return IsPermissionManagedPath(path, eNtfsPathKind.Folder);
|
return IsPermissionManagedPath(path, eNtfsPathKind.Folder);
|
||||||
@@ -1042,6 +1056,23 @@ namespace C4IT.LIAM
|
|||||||
return IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule);
|
return IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsTraversePermissionManagedPath(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey)))
|
||||||
|
return IsPermissionManagedFolderPath(path);
|
||||||
|
|
||||||
|
var classification = ClassifyPath(path);
|
||||||
|
if (classification == null || classification.Kind == eNtfsPathKind.ServerRoot || classification.Kind == eNtfsPathKind.Unknown)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string matchingConfigurationKey;
|
||||||
|
string matchingRule;
|
||||||
|
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Directory.Exists(path);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds)
|
private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds)
|
||||||
{
|
{
|
||||||
if (classification == null || supportedKinds == null || supportedKinds.Length == 0)
|
if (classification == null || supportedKinds == null || supportedKinds.Length == 0)
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ namespace C4IT_IAM_SET
|
|||||||
public ICollection<string> readerUserSids;
|
public ICollection<string> readerUserSids;
|
||||||
public ICollection<string> writerUserSids;
|
public ICollection<string> writerUserSids;
|
||||||
public Func<string, bool> CanManagePermissionsForPath;
|
public Func<string, bool> CanManagePermissionsForPath;
|
||||||
|
public Func<string, bool> CanManageTraversePermissionsForPath;
|
||||||
|
public string traverseBoundaryPath;
|
||||||
public bool forceStrictAdGroupNames;
|
public bool forceStrictAdGroupNames;
|
||||||
public bool WhatIf;
|
public bool WhatIf;
|
||||||
|
|
||||||
@@ -147,6 +149,10 @@ namespace C4IT_IAM_SET
|
|||||||
DefaultLogger.LogEntry(LogLevels.Info, $"Establishing connection to {baseFolder}, User: {username}, Password: {Helper.MaskAllButLastAndFirst(new NetworkCredential("", password).Password)}");
|
DefaultLogger.LogEntry(LogLevels.Info, $"Establishing connection to {baseFolder}, User: {username}, Password: {Helper.MaskAllButLastAndFirst(new NetworkCredential("", password).Password)}");
|
||||||
using (Connection = new cNetworkConnection(baseFolder, username, new NetworkCredential("", password).Password))
|
using (Connection = new cNetworkConnection(baseFolder, username, new NetworkCredential("", password).Password))
|
||||||
{
|
{
|
||||||
|
var traverseBoundaryResult = ValidateTraverseBoundaryForCurrentFolder();
|
||||||
|
if (traverseBoundaryResult.resultErrorId != 0)
|
||||||
|
return traverseBoundaryResult;
|
||||||
|
|
||||||
var folderCheckResult = checkFolder();
|
var folderCheckResult = checkFolder();
|
||||||
if (folderCheckResult.resultErrorId == 0)
|
if (folderCheckResult.resultErrorId == 0)
|
||||||
{
|
{
|
||||||
@@ -299,6 +305,39 @@ namespace C4IT_IAM_SET
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResultToken ValidateTraverseBoundaryForCurrentFolder()
|
||||||
|
{
|
||||||
|
var resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
||||||
|
resultToken.resultErrorId = 0;
|
||||||
|
|
||||||
|
var boundaryPath = GetNormalizedTraverseBoundaryPath();
|
||||||
|
if (string.IsNullOrWhiteSpace(boundaryPath))
|
||||||
|
return resultToken;
|
||||||
|
|
||||||
|
var targetParent = new DirectoryInfo(newFolderPath).Parent;
|
||||||
|
if (targetParent == null)
|
||||||
|
{
|
||||||
|
resultToken.resultErrorId = 30009;
|
||||||
|
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' cannot be validated because '{newFolderPath}' has no parent directory.";
|
||||||
|
return resultToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(boundaryPath))
|
||||||
|
{
|
||||||
|
resultToken.resultErrorId = 30009;
|
||||||
|
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' does not exist or is not reachable.";
|
||||||
|
return resultToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsSameOrAncestorPath(boundaryPath, targetParent.FullName))
|
||||||
|
{
|
||||||
|
resultToken.resultErrorId = 30009;
|
||||||
|
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' is not a parent path of '{newFolderPath}'.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultToken;
|
||||||
|
}
|
||||||
|
|
||||||
public ResultToken ensureDataAreaPermissions(bool ensureTraverseGroups = false)
|
public ResultToken ensureDataAreaPermissions(bool ensureTraverseGroups = false)
|
||||||
{
|
{
|
||||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
@@ -327,6 +366,10 @@ namespace C4IT_IAM_SET
|
|||||||
|
|
||||||
InitializeFolderContext();
|
InitializeFolderContext();
|
||||||
|
|
||||||
|
var traverseBoundaryResult = ValidateTraverseBoundaryForCurrentFolder();
|
||||||
|
if (traverseBoundaryResult.resultErrorId != 0)
|
||||||
|
return traverseBoundaryResult;
|
||||||
|
|
||||||
ensureADGroups(resultToken);
|
ensureADGroups(resultToken);
|
||||||
resultToken = ensureFolderPermissions(resultToken);
|
resultToken = ensureFolderPermissions(resultToken);
|
||||||
|
|
||||||
@@ -424,6 +467,10 @@ namespace C4IT_IAM_SET
|
|||||||
|
|
||||||
var lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
var lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Ebene (lvl): {lvl}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Ebene (lvl): {lvl}");
|
||||||
|
var currentTraverseLevel = lvl;
|
||||||
|
var defaultTraverseLoopIndex = lvl;
|
||||||
|
var hasTraverseBoundary = !string.IsNullOrWhiteSpace(GetNormalizedTraverseBoundaryPath());
|
||||||
|
var processedNearestTraverseParent = false;
|
||||||
|
|
||||||
// Überprüfen der Templates
|
// Überprüfen der Templates
|
||||||
if (templates == null)
|
if (templates == null)
|
||||||
@@ -472,9 +519,9 @@ namespace C4IT_IAM_SET
|
|||||||
return resultToken;
|
return resultToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = lvl; i >= createTraverseGroupLvl; i--)
|
while (parent != null && (hasTraverseBoundary || defaultTraverseLoopIndex >= createTraverseGroupLvl))
|
||||||
{
|
{
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Verarbeite Ebene {i}.");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Verarbeite Ebene {currentTraverseLevel}.");
|
||||||
|
|
||||||
if (parent == null)
|
if (parent == null)
|
||||||
{
|
{
|
||||||
@@ -482,14 +529,22 @@ namespace C4IT_IAM_SET
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanManagePermissionsForPath != null && !CanManagePermissionsForPath(parent.FullName))
|
var canManageTraversePath = CanManageTraversePermissionsForPath ?? CanManagePermissionsForPath;
|
||||||
|
if (canManageTraversePath != null && !canManageTraversePath(parent.FullName))
|
||||||
{
|
{
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Überspringe Traverse-Verarbeitung für nicht verwaltbaren NTFS-Pfad: {parent.FullName}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Überspringe Traverse-Verarbeitung für nicht verwaltbaren NTFS-Pfad: {parent.FullName}");
|
||||||
|
if (IsTraverseBoundaryPath(parent.FullName))
|
||||||
|
break;
|
||||||
|
|
||||||
parent = parent.Parent;
|
parent = parent.Parent;
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
currentTraverseLevel = hasTraverseBoundary
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Überspringen: {lvl}");
|
? currentTraverseLevel + 1
|
||||||
|
: DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
||||||
|
if (!hasTraverseBoundary)
|
||||||
|
defaultTraverseLoopIndex--;
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Überspringen: {currentTraverseLevel}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -530,13 +585,14 @@ namespace C4IT_IAM_SET
|
|||||||
var folderName = sanitizedSegments.Length > 0
|
var folderName = sanitizedSegments.Length > 0
|
||||||
? sanitizedSegments[sanitizedSegments.Length - 1]
|
? sanitizedSegments[sanitizedSegments.Length - 1]
|
||||||
: Helper.SanitizePathSegment(Path.GetFileName(parent.FullName.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
|
: Helper.SanitizePathSegment(Path.GetFileName(parent.FullName.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
|
||||||
|
var traverseTags = GetTraverseReplacementTags(parent.FullName);
|
||||||
var boundedTraverseContext = Helper.GetBoundedAdGroupTemplateContext(
|
var boundedTraverseContext = Helper.GetBoundedAdGroupTemplateContext(
|
||||||
traverseGroupTemplate.NamingTemplate,
|
traverseGroupTemplate.NamingTemplate,
|
||||||
true,
|
true,
|
||||||
relativePath,
|
relativePath,
|
||||||
sanitizedSegments,
|
sanitizedSegments,
|
||||||
folderName,
|
folderName,
|
||||||
null,
|
traverseTags,
|
||||||
Helper.MaxAdGroupNameLength,
|
Helper.MaxAdGroupNameLength,
|
||||||
$"Traverse fuer '{parent.FullName}'");
|
$"Traverse fuer '{parent.FullName}'");
|
||||||
var boundedTraverseDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
|
var boundedTraverseDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
|
||||||
@@ -545,7 +601,7 @@ namespace C4IT_IAM_SET
|
|||||||
relativePath,
|
relativePath,
|
||||||
sanitizedSegments,
|
sanitizedSegments,
|
||||||
folderName,
|
folderName,
|
||||||
null,
|
traverseTags,
|
||||||
Helper.MaxAdGroupDescriptionLength,
|
Helper.MaxAdGroupDescriptionLength,
|
||||||
$"Traverse fuer '{parent.FullName}'",
|
$"Traverse fuer '{parent.FullName}'",
|
||||||
"AD-Gruppenbeschreibung");
|
"AD-Gruppenbeschreibung");
|
||||||
@@ -555,13 +611,13 @@ namespace C4IT_IAM_SET
|
|||||||
var adjustedTraverseDescriptionSegments = boundedTraverseDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
|
var adjustedTraverseDescriptionSegments = boundedTraverseDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
|
||||||
var adjustedTraverseDescriptionRelativePath = adjustedTraverseDescriptionSegments.Length > 0 ? string.Join("_", adjustedTraverseDescriptionSegments) : string.Empty;
|
var adjustedTraverseDescriptionRelativePath = adjustedTraverseDescriptionSegments.Length > 0 ? string.Join("_", adjustedTraverseDescriptionSegments) : string.Empty;
|
||||||
var adjustedTraverseDescriptionFolderName = boundedTraverseDescriptionContext.FolderName;
|
var adjustedTraverseDescriptionFolderName = boundedTraverseDescriptionContext.FolderName;
|
||||||
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName);
|
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName).ReplaceTags(traverseTags);
|
||||||
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName);
|
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName).ReplaceTags(traverseTags);
|
||||||
|
|
||||||
string traverseRegex = null;
|
string traverseRegex = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName);
|
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName).ReplaceTags(traverseTags);
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -570,8 +626,12 @@ namespace C4IT_IAM_SET
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasTraverseWildcard = !string.IsNullOrWhiteSpace(traverseRegex);
|
||||||
foreach (FileSystemAccessRule acl in ACLs)
|
foreach (FileSystemAccessRule acl in ACLs)
|
||||||
{
|
{
|
||||||
|
if (!hasTraverseWildcard)
|
||||||
|
break;
|
||||||
|
|
||||||
var searchString = acl.IdentityReference.Value;
|
var searchString = acl.IdentityReference.Value;
|
||||||
var aclSplit = searchString.Split('\\');
|
var aclSplit = searchString.Split('\\');
|
||||||
if (aclSplit.Length == 2)
|
if (aclSplit.Length == 2)
|
||||||
@@ -600,7 +660,18 @@ namespace C4IT_IAM_SET
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentTraverseGroup == null && !string.IsNullOrEmpty(traverseNameTemplate))
|
if (parentTraverseGroup == null && hasTraverseWildcard && !forceStrictAdGroupNames)
|
||||||
|
{
|
||||||
|
parentTraverseGroup = FindTraverseGroupByWildcard(domainContext, traverseRegex);
|
||||||
|
if (parentTraverseGroup != null)
|
||||||
|
{
|
||||||
|
resultToken.reusedGroups.Add(parentTraverseGroup.Name);
|
||||||
|
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe per Wildcard wiederverwendet: {parentTraverseGroup.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentTraverseGroup == null && !string.IsNullOrWhiteSpace(traverseNameTemplate))
|
||||||
{
|
{
|
||||||
for (var loop = 0; loop < 20; loop++)
|
for (var loop = 0; loop < 20; loop++)
|
||||||
{
|
{
|
||||||
@@ -616,7 +687,7 @@ namespace C4IT_IAM_SET
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentTraverseGroup == null && !traverseGroupTemplate.NamingTemplate.Equals(string.Empty))
|
if (parentTraverseGroup == null && !string.IsNullOrWhiteSpace(traverseNameTemplate))
|
||||||
{
|
{
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, "Erstelle neue TraverseGroup.");
|
DefaultLogger.LogEntry(LogLevels.Debug, "Erstelle neue TraverseGroup.");
|
||||||
if (newSecurityGroups == null)
|
if (newSecurityGroups == null)
|
||||||
@@ -750,7 +821,7 @@ namespace C4IT_IAM_SET
|
|||||||
|
|
||||||
if (parentTraverseGroup != null)
|
if (parentTraverseGroup != null)
|
||||||
{
|
{
|
||||||
if (i == lvl)
|
if (!processedNearestTraverseParent)
|
||||||
{
|
{
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
|
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
|
||||||
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
|
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
|
||||||
@@ -773,6 +844,7 @@ namespace C4IT_IAM_SET
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
traverseGroup = parentTraverseGroup;
|
traverseGroup = parentTraverseGroup;
|
||||||
|
processedNearestTraverseParent = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -821,12 +893,19 @@ namespace C4IT_IAM_SET
|
|||||||
if (parentTraverseGroup != null && !resultToken.ensuredTraverseGroups.Contains(parentTraverseGroup.Name))
|
if (parentTraverseGroup != null && !resultToken.ensuredTraverseGroups.Contains(parentTraverseGroup.Name))
|
||||||
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
|
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
|
||||||
|
|
||||||
|
if (IsTraverseBoundaryPath(parent.FullName))
|
||||||
|
break;
|
||||||
|
|
||||||
// Aktualisiere parent und lvl für die nächste Iteration
|
// Aktualisiere parent und lvl für die nächste Iteration
|
||||||
parent = parent.Parent;
|
parent = parent.Parent;
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
currentTraverseLevel = hasTraverseBoundary
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Aktualisierung: {lvl}");
|
? currentTraverseLevel + 1
|
||||||
|
: DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
||||||
|
if (!hasTraverseBoundary)
|
||||||
|
defaultTraverseLoopIndex--;
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Aktualisierung: {currentTraverseLevel}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -847,6 +926,177 @@ namespace C4IT_IAM_SET
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetNormalizedTraverseBoundaryPath()
|
||||||
|
{
|
||||||
|
return NormalizeDirectoryPath(traverseBoundaryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsTraverseBoundaryPath(string path)
|
||||||
|
{
|
||||||
|
var boundaryPath = GetNormalizedTraverseBoundaryPath();
|
||||||
|
return !string.IsNullOrWhiteSpace(boundaryPath)
|
||||||
|
&& PathsEqual(boundaryPath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, string> GetTraverseReplacementTags(string currentPath)
|
||||||
|
{
|
||||||
|
var visibleSegments = GetVisibleTraversePathSegments(currentPath);
|
||||||
|
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "TRAVERSE_NAME", Helper.SanitizePathSegment(GetLastPathSegment(currentPath)) },
|
||||||
|
{ "TRAVERSE_VISIBLEPATH", string.Join("_", visibleSegments.Select(Helper.SanitizePathSegment)) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetVisibleTraversePathSegments(string currentPath)
|
||||||
|
{
|
||||||
|
var normalizedCurrentPath = NormalizeDirectoryPath(currentPath);
|
||||||
|
var boundaryPath = GetNormalizedTraverseBoundaryPath();
|
||||||
|
if (string.IsNullOrWhiteSpace(boundaryPath))
|
||||||
|
boundaryPath = NormalizeDirectoryPath(baseFolder);
|
||||||
|
|
||||||
|
var visibleRoot = GetParentPath(boundaryPath);
|
||||||
|
if (string.IsNullOrWhiteSpace(visibleRoot))
|
||||||
|
visibleRoot = boundaryPath;
|
||||||
|
|
||||||
|
var currentSegments = SplitPathSegments(normalizedCurrentPath);
|
||||||
|
var rootSegments = SplitPathSegments(visibleRoot);
|
||||||
|
if (currentSegments.Length <= rootSegments.Length)
|
||||||
|
return currentSegments;
|
||||||
|
|
||||||
|
var isRootPrefix = rootSegments
|
||||||
|
.Select((segment, index) => new { segment, index })
|
||||||
|
.All(i => string.Equals(i.segment, currentSegments[i.index], StringComparison.OrdinalIgnoreCase));
|
||||||
|
return isRootPrefix
|
||||||
|
? currentSegments.Skip(rootSegments.Length)
|
||||||
|
: currentSegments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GroupPrincipal FindTraverseGroupByWildcard(PrincipalContext domainContext, string wildcardPattern)
|
||||||
|
{
|
||||||
|
if (domainContext == null || string.IsNullOrWhiteSpace(wildcardPattern))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Regex wildcardRegex;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wildcardRegex = new Regex(wildcardPattern, RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
cLogManager.DefaultLogger.LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var basePath = "LDAP://" + domainName;
|
||||||
|
if (!string.IsNullOrWhiteSpace(groupOUPath))
|
||||||
|
basePath += "/" + groupOUPath;
|
||||||
|
|
||||||
|
DirectoryEntry entry = new DirectoryEntry
|
||||||
|
{
|
||||||
|
Path = basePath,
|
||||||
|
Username = username,
|
||||||
|
Password = new NetworkCredential("", password).Password,
|
||||||
|
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectorySearcher search = new DirectorySearcher(entry)
|
||||||
|
{
|
||||||
|
Filter = "(objectClass=group)"
|
||||||
|
};
|
||||||
|
search.PageSize = 100000;
|
||||||
|
search.PropertiesToLoad.Add("sAMAccountName");
|
||||||
|
search.PropertiesToLoad.Add("objectSid");
|
||||||
|
|
||||||
|
string matchedSid = null;
|
||||||
|
string matchedName = null;
|
||||||
|
var matchCount = 0;
|
||||||
|
|
||||||
|
foreach (SearchResult result in search.FindAll())
|
||||||
|
{
|
||||||
|
if (!result.Properties.Contains("sAMAccountName") || result.Properties["sAMAccountName"].Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var samAccountName = result.Properties["sAMAccountName"][0]?.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(samAccountName) || !wildcardRegex.IsMatch(samAccountName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
matchCount++;
|
||||||
|
if (matchCount > 1)
|
||||||
|
{
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Warning, $"Multiple AD groups matched traverse wildcard '{wildcardPattern}' in '{basePath}'. Regex-based reuse is skipped.");
|
||||||
|
search.Dispose();
|
||||||
|
entry.Dispose();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchedName = samAccountName;
|
||||||
|
matchedSid = result.Properties.Contains("objectSid") && result.Properties["objectSid"].Count > 0
|
||||||
|
? new SecurityIdentifier((byte[])result.Properties["objectSid"][0], 0).Value
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
search.Dispose();
|
||||||
|
entry.Dispose();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(matchedSid))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Reusing existing traverse AD group '{matchedName}' via wildcard '{wildcardPattern}'.");
|
||||||
|
return GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, matchedSid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeDirectoryPath(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var normalized = path.Trim().Replace('/', '\\').TrimEnd('\\');
|
||||||
|
if (normalized.StartsWith(@"\\", StringComparison.Ordinal))
|
||||||
|
return @"\\" + string.Join("\\", SplitPathSegments(normalized));
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool PathsEqual(string left, string right)
|
||||||
|
{
|
||||||
|
return string.Equals(NormalizeDirectoryPath(left), NormalizeDirectoryPath(right), StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsSameOrAncestorPath(string ancestorPath, string path)
|
||||||
|
{
|
||||||
|
var ancestor = NormalizeDirectoryPath(ancestorPath);
|
||||||
|
var current = NormalizeDirectoryPath(path);
|
||||||
|
return string.Equals(ancestor, current, StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| current.StartsWith(ancestor + "\\", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetParentPath(string path)
|
||||||
|
{
|
||||||
|
var segments = SplitPathSegments(path);
|
||||||
|
if (segments.Length <= 1)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
if (NormalizeDirectoryPath(path).StartsWith(@"\\", StringComparison.Ordinal))
|
||||||
|
return @"\\" + string.Join("\\", segments.Take(segments.Length - 1));
|
||||||
|
|
||||||
|
return string.Join("\\", segments.Take(segments.Length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLastPathSegment(string path)
|
||||||
|
{
|
||||||
|
var segments = SplitPathSegments(path);
|
||||||
|
return segments.Length == 0 ? string.Empty : segments[segments.Length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] SplitPathSegments(string path)
|
||||||
|
{
|
||||||
|
return (path ?? string.Empty)
|
||||||
|
.Trim()
|
||||||
|
.Replace('/', '\\')
|
||||||
|
.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
}
|
||||||
|
|
||||||
private bool TryEnsureGlobalGroupMembershipWithRetry(PrincipalContext domainContext, GroupPrincipal parentTraverseGroup, IAM_SecurityGroup currentSecGroup)
|
private bool TryEnsureGlobalGroupMembershipWithRetry(PrincipalContext domainContext, GroupPrincipal parentTraverseGroup, IAM_SecurityGroup currentSecGroup)
|
||||||
{
|
{
|
||||||
if (domainContext == null || parentTraverseGroup == null || currentSecGroup == null || string.IsNullOrWhiteSpace(currentSecGroup.UID))
|
if (domainContext == null || parentTraverseGroup == null || currentSecGroup == null || string.IsNullOrWhiteSpace(currentSecGroup.UID))
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ namespace LiamWorkflowActivities
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
allowSharePathEnsure,
|
allowSharePathEnsure,
|
||||||
false,
|
ntfsArea is cLiamNtfsFolder,
|
||||||
simulateOnly);
|
simulateOnly);
|
||||||
if (ensureResult == null)
|
if (ensureResult == null)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user