Add configurable NTFS group name formatting
This commit is contained in:
@@ -56,6 +56,8 @@ namespace C4IT.LIAM
|
|||||||
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";
|
private const string AdditionalConfigurationTraverseBoundaryPathKey = "NtfsTraverseBoundaryPath";
|
||||||
|
private const string AdditionalConfigurationGroupNameSanitizeReplacementKey = "NtfsGroupNameSanitizeReplacement";
|
||||||
|
private const string AdditionalConfigurationPreserveAdGroupNameCaseKey = "PreserveNtfsAdGroupNameCase";
|
||||||
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);
|
||||||
@@ -998,7 +1000,11 @@ namespace C4IT.LIAM
|
|||||||
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
|
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
|
||||||
CanManagePermissionsForPath = IsPermissionManagedFolderPath,
|
CanManagePermissionsForPath = IsPermissionManagedFolderPath,
|
||||||
CanManageTraversePermissionsForPath = IsTraversePermissionManagedPath,
|
CanManageTraversePermissionsForPath = IsTraversePermissionManagedPath,
|
||||||
forceStrictAdGroupNames = IsAdditionalConfigurationEnabled("ForceStrictAdGroupNames")
|
forceStrictAdGroupNames = IsAdditionalConfigurationEnabled("ForceStrictAdGroupNames"),
|
||||||
|
groupNameSanitizeReplacement = GetAdditionalConfigurationValueOrDefault(
|
||||||
|
AdditionalConfigurationGroupNameSanitizeReplacementKey,
|
||||||
|
Helper.DefaultGroupNameSanitizeReplacement),
|
||||||
|
preserveAdGroupNameCase = IsAdditionalConfigurationEnabled(AdditionalConfigurationPreserveAdGroupNameCaseKey)
|
||||||
};
|
};
|
||||||
engine.traverseBoundaryPath = GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey);
|
engine.traverseBoundaryPath = GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey);
|
||||||
|
|
||||||
@@ -1032,6 +1038,17 @@ namespace C4IT.LIAM
|
|||||||
return rawValue.Trim();
|
return rawValue.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetAdditionalConfigurationValueOrDefault(string key, string defaultValue)
|
||||||
|
{
|
||||||
|
if (AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
if (!AdditionalConfiguration.TryGetValue(key, out var rawValue))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
return rawValue == null ? string.Empty : rawValue.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsPermissionManagedFolderPath(string path)
|
public bool IsPermissionManagedFolderPath(string path)
|
||||||
{
|
{
|
||||||
return IsPermissionManagedPath(path, eNtfsPathKind.Folder);
|
return IsPermissionManagedPath(path, eNtfsPathKind.Folder);
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ namespace C4IT_IAM_SET
|
|||||||
public Func<string, bool> CanManageTraversePermissionsForPath;
|
public Func<string, bool> CanManageTraversePermissionsForPath;
|
||||||
public string traverseBoundaryPath;
|
public string traverseBoundaryPath;
|
||||||
public bool forceStrictAdGroupNames;
|
public bool forceStrictAdGroupNames;
|
||||||
|
public string groupNameSanitizeReplacement = Helper.DefaultGroupNameSanitizeReplacement;
|
||||||
|
public bool preserveAdGroupNameCase;
|
||||||
public bool WhatIf;
|
public bool WhatIf;
|
||||||
|
|
||||||
public int ReadACLPermission = 0x200A9;
|
public int ReadACLPermission = 0x200A9;
|
||||||
@@ -301,7 +303,8 @@ namespace C4IT_IAM_SET
|
|||||||
username = username,
|
username = username,
|
||||||
domainName = domainName,
|
domainName = domainName,
|
||||||
password = password,
|
password = password,
|
||||||
ForceStrictAdGroupNames = forceStrictAdGroupNames
|
ForceStrictAdGroupNames = forceStrictAdGroupNames,
|
||||||
|
PreserveAdGroupNameCase = preserveAdGroupNameCase
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,14 +582,14 @@ namespace C4IT_IAM_SET
|
|||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"relativePath vor Normalisierung: {relativePathRaw}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"relativePath vor Normalisierung: {relativePathRaw}");
|
||||||
|
|
||||||
var relativePathSegments = relativePathRaw.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
var relativePathSegments = relativePathRaw.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var sanitizedSegments = relativePathSegments.Select(Helper.SanitizePathSegment).ToArray();
|
var sanitizedSegments = relativePathSegments.Select(i => Helper.SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
|
||||||
var relativePath = sanitizedSegments.Length > 0 ? string.Join("_", sanitizedSegments) : string.Empty;
|
var relativePath = sanitizedSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(sanitizedSegments, groupNameSanitizeReplacement) : string.Empty;
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"relativePath nach Normalisierung: {relativePath}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"relativePath nach Normalisierung: {relativePath}");
|
||||||
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)), groupNameSanitizeReplacement);
|
||||||
var traverseTags = GetTraverseReplacementTags(parent.FullName);
|
var traverseTags = GetTraverseReplacementTags(parent.FullName);
|
||||||
var rootContext = Helper.GetRootPathTemplateContext(baseFolder);
|
var rootContext = Helper.GetRootPathTemplateContext(baseFolder, groupNameSanitizeReplacement);
|
||||||
var boundedTraverseContext = Helper.GetBoundedAdGroupTemplateContext(
|
var boundedTraverseContext = Helper.GetBoundedAdGroupTemplateContext(
|
||||||
traverseGroupTemplate.NamingTemplate,
|
traverseGroupTemplate.NamingTemplate,
|
||||||
true,
|
true,
|
||||||
@@ -597,7 +600,9 @@ namespace C4IT_IAM_SET
|
|||||||
Helper.MaxAdGroupNameLength,
|
Helper.MaxAdGroupNameLength,
|
||||||
$"Traverse fuer '{parent.FullName}'",
|
$"Traverse fuer '{parent.FullName}'",
|
||||||
"AD-Gruppenname",
|
"AD-Gruppenname",
|
||||||
rootContext);
|
rootContext,
|
||||||
|
preserveAdGroupNameCase,
|
||||||
|
groupNameSanitizeReplacement);
|
||||||
var boundedTraverseDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
|
var boundedTraverseDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
|
||||||
traverseGroupTemplate.DescriptionTemplate,
|
traverseGroupTemplate.DescriptionTemplate,
|
||||||
true,
|
true,
|
||||||
@@ -608,20 +613,28 @@ namespace C4IT_IAM_SET
|
|||||||
Helper.MaxAdGroupDescriptionLength,
|
Helper.MaxAdGroupDescriptionLength,
|
||||||
$"Traverse fuer '{parent.FullName}'",
|
$"Traverse fuer '{parent.FullName}'",
|
||||||
"AD-Gruppenbeschreibung",
|
"AD-Gruppenbeschreibung",
|
||||||
rootContext);
|
rootContext,
|
||||||
|
preserveAdGroupNameCase,
|
||||||
|
groupNameSanitizeReplacement);
|
||||||
var adjustedTraverseSegments = boundedTraverseContext.SanitizedSegments ?? Array.Empty<string>();
|
var adjustedTraverseSegments = boundedTraverseContext.SanitizedSegments ?? Array.Empty<string>();
|
||||||
var adjustedTraverseRelativePath = adjustedTraverseSegments.Length > 0 ? string.Join("_", adjustedTraverseSegments) : string.Empty;
|
var adjustedTraverseRelativePath = adjustedTraverseSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedTraverseSegments, groupNameSanitizeReplacement) : string.Empty;
|
||||||
var adjustedTraverseFolderName = boundedTraverseContext.FolderName;
|
var adjustedTraverseFolderName = boundedTraverseContext.FolderName;
|
||||||
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 ? Helper.JoinSanitizedPathSegments(adjustedTraverseDescriptionSegments, groupNameSanitizeReplacement) : string.Empty;
|
||||||
var adjustedTraverseDescriptionFolderName = boundedTraverseDescriptionContext.FolderName;
|
var adjustedTraverseDescriptionFolderName = boundedTraverseDescriptionContext.FolderName;
|
||||||
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext).ReplaceTags(traverseTags);
|
var traverseNameTemplate = Helper.ApplyAdGroupNameCasing(
|
||||||
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName, rootContext).ReplaceTags(traverseTags);
|
Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext, groupNameSanitizeReplacement).ReplaceTags(traverseTags),
|
||||||
|
preserveAdGroupNameCase);
|
||||||
|
var traverseDescriptionTemplate = Helper.ApplyAdGroupNameCasing(
|
||||||
|
Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName, rootContext, groupNameSanitizeReplacement).ReplaceTags(traverseTags),
|
||||||
|
preserveAdGroupNameCase);
|
||||||
|
|
||||||
string traverseRegex = null;
|
string traverseRegex = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext).ReplaceTags(traverseTags);
|
traverseRegex = Helper.ApplyAdGroupNameCasing(
|
||||||
|
Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext, groupNameSanitizeReplacement).ReplaceTags(traverseTags),
|
||||||
|
preserveAdGroupNameCase);
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -721,7 +734,7 @@ namespace C4IT_IAM_SET
|
|||||||
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen von newTraverseGroup: {ex.Message}");
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen von newTraverseGroup: {ex.Message}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (newSecurityGroups.GroupAllreadyExisting(newTraverseGroup.Name.ToUpper()) && loop < 20);
|
} while (newSecurityGroups.GroupAllreadyExisting(newTraverseGroup.Name) && loop < 20);
|
||||||
|
|
||||||
if (newTraverseGroup != null)
|
if (newTraverseGroup != null)
|
||||||
{
|
{
|
||||||
@@ -947,8 +960,8 @@ namespace C4IT_IAM_SET
|
|||||||
var visibleSegments = GetVisibleTraversePathSegments(currentPath);
|
var visibleSegments = GetVisibleTraversePathSegments(currentPath);
|
||||||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
{ "TRAVERSE_NAME", Helper.SanitizePathSegment(GetLastPathSegment(currentPath)) },
|
{ "TRAVERSE_NAME", Helper.SanitizePathSegment(GetLastPathSegment(currentPath), groupNameSanitizeReplacement) },
|
||||||
{ "TRAVERSE_VISIBLEPATH", string.Join("_", visibleSegments.Select(Helper.SanitizePathSegment)) }
|
{ "TRAVERSE_VISIBLEPATH", Helper.JoinSanitizedPathSegments(visibleSegments.Select(i => Helper.SanitizePathSegment(i, groupNameSanitizeReplacement)), groupNameSanitizeReplacement) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,7 +1332,10 @@ namespace C4IT_IAM_SET
|
|||||||
ReadACLPermission,
|
ReadACLPermission,
|
||||||
WriteACLPermission,
|
WriteACLPermission,
|
||||||
OwnerACLPermission,
|
OwnerACLPermission,
|
||||||
0);
|
0,
|
||||||
|
0,
|
||||||
|
groupNameSanitizeReplacement,
|
||||||
|
preserveAdGroupNameCase);
|
||||||
|
|
||||||
List<UserPrincipal> owners = getUserPrincipalBySid(ownerUserSids);
|
List<UserPrincipal> owners = getUserPrincipalBySid(ownerUserSids);
|
||||||
List<UserPrincipal> writers = getUserPrincipalBySid(writerUserSids);
|
List<UserPrincipal> writers = getUserPrincipalBySid(writerUserSids);
|
||||||
@@ -1482,7 +1498,10 @@ namespace C4IT_IAM_SET
|
|||||||
ReadACLPermission,
|
ReadACLPermission,
|
||||||
WriteACLPermission,
|
WriteACLPermission,
|
||||||
OwnerACLPermission,
|
OwnerACLPermission,
|
||||||
existingADGroupCount);
|
existingADGroupCount,
|
||||||
|
0,
|
||||||
|
groupNameSanitizeReplacement,
|
||||||
|
preserveAdGroupNameCase);
|
||||||
/*
|
/*
|
||||||
if (existingADGroupCount > 0 && !templates.All(t => t.Type == SecurityGroupType.Traverse || Regex.IsMatch(t.NamingTemplate, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})")))
|
if (existingADGroupCount > 0 && !templates.All(t => t.Type == SecurityGroupType.Traverse || Regex.IsMatch(t.NamingTemplate, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})")))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace C4IT_IAM_Engine
|
|||||||
public const int MaxAdGroupNameLength = 64;
|
public const int MaxAdGroupNameLength = 64;
|
||||||
public const int MaxAdGroupDescriptionLength = 1024;
|
public const int MaxAdGroupDescriptionLength = 1024;
|
||||||
public const int MaxAdGroupLoopDigits = 3;
|
public const int MaxAdGroupLoopDigits = 3;
|
||||||
|
public const string DefaultGroupNameSanitizeReplacement = "_";
|
||||||
private const int MinLeadingRelativePathSegmentLength = 3;
|
private const int MinLeadingRelativePathSegmentLength = 3;
|
||||||
private const int MinSingleLeadingRelativePathSegmentLength = 2;
|
private const int MinSingleLeadingRelativePathSegmentLength = 2;
|
||||||
private const int MinLastRelativePathSegmentLength = 12;
|
private const int MinLastRelativePathSegmentLength = 12;
|
||||||
@@ -34,6 +35,7 @@ namespace C4IT_IAM_Engine
|
|||||||
public string[] Segments { get; set; } = Array.Empty<string>();
|
public string[] Segments { get; set; } = Array.Empty<string>();
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public string Path { get; set; } = string.Empty;
|
public string Path { get; set; } = string.Empty;
|
||||||
|
public string PathSegmentSeparator { get; set; } = DefaultGroupNameSanitizeReplacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReplaceLoopTag(this string str, int loop)
|
public static string ReplaceLoopTag(this string str, int loop)
|
||||||
@@ -49,10 +51,15 @@ namespace C4IT_IAM_Engine
|
|||||||
}
|
}
|
||||||
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName)
|
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName)
|
||||||
{
|
{
|
||||||
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, null);
|
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, null, DefaultGroupNameSanitizeReplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName, RootPathTemplateContext rootContext)
|
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName, RootPathTemplateContext rootContext)
|
||||||
|
{
|
||||||
|
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext, DefaultGroupNameSanitizeReplacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName, RootPathTemplateContext rootContext, string pathSegmentSeparator)
|
||||||
{
|
{
|
||||||
if (templateValue == null)
|
if (templateValue == null)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
@@ -75,7 +82,7 @@ namespace C4IT_IAM_Engine
|
|||||||
|
|
||||||
var segmentCount = Math.Min(sanitizedSegments.Length, segmentIndex + 1);
|
var segmentCount = Math.Min(sanitizedSegments.Length, segmentIndex + 1);
|
||||||
var skip = sanitizedSegments.Length - segmentCount;
|
var skip = sanitizedSegments.Length - segmentCount;
|
||||||
return string.Join("_", sanitizedSegments.Skip(skip));
|
return JoinSanitizedPathSegments(sanitizedSegments.Skip(skip), pathSegmentSeparator);
|
||||||
}, RegexOptions.IgnoreCase);
|
}, RegexOptions.IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,22 +90,28 @@ namespace C4IT_IAM_Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath)
|
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath)
|
||||||
|
{
|
||||||
|
return GetRootPathTemplateContext(rootPath, DefaultGroupNameSanitizeReplacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath, string groupNameSanitizeReplacement)
|
||||||
{
|
{
|
||||||
var segments = SplitPathSegments(rootPath);
|
var segments = SplitPathSegments(rootPath);
|
||||||
if (segments.Length == 0)
|
if (segments.Length == 0)
|
||||||
return new RootPathTemplateContext();
|
return new RootPathTemplateContext();
|
||||||
|
|
||||||
var isUncPath = (rootPath ?? string.Empty).Trim().Replace('/', '\\').StartsWith(@"\\", StringComparison.Ordinal);
|
var isUncPath = (rootPath ?? string.Empty).Trim().Replace('/', '\\').StartsWith(@"\\", StringComparison.Ordinal);
|
||||||
var server = isUncPath ? SanitizePathSegment(segments[0]) : string.Empty;
|
var server = isUncPath ? SanitizePathSegment(segments[0], groupNameSanitizeReplacement) : string.Empty;
|
||||||
var pathSegments = isUncPath ? segments.Skip(1).ToArray() : segments;
|
var pathSegments = isUncPath ? segments.Skip(1).ToArray() : segments;
|
||||||
var sanitizedPathSegments = pathSegments.Select(SanitizePathSegment).ToArray();
|
var sanitizedPathSegments = pathSegments.Select(i => SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
|
||||||
|
|
||||||
return new RootPathTemplateContext
|
return new RootPathTemplateContext
|
||||||
{
|
{
|
||||||
Server = server,
|
Server = server,
|
||||||
Segments = sanitizedPathSegments,
|
Segments = sanitizedPathSegments,
|
||||||
Name = sanitizedPathSegments.Length == 0 ? string.Empty : sanitizedPathSegments[sanitizedPathSegments.Length - 1],
|
Name = sanitizedPathSegments.Length == 0 ? string.Empty : sanitizedPathSegments[sanitizedPathSegments.Length - 1],
|
||||||
Path = sanitizedPathSegments.Length == 0 ? string.Empty : string.Join("_", sanitizedPathSegments)
|
Path = sanitizedPathSegments.Length == 0 ? string.Empty : JoinSanitizedPathSegments(sanitizedPathSegments, groupNameSanitizeReplacement),
|
||||||
|
PathSegmentSeparator = NormalizeGroupNameSanitizeReplacement(groupNameSanitizeReplacement)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,13 +125,15 @@ namespace C4IT_IAM_Engine
|
|||||||
int maxLength,
|
int maxLength,
|
||||||
string logContext,
|
string logContext,
|
||||||
string valueLabel = "AD-Gruppenname",
|
string valueLabel = "AD-Gruppenname",
|
||||||
RootPathTemplateContext rootContext = null)
|
RootPathTemplateContext rootContext = null,
|
||||||
|
bool preserveCase = false,
|
||||||
|
string pathSegmentSeparator = DefaultGroupNameSanitizeReplacement)
|
||||||
{
|
{
|
||||||
var effectiveSegments = (sanitizedSegments ?? Array.Empty<string>()).Where(i => i != null).ToArray();
|
var effectiveSegments = (sanitizedSegments ?? Array.Empty<string>()).Where(i => i != null).ToArray();
|
||||||
var effectiveFolderName = folderName ?? string.Empty;
|
var effectiveFolderName = folderName ?? string.Empty;
|
||||||
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
|
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath, pathSegmentSeparator);
|
||||||
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
|
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
|
||||||
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
|
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
|
||||||
var usesRelativePath = allowRelativePath && Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*RELATIVEPATH", RegexOptions.IgnoreCase);
|
var usesRelativePath = allowRelativePath && Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*RELATIVEPATH", RegexOptions.IgnoreCase);
|
||||||
var usesName = Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*NAME\s*}}", RegexOptions.IgnoreCase);
|
var usesName = Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*NAME\s*}}", RegexOptions.IgnoreCase);
|
||||||
var strategy = string.Empty;
|
var strategy = string.Empty;
|
||||||
@@ -144,19 +159,21 @@ namespace C4IT_IAM_Engine
|
|||||||
if (!changed)
|
if (!changed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
|
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath, pathSegmentSeparator);
|
||||||
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
|
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
|
||||||
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
|
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
var initialValue = MaterializeTemplateValue(
|
var initialValue = MaterializeTemplateValue(
|
||||||
templateValue,
|
templateValue,
|
||||||
allowRelativePath,
|
allowRelativePath,
|
||||||
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath),
|
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath, pathSegmentSeparator),
|
||||||
sanitizedSegments,
|
sanitizedSegments,
|
||||||
folderName,
|
folderName,
|
||||||
replacementTags,
|
replacementTags,
|
||||||
rootContext);
|
rootContext,
|
||||||
|
preserveCase,
|
||||||
|
pathSegmentSeparator);
|
||||||
var result = new BoundedTemplateContext
|
var result = new BoundedTemplateContext
|
||||||
{
|
{
|
||||||
SanitizedSegments = effectiveSegments,
|
SanitizedSegments = effectiveSegments,
|
||||||
@@ -184,11 +201,50 @@ namespace C4IT_IAM_Engine
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static string SanitizePathSegment(string segment)
|
public static string SanitizePathSegment(string segment)
|
||||||
|
{
|
||||||
|
return SanitizePathSegment(segment, DefaultGroupNameSanitizeReplacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SanitizePathSegment(string segment, string groupNameSanitizeReplacement)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(segment))
|
if (string.IsNullOrEmpty(segment))
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
return Regex.Replace(segment, @"[\s\-]", "_");
|
var replacement = NormalizeGroupNameSanitizeReplacement(groupNameSanitizeReplacement);
|
||||||
|
return Regex.Replace(segment, @"[\s\-]", match => replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NormalizeGroupNameSanitizeReplacement(string replacement)
|
||||||
|
{
|
||||||
|
if (replacement == null)
|
||||||
|
return DefaultGroupNameSanitizeReplacement;
|
||||||
|
|
||||||
|
var trimmed = replacement.Trim();
|
||||||
|
if (trimmed.Equals("<empty>", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| trimmed.Equals("empty", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| trimmed.Equals("none", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| trimmed.Equals("remove", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string JoinSanitizedPathSegments(IEnumerable<string> sanitizedSegments, string groupNameSanitizeReplacement)
|
||||||
|
{
|
||||||
|
if (sanitizedSegments == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return string.Join(NormalizeGroupNameSanitizeReplacement(groupNameSanitizeReplacement), sanitizedSegments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ApplyAdGroupNameCasing(string value, bool preserveCase)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return preserveCase ? value : value.ToUpper();
|
||||||
}
|
}
|
||||||
public static void CreatePathWithWriteAccess(string FilePath)
|
public static void CreatePathWithWriteAccess(string FilePath)
|
||||||
{
|
{
|
||||||
@@ -219,11 +275,14 @@ namespace C4IT_IAM_Engine
|
|||||||
string[] sanitizedSegments,
|
string[] sanitizedSegments,
|
||||||
string folderName,
|
string folderName,
|
||||||
IDictionary<string, string> replacementTags,
|
IDictionary<string, string> replacementTags,
|
||||||
RootPathTemplateContext rootContext)
|
RootPathTemplateContext rootContext,
|
||||||
|
bool preserveCase,
|
||||||
|
string pathSegmentSeparator)
|
||||||
{
|
{
|
||||||
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext)
|
var materializedValue = ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext, pathSegmentSeparator)
|
||||||
.ReplaceTags(replacementTags)
|
.ReplaceTags(replacementTags);
|
||||||
.ToUpper();
|
|
||||||
|
return ApplyAdGroupNameCasing(materializedValue, preserveCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string MaterializeTemplateValueForLength(
|
private static string MaterializeTemplateValueForLength(
|
||||||
@@ -233,10 +292,12 @@ namespace C4IT_IAM_Engine
|
|||||||
string[] sanitizedSegments,
|
string[] sanitizedSegments,
|
||||||
string folderName,
|
string folderName,
|
||||||
IDictionary<string, string> replacementTags,
|
IDictionary<string, string> replacementTags,
|
||||||
RootPathTemplateContext rootContext)
|
RootPathTemplateContext rootContext,
|
||||||
|
bool preserveCase,
|
||||||
|
string pathSegmentSeparator)
|
||||||
{
|
{
|
||||||
return NormalizeLoopPlaceholderLength(
|
return NormalizeLoopPlaceholderLength(
|
||||||
MaterializeTemplateValue(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, replacementTags, rootContext));
|
MaterializeTemplateValue(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ApplyRootPathPlaceholders(string templateValue, RootPathTemplateContext rootContext)
|
private static string ApplyRootPathPlaceholders(string templateValue, RootPathTemplateContext rootContext)
|
||||||
@@ -257,7 +318,7 @@ namespace C4IT_IAM_Engine
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
var take = Math.Min(segmentCount, segments.Length);
|
var take = Math.Min(segmentCount, segments.Length);
|
||||||
return take == 0 ? string.Empty : string.Join("_", segments.Skip(segments.Length - take));
|
return take == 0 ? string.Empty : JoinSanitizedPathSegments(segments.Skip(segments.Length - take), context.PathSegmentSeparator);
|
||||||
}, RegexOptions.IgnoreCase);
|
}, RegexOptions.IgnoreCase);
|
||||||
result = Regex.Replace(result, @"{{\s*ROOT_SEGMENT\s*\(\s*(\d+)\s*\)\s*}}", match =>
|
result = Regex.Replace(result, @"{{\s*ROOT_SEGMENT\s*\(\s*(\d+)\s*\)\s*}}", match =>
|
||||||
{
|
{
|
||||||
@@ -296,10 +357,10 @@ namespace C4IT_IAM_Engine
|
|||||||
.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath)
|
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath, string pathSegmentSeparator)
|
||||||
{
|
{
|
||||||
if (sanitizedSegments != null && sanitizedSegments.Length > 0)
|
if (sanitizedSegments != null && sanitizedSegments.Length > 0)
|
||||||
return string.Join("_", sanitizedSegments);
|
return JoinSanitizedPathSegments(sanitizedSegments, pathSegmentSeparator);
|
||||||
|
|
||||||
return fallbackRelativePath ?? string.Empty;
|
return fallbackRelativePath ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace C4IT_IAM_Engine
|
|||||||
public string username;
|
public string username;
|
||||||
public SecureString password;
|
public SecureString password;
|
||||||
public bool ForceStrictAdGroupNames;
|
public bool ForceStrictAdGroupNames;
|
||||||
|
public bool PreserveAdGroupNameCase;
|
||||||
|
|
||||||
public List<IAM_SecurityGroup> IAM_SecurityGroups;
|
public List<IAM_SecurityGroup> IAM_SecurityGroups;
|
||||||
public string rootUID;
|
public string rootUID;
|
||||||
@@ -53,7 +54,7 @@ namespace C4IT_IAM_Engine
|
|||||||
};
|
};
|
||||||
DirectorySearcher dSearch = new DirectorySearcher(entry)
|
DirectorySearcher dSearch = new DirectorySearcher(entry)
|
||||||
{
|
{
|
||||||
Filter = "(&(CN=" + s.Name.ToUpper() + ")(objectClass=group))"
|
Filter = "(&(CN=" + GetConfiguredGroupName(s.Name) + ")(objectClass=group))"
|
||||||
};
|
};
|
||||||
dSearch.PageSize = 100000;
|
dSearch.PageSize = 100000;
|
||||||
SearchResultCollection sr = dSearch.FindAll();
|
SearchResultCollection sr = dSearch.FindAll();
|
||||||
@@ -92,7 +93,7 @@ namespace C4IT_IAM_Engine
|
|||||||
};
|
};
|
||||||
DirectorySearcher dSearch = new DirectorySearcher(entry)
|
DirectorySearcher dSearch = new DirectorySearcher(entry)
|
||||||
{
|
{
|
||||||
Filter = "(&(CN=" + CN.ToUpper() + ")(objectClass=group))"
|
Filter = "(&(CN=" + GetConfiguredGroupName(CN) + ")(objectClass=group))"
|
||||||
};
|
};
|
||||||
dSearch.PageSize = 100000;
|
dSearch.PageSize = 100000;
|
||||||
SearchResultCollection sr = dSearch.FindAll();
|
SearchResultCollection sr = dSearch.FindAll();
|
||||||
@@ -129,7 +130,9 @@ namespace C4IT_IAM_Engine
|
|||||||
int writeACLPermission,
|
int writeACLPermission,
|
||||||
int ownerACLPermission,
|
int ownerACLPermission,
|
||||||
int loop = 0,
|
int loop = 0,
|
||||||
int existingADGroupCount = 0)
|
int existingADGroupCount = 0,
|
||||||
|
string groupNameSanitizeReplacement = Helper.DefaultGroupNameSanitizeReplacement,
|
||||||
|
bool preserveAdGroupNameCase = false)
|
||||||
{
|
{
|
||||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
try
|
try
|
||||||
@@ -145,12 +148,12 @@ namespace C4IT_IAM_Engine
|
|||||||
var relativePathRaw = DataArea.GetRelativePath(newFolderPath, baseFolder).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
var relativePathRaw = DataArea.GetRelativePath(newFolderPath, baseFolder).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
relativePathRaw = relativePathRaw.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
relativePathRaw = relativePathRaw.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||||
var relativePathSegments = relativePathRaw.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
var relativePathSegments = relativePathRaw.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var sanitizedSegments = relativePathSegments.Select(Helper.SanitizePathSegment).ToArray();
|
var sanitizedSegments = relativePathSegments.Select(i => Helper.SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
|
||||||
var relativePath = sanitizedSegments.Length > 0 ? string.Join("_", sanitizedSegments) : string.Empty;
|
var relativePath = sanitizedSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(sanitizedSegments, groupNameSanitizeReplacement) : string.Empty;
|
||||||
var folderName = sanitizedSegments.Length > 0
|
var folderName = sanitizedSegments.Length > 0
|
||||||
? sanitizedSegments[sanitizedSegments.Length - 1]
|
? sanitizedSegments[sanitizedSegments.Length - 1]
|
||||||
: Helper.SanitizePathSegment(Path.GetFileName(newFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
|
: Helper.SanitizePathSegment(Path.GetFileName(newFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)), groupNameSanitizeReplacement);
|
||||||
var rootContext = Helper.GetRootPathTemplateContext(baseFolder);
|
var rootContext = Helper.GetRootPathTemplateContext(baseFolder, groupNameSanitizeReplacement);
|
||||||
|
|
||||||
foreach (var template in resolvedTemplates)
|
foreach (var template in resolvedTemplates)
|
||||||
{
|
{
|
||||||
@@ -209,7 +212,9 @@ namespace C4IT_IAM_Engine
|
|||||||
Helper.MaxAdGroupNameLength,
|
Helper.MaxAdGroupNameLength,
|
||||||
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
|
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
|
||||||
"AD-Gruppenname",
|
"AD-Gruppenname",
|
||||||
rootContext);
|
rootContext,
|
||||||
|
preserveAdGroupNameCase,
|
||||||
|
groupNameSanitizeReplacement);
|
||||||
|
|
||||||
var boundedDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
|
var boundedDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
|
||||||
template.DescriptionTemplate,
|
template.DescriptionTemplate,
|
||||||
@@ -221,27 +226,32 @@ namespace C4IT_IAM_Engine
|
|||||||
Helper.MaxAdGroupDescriptionLength,
|
Helper.MaxAdGroupDescriptionLength,
|
||||||
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
|
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
|
||||||
"AD-Gruppenbeschreibung",
|
"AD-Gruppenbeschreibung",
|
||||||
rootContext);
|
rootContext,
|
||||||
|
preserveAdGroupNameCase,
|
||||||
|
groupNameSanitizeReplacement);
|
||||||
|
|
||||||
var adjustedNameSegments = boundedNameContext.SanitizedSegments ?? Array.Empty<string>();
|
var adjustedNameSegments = boundedNameContext.SanitizedSegments ?? Array.Empty<string>();
|
||||||
var adjustedNameRelativePath = adjustedNameSegments.Length > 0 ? string.Join("_", adjustedNameSegments) : string.Empty;
|
var adjustedNameRelativePath = adjustedNameSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedNameSegments, groupNameSanitizeReplacement) : string.Empty;
|
||||||
var adjustedNameFolderName = boundedNameContext.FolderName;
|
var adjustedNameFolderName = boundedNameContext.FolderName;
|
||||||
var adjustedDescriptionSegments = boundedDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
|
var adjustedDescriptionSegments = boundedDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
|
||||||
var adjustedDescriptionRelativePath = adjustedDescriptionSegments.Length > 0 ? string.Join("_", adjustedDescriptionSegments) : string.Empty;
|
var adjustedDescriptionRelativePath = adjustedDescriptionSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedDescriptionSegments, groupNameSanitizeReplacement) : string.Empty;
|
||||||
var adjustedDescriptionFolderName = boundedDescriptionContext.FolderName;
|
var adjustedDescriptionFolderName = boundedDescriptionContext.FolderName;
|
||||||
|
|
||||||
template.NamingTemplate = Helper.ApplyTemplatePlaceholders(template.NamingTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext)
|
template.NamingTemplate = Helper.ApplyAdGroupNameCasing(
|
||||||
.ReplaceTags(customTags).ReplaceTags(tags)
|
Helper.ApplyTemplatePlaceholders(template.NamingTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext, groupNameSanitizeReplacement)
|
||||||
.ToUpper();
|
.ReplaceTags(customTags).ReplaceTags(tags),
|
||||||
|
preserveAdGroupNameCase);
|
||||||
|
|
||||||
template.DescriptionTemplate = Helper.ApplyTemplatePlaceholders(template.DescriptionTemplate, template.Type != SecurityGroupType.Traverse, adjustedDescriptionRelativePath, adjustedDescriptionSegments, adjustedDescriptionFolderName, rootContext)
|
template.DescriptionTemplate = Helper.ApplyAdGroupNameCasing(
|
||||||
.ReplaceTags(customTags).ReplaceTags(tags)
|
Helper.ApplyTemplatePlaceholders(template.DescriptionTemplate, template.Type != SecurityGroupType.Traverse, adjustedDescriptionRelativePath, adjustedDescriptionSegments, adjustedDescriptionFolderName, rootContext, groupNameSanitizeReplacement)
|
||||||
.ToUpper();
|
.ReplaceTags(customTags).ReplaceTags(tags),
|
||||||
|
preserveAdGroupNameCase);
|
||||||
|
|
||||||
|
|
||||||
template.WildcardTemplate = Helper.ApplyTemplatePlaceholders(template.WildcardTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext)
|
template.WildcardTemplate = Helper.ApplyAdGroupNameCasing(
|
||||||
.ReplaceTags(customTags).ReplaceTags(tags)
|
Helper.ApplyTemplatePlaceholders(template.WildcardTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext, groupNameSanitizeReplacement)
|
||||||
.ToUpper();
|
.ReplaceTags(customTags).ReplaceTags(tags),
|
||||||
|
preserveAdGroupNameCase);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +439,7 @@ namespace C4IT_IAM_Engine
|
|||||||
|
|
||||||
DirectorySearcher search = new DirectorySearcher(entry)
|
DirectorySearcher search = new DirectorySearcher(entry)
|
||||||
{
|
{
|
||||||
Filter = "(&(objectClass=group)(sAMAccountName=" + groupName.ToUpper() + "))"
|
Filter = "(&(objectClass=group)(sAMAccountName=" + GetConfiguredGroupName(groupName) + "))"
|
||||||
};
|
};
|
||||||
search.PageSize = 100000;
|
search.PageSize = 100000;
|
||||||
|
|
||||||
@@ -718,13 +728,17 @@ namespace C4IT_IAM_Engine
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
secGroup.CreatedNewEntry = false;
|
secGroup.CreatedNewEntry = false;
|
||||||
if (!GroupAllreadyExisting(secGroup.Name.ToUpper()))
|
var groupName = GetConfiguredGroupName(secGroup.Name);
|
||||||
|
secGroup.Name = groupName;
|
||||||
|
secGroup.technicalName = "CN=" + groupName + "," + ouPath;
|
||||||
|
|
||||||
|
if (!GroupAllreadyExisting(groupName))
|
||||||
{
|
{
|
||||||
|
|
||||||
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName + "/" + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName + "/" + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Creating ad entry with CN / sAmAccountName: {secGroup.Name.ToUpper()}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Creating ad entry with CN / sAmAccountName: {groupName}");
|
||||||
DirectoryEntry group = entry.Children.Add("CN=" + secGroup.Name.ToUpper(), "group");
|
DirectoryEntry group = entry.Children.Add("CN=" + groupName, "group");
|
||||||
group.Properties["sAmAccountName"].Value = secGroup.Name.ToUpper();
|
group.Properties["sAmAccountName"].Value = groupName;
|
||||||
if (users != null && secGroup.Scope == GroupScope.Global)
|
if (users != null && secGroup.Scope == GroupScope.Global)
|
||||||
{
|
{
|
||||||
foreach (var user in users)
|
foreach (var user in users)
|
||||||
@@ -749,7 +763,7 @@ namespace C4IT_IAM_Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
group.CommitChanges();
|
group.CommitChanges();
|
||||||
DirectoryEntry ent = new DirectoryEntry("LDAP://" + domainName + "/" + "CN =" + secGroup.Name.ToUpper() + "," + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
DirectoryEntry ent = new DirectoryEntry("LDAP://" + domainName + "/" + "CN=" + groupName + "," + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
||||||
|
|
||||||
var objectid = SecurityGroups.getSID(ent);
|
var objectid = SecurityGroups.getSID(ent);
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Security group created in ad: {secGroup.technicalName}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Security group created in ad: {secGroup.technicalName}");
|
||||||
@@ -778,6 +792,11 @@ namespace C4IT_IAM_Engine
|
|||||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetConfiguredGroupName(string groupName)
|
||||||
|
{
|
||||||
|
return Helper.ApplyAdGroupNameCasing(groupName, PreserveAdGroupNameCase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public enum GroupScopeValues : int
|
public enum GroupScopeValues : int
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ stehen folgende Root-Platzhalter zur Verfuegung:
|
|||||||
- `{{ROOT_SEGMENT(0)}}`: erstes Root-Segment nach dem Server, z.B. `file_shares`
|
- `{{ROOT_SEGMENT(0)}}`: erstes Root-Segment nach dem Server, z.B. `file_shares`
|
||||||
- `{{ROOT_SEGMENT(1)}}`: zweites Root-Segment nach dem Server, z.B. `share2`
|
- `{{ROOT_SEGMENT(1)}}`: zweites Root-Segment nach dem Server, z.B. `share2`
|
||||||
|
|
||||||
Root-Segmente werden wie Ordnersegmente sanitisiert. Leerzeichen und Bindestriche werden zu `_`. Nicht vorhandene `ROOT_SEGMENT(n)`-Werte werden zu einem leeren String. Wenn `ROOT_PATH(n)` mehr Segmente anfordert als vorhanden sind, werden alle vorhandenen Root-Segmente verwendet.
|
Root-Segmente werden wie Ordnersegmente sanitisiert. Leerzeichen und Bindestriche werden standardmaessig zu `_`. Nicht vorhandene `ROOT_SEGMENT(n)`-Werte werden zu einem leeren String. Wenn `ROOT_PATH(n)` mehr Segmente anfordert als vorhanden sind, werden alle vorhandenen Root-Segmente verwendet.
|
||||||
|
|
||||||
Beispiel:
|
Beispiel:
|
||||||
|
|
||||||
@@ -231,6 +231,35 @@ ACL_FILE_SHARES_SHARE2.TEST33_O
|
|||||||
|
|
||||||
Die bestehenden Platzhalter `{{NAME}}`, `{{RELATIVEPATH}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}` bleiben unveraendert.
|
Die bestehenden Platzhalter `{{NAME}}`, `{{RELATIVEPATH}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}` bleiben unveraendert.
|
||||||
|
|
||||||
|
### 11. Konfigurierbares Sanitizing und Gross-/Kleinschreibung fuer NTFS-Gruppennamen
|
||||||
|
|
||||||
|
Die Normalisierung der dynamischen Pfadbestandteile wird ueber `AdditionalConfiguration` gesteuert. Die Werte kommen wie `EnsureNtfsPermissionGroups` aus `C4IT_GCC_DataArea_Collector_AdditionalAttributes`.
|
||||||
|
|
||||||
|
`NtfsGroupNameSanitizeReplacement` steuert das Ersatz-/Trennzeichen fuer dynamische Pfadbestandteile:
|
||||||
|
|
||||||
|
- nicht gesetzt: bisheriges Verhalten, Leerzeichen und Bindestriche werden durch `_` ersetzt und Pfadsegmente werden mit `_` verbunden
|
||||||
|
- gesetzt auf z.B. `.`: Leerzeichen und Bindestriche werden durch `.` ersetzt und Pfadsegmente werden mit `.` verbunden
|
||||||
|
- gesetzt auf einen leeren Wert, `<empty>`, `empty`, `none` oder `remove`: Leerzeichen/Bindestriche werden entfernt und Pfadsegmente ohne Trennzeichen verbunden
|
||||||
|
|
||||||
|
Die Einstellung wirkt auf `{{NAME}}`, `{{RELATIVEPATH}}`, `{{ROOT_*}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}`. Sie aendert nicht die statischen Zeichen, die direkt im Naming Template stehen. Soll z.B. zwischen Root und Ordner immer ein Punkt stehen, bleibt der Punkt Bestandteil des Templates.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2
|
||||||
|
Zielpfad=\\SRVWSM001.imagoverum.com\file_shares\share2\test-33
|
||||||
|
NamingTemplate={{ADGroupPrefix}}_{{ROOT_NAME}}.{{NAME}}{{GROUPTYPEPOSTFIX}}
|
||||||
|
NtfsGroupNameSanitizeReplacement=
|
||||||
|
```
|
||||||
|
|
||||||
|
ergibt bei deaktivierter automatischer Grossschreibung:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ACL_share2.test33_O
|
||||||
|
```
|
||||||
|
|
||||||
|
`PreserveNtfsAdGroupNameCase=1` unterbindet die bisher automatische Grossschreibung der erzeugten AD-Gruppennamen. Ohne diesen Schalter bleibt das bisherige Verhalten erhalten und die generierten CN-/sAMAccountName-Werte werden in Grossbuchstaben erzeugt.
|
||||||
|
|
||||||
## Matching-Regeln
|
## Matching-Regeln
|
||||||
|
|
||||||
Empfohlene Semantik:
|
Empfohlene Semantik:
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ Das bedeutet:
|
|||||||
- kein Caching ueber den gesamten Lauf
|
- kein Caching ueber den gesamten Lauf
|
||||||
- Owner-/Write-/Read-Gruppen sowie Traverse-Gruppen werden analog zur Ordner-Neuanlage sichergestellt
|
- Owner-/Write-/Read-Gruppen sowie Traverse-Gruppen werden analog zur Ordner-Neuanlage sichergestellt
|
||||||
- eine optionale Traverse-Grenze kann ueber `NtfsTraverseBoundaryPath` aus `AdditionalConfiguration` gesetzt werden
|
- eine optionale Traverse-Grenze kann ueber `NtfsTraverseBoundaryPath` aus `AdditionalConfiguration` gesetzt werden
|
||||||
|
- das Sanitizing dynamischer Pfadbestandteile kann ueber `NtfsGroupNameSanitizeReplacement` angepasst werden; `PreserveNtfsAdGroupNameCase=1` unterbindet die automatische Grossschreibung neuer AD-Gruppennamen
|
||||||
|
|
||||||
### 2. Create-/Ensure-Pfad
|
### 2. Create-/Ensure-Pfad
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user