diff --git a/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs b/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs index d4ed161..a9b6a55 100644 --- a/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs +++ b/LiamNtfs/C4IT_IAM_SET/DataArea_FileSystem.cs @@ -711,10 +711,6 @@ namespace C4IT_IAM_SET if (i == lvl) { DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene."); - if (!WhatIf) - { - WaitForNewGlobalGroupsToBecomeResolvable(domainContext); - } foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups) { if (currentSecGroup == null) @@ -722,39 +718,17 @@ namespace C4IT_IAM_SET DefaultLogger.LogEntry(LogLevels.Error, "currentSecGroup ist null."); continue; } - using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, currentSecGroup.UID)) - { - if (groupPrincipal == null) - { - DefaultLogger.LogEntry(LogLevels.Debug, $"GroupPrincipal nicht gefunden für UID: {currentSecGroup.UID}"); - continue; - } + if (currentSecGroup.Scope != GroupScope.Global) + continue; - if (currentSecGroup.Scope == GroupScope.Global) - { - try - { - if (!parentTraverseGroup.Members.Contains(groupPrincipal)) - { - if (WhatIf) - { - resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde Mitglied '{groupPrincipal.Name}' erhalten."); - } - else - { - DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {groupPrincipal.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu"); - parentTraverseGroup.Members.Add(groupPrincipal); - parentTraverseGroup.Save(); - } - } - } - catch (Exception ex) - { - DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Hinzufügen der Gruppe: {ex.Message}"); - continue; - } - } + if (WhatIf) + { + resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde Mitglied '{currentSecGroup.Name}' erhalten."); + continue; } + + if (!TryEnsureGlobalGroupMembershipWithRetry(domainContext, parentTraverseGroup, currentSecGroup)) + continue; } traverseGroup = parentTraverseGroup; } @@ -772,9 +746,8 @@ namespace C4IT_IAM_SET } else { - DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {traverseGroup.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu"); - parentTraverseGroup.Members.Add(traverseGroup); - parentTraverseGroup.Save(); + if (!TryEnsureNestedTraverseGroupMembershipWithRetry(parentTraverseGroup, traverseGroup)) + continue; } } } @@ -832,32 +805,66 @@ namespace C4IT_IAM_SET } } - private void WaitForNewGlobalGroupsToBecomeResolvable(PrincipalContext domainContext) + private bool TryEnsureGlobalGroupMembershipWithRetry(PrincipalContext domainContext, GroupPrincipal parentTraverseGroup, IAM_SecurityGroup currentSecGroup) { - if (WhatIf || domainContext == null || newSecurityGroups?.IAM_SecurityGroups == null) - return; + if (domainContext == null || parentTraverseGroup == null || currentSecGroup == null || string.IsNullOrWhiteSpace(currentSecGroup.UID)) + return false; - var pendingGroups = newSecurityGroups.IAM_SecurityGroups - .Where(group => group != null - && group.Scope == GroupScope.Global - && group.CreatedNewEntry - && !string.IsNullOrWhiteSpace(group.UID)) - .ToList(); - if (pendingGroups.Count == 0) - return; + return RetryTraverseMembershipAction( + currentSecGroup.Name, + currentSecGroup.CreatedNewEntry, + () => + { + using (var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, currentSecGroup.UID)) + { + if (groupPrincipal == null) + return false; - var pendingNames = pendingGroups - .Select(group => group.Name) - .Where(name => !string.IsNullOrWhiteSpace(name)) - .ToList(); - var retryDelaysMs = new[] { 0, 250, 500, 1000, 2000, 5000 }; + if (parentTraverseGroup.Members.Contains(groupPrincipal)) + return true; + + DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {groupPrincipal.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu"); + parentTraverseGroup.Members.Add(groupPrincipal); + parentTraverseGroup.Save(); + return true; + } + }); + } + + private bool TryEnsureNestedTraverseGroupMembershipWithRetry(GroupPrincipal parentTraverseGroup, GroupPrincipal traverseGroup) + { + if (parentTraverseGroup == null || traverseGroup == null) + return false; + + return RetryTraverseMembershipAction( + traverseGroup.Name, + true, + () => + { + if (parentTraverseGroup.Members.Contains(traverseGroup)) + return true; + + DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {traverseGroup.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu"); + parentTraverseGroup.Members.Add(traverseGroup); + parentTraverseGroup.Save(); + return true; + }); + } + + private bool RetryTraverseMembershipAction(string memberName, bool allowRetry, Func tryAction) + { + if (tryAction == null) + return false; + + var retryDelaysMs = allowRetry + ? new[] { 0, 250, 500, 1000, 2000, 5000 } + : new[] { 0 }; var delayIndex = 0; - var maxWait = TimeSpan.FromMinutes(3); + var maxWait = allowRetry ? TimeSpan.FromMinutes(3) : TimeSpan.Zero; var waitStopwatch = Stopwatch.StartNew(); + Exception lastException = null; - DefaultLogger.LogEntry(LogLevels.Debug, $"Warte auf neue globale Gruppen fuer Traverse-Verschachtelung: {string.Join(", ", pendingNames)}"); - - while (pendingGroups.Count > 0 && waitStopwatch.Elapsed < maxWait) + while (true) { var delayMs = retryDelaysMs[Math.Min(delayIndex, retryDelaysMs.Length - 1)]; if (delayMs > 0) @@ -865,43 +872,30 @@ namespace C4IT_IAM_SET if (delayIndex < retryDelaysMs.Length - 1) delayIndex++; - for (var index = pendingGroups.Count - 1; index >= 0; index--) + try { - var pendingGroup = pendingGroups[index]; - try + if (tryAction()) { - using (var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, pendingGroup.UID)) - { - if (groupPrincipal == null) - continue; - - DefaultLogger.LogEntry(LogLevels.Debug, $"Neue globale Gruppe fuer Traverse-Verarbeitung aufloesbar: {pendingGroup.Name}"); - pendingGroups.RemoveAt(index); - } - } - catch (Exception ex) - { - DefaultLogger.LogEntry(LogLevels.Debug, $"Neue globale Gruppe '{pendingGroup.Name}' noch nicht aufloesbar: {ex.Message}"); + if (waitStopwatch.ElapsedMilliseconds > 0) + DefaultLogger.LogEntry(LogLevels.Debug, $"Traverse-Mitgliedschaft für '{memberName}' nach {waitStopwatch.Elapsed.TotalSeconds:F1}s erfolgreich."); + return true; } } + catch (Exception ex) + { + lastException = ex; + DefaultLogger.LogEntry(LogLevels.Debug, $"Traverse-Mitgliedschaft für '{memberName}' noch nicht möglich: {ex.Message}"); + } + + if (!allowRetry || waitStopwatch.Elapsed >= maxWait) + break; } - if (pendingGroups.Count > 0) - { - var unresolvedNames = pendingGroups - .Select(group => group.Name) - .Where(name => !string.IsNullOrWhiteSpace(name)) - .ToList(); - DefaultLogger.LogEntry(LogLevels.Warning, $"Nicht alle neuen globalen Gruppen waren nach {waitStopwatch.Elapsed.TotalSeconds:F1}s fuer Traverse-Verarbeitung aufloesbar: {string.Join(", ", unresolvedNames)}"); - } - else - { - DefaultLogger.LogEntry(LogLevels.Debug, $"Neue globale Gruppen nach {waitStopwatch.Elapsed.TotalSeconds:F1}s fuer Traverse-Verarbeitung aufloesbar."); - } + var suffix = lastException == null ? string.Empty : $" Letzte Exception: {lastException.Message}"; + DefaultLogger.LogEntry(LogLevels.Warning, $"Traverse-Mitgliedschaft für '{memberName}' konnte nach {waitStopwatch.Elapsed.TotalSeconds:F1}s nicht sichergestellt werden.{suffix}"); + return false; } - - private ResultToken checkFolder() { LogMethodBegin(MethodBase.GetCurrentMethod());