Add configurable NTFS group name formatting

This commit is contained in:
Meik
2026-05-08 21:45:36 +02:00
parent b9edd16cab
commit 2b460ccc1a
6 changed files with 215 additions and 69 deletions

View File

@@ -14,6 +14,7 @@ namespace C4IT_IAM_Engine
public const int MaxAdGroupNameLength = 64;
public const int MaxAdGroupDescriptionLength = 1024;
public const int MaxAdGroupLoopDigits = 3;
public const string DefaultGroupNameSanitizeReplacement = "_";
private const int MinLeadingRelativePathSegmentLength = 3;
private const int MinSingleLeadingRelativePathSegmentLength = 2;
private const int MinLastRelativePathSegmentLength = 12;
@@ -34,6 +35,7 @@ namespace C4IT_IAM_Engine
public string[] Segments { get; set; } = Array.Empty<string>();
public string Name { 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)
@@ -49,10 +51,15 @@ namespace C4IT_IAM_Engine
}
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)
{
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)
return string.Empty;
@@ -75,7 +82,7 @@ namespace C4IT_IAM_Engine
var segmentCount = Math.Min(sanitizedSegments.Length, segmentIndex + 1);
var skip = sanitizedSegments.Length - segmentCount;
return string.Join("_", sanitizedSegments.Skip(skip));
return JoinSanitizedPathSegments(sanitizedSegments.Skip(skip), pathSegmentSeparator);
}, RegexOptions.IgnoreCase);
}
@@ -83,22 +90,28 @@ namespace C4IT_IAM_Engine
}
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath)
{
return GetRootPathTemplateContext(rootPath, DefaultGroupNameSanitizeReplacement);
}
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath, string groupNameSanitizeReplacement)
{
var segments = SplitPathSegments(rootPath);
if (segments.Length == 0)
return new RootPathTemplateContext();
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 sanitizedPathSegments = pathSegments.Select(SanitizePathSegment).ToArray();
var sanitizedPathSegments = pathSegments.Select(i => SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
return new RootPathTemplateContext
{
Server = server,
Segments = sanitizedPathSegments,
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,
string logContext,
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 effectiveFolderName = folderName ?? string.Empty;
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath, pathSegmentSeparator);
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
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 usesName = Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*NAME\s*}}", RegexOptions.IgnoreCase);
var strategy = string.Empty;
@@ -144,19 +159,21 @@ namespace C4IT_IAM_Engine
if (!changed)
break;
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath, pathSegmentSeparator);
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
}
var initialValue = MaterializeTemplateValue(
templateValue,
allowRelativePath,
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath),
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath, pathSegmentSeparator),
sanitizedSegments,
folderName,
replacementTags,
rootContext);
rootContext,
preserveCase,
pathSegmentSeparator);
var result = new BoundedTemplateContext
{
SanitizedSegments = effectiveSegments,
@@ -184,11 +201,50 @@ namespace C4IT_IAM_Engine
return result;
}
public static string SanitizePathSegment(string segment)
{
return SanitizePathSegment(segment, DefaultGroupNameSanitizeReplacement);
}
public static string SanitizePathSegment(string segment, string groupNameSanitizeReplacement)
{
if (string.IsNullOrEmpty(segment))
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)
{
@@ -219,11 +275,14 @@ namespace C4IT_IAM_Engine
string[] sanitizedSegments,
string folderName,
IDictionary<string, string> replacementTags,
RootPathTemplateContext rootContext)
RootPathTemplateContext rootContext,
bool preserveCase,
string pathSegmentSeparator)
{
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext)
.ReplaceTags(replacementTags)
.ToUpper();
var materializedValue = ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext, pathSegmentSeparator)
.ReplaceTags(replacementTags);
return ApplyAdGroupNameCasing(materializedValue, preserveCase);
}
private static string MaterializeTemplateValueForLength(
@@ -233,10 +292,12 @@ namespace C4IT_IAM_Engine
string[] sanitizedSegments,
string folderName,
IDictionary<string, string> replacementTags,
RootPathTemplateContext rootContext)
RootPathTemplateContext rootContext,
bool preserveCase,
string pathSegmentSeparator)
{
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)
@@ -257,7 +318,7 @@ namespace C4IT_IAM_Engine
return string.Empty;
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);
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);
}
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath)
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath, string pathSegmentSeparator)
{
if (sanitizedSegments != null && sanitizedSegments.Length > 0)
return string.Join("_", sanitizedSegments);
return JoinSanitizedPathSegments(sanitizedSegments, pathSegmentSeparator);
return fallbackRelativePath ?? string.Empty;
}