1314 lines
63 KiB
C#
1314 lines
63 KiB
C#
using C4IT_IAM;
|
|
using C4IT_IAM_Engine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.DirectoryServices;
|
|
using System.DirectoryServices.AccountManagement;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Security;
|
|
using System.Security.AccessControl;
|
|
using System.Security.Principal;
|
|
using System.Text.RegularExpressions;
|
|
using C4IT.Logging;
|
|
|
|
using static C4IT.Logging.cLogManager;
|
|
using System.Reflection;
|
|
using C4IT_IAM_GET;
|
|
|
|
|
|
namespace C4IT_IAM_SET
|
|
{
|
|
public class DataArea_FileSystem
|
|
{
|
|
public const string constApplicationDataPath = "%ProgramData%\\Consulting4IT GmbH\\LIAM";
|
|
|
|
public string domainName;
|
|
public string username;
|
|
public SecureString password;
|
|
private cNetworkConnection Connection;
|
|
|
|
public string groupPrefix;
|
|
public string groupOUPath;
|
|
public string baseFolder;
|
|
public string newFolderPath;
|
|
public string newFolder;
|
|
public string newFolderParent;
|
|
|
|
public PermissionGroupStrategy groupPermissionStrategy;
|
|
public string groupDescriptionTemplate;
|
|
public string groupNamingTemplate;
|
|
public string groupDLTag;
|
|
public string groupGTag;
|
|
public string groupOwnerTag;
|
|
public string groupReadTag;
|
|
public string groupWriteTag;
|
|
public string groupTraverseTag;
|
|
public string groupWildcard;
|
|
public IDictionary<string, string> groupCustomTags;
|
|
public ICollection<string> ownerUserSids;
|
|
public ICollection<string> readerUserSids;
|
|
public ICollection<string> writerUserSids;
|
|
public bool forceStrictAdGroupNames;
|
|
public bool WhatIf;
|
|
|
|
public int ReadACLPermission = 0x200A9;
|
|
public int WriteACLPermission = 0x301BF;
|
|
public int OwnerACLPermission = 0x1F01FF;
|
|
|
|
|
|
public string ConfigID;
|
|
Dictionary<FileSystemRights, string> adGroupDic;
|
|
public DataArea newDataArea;
|
|
public SecurityGroups newSecurityGroups;
|
|
|
|
public List<IAM_SecurityGroupTemplate> templates;
|
|
|
|
public int createTraverseGroupLvl = 0;
|
|
|
|
public DataArea_FileSystem()
|
|
{
|
|
var logDirectory = Environment.ExpandEnvironmentVariables(constApplicationDataPath);
|
|
Helper.CreatePathWithWriteAccess(logDirectory);
|
|
var LogPath = Path.Combine(logDirectory, "Logs");
|
|
cLogManagerFile.CreateInstance(Path.Combine(LogPath, "LIAM.log"));
|
|
|
|
DefaultLogger.LogEntry(LogLevels.Info, "=================================================");
|
|
DefaultLogger.LogEntry(LogLevels.Info, $"LIAM engine v{Assembly.GetExecutingAssembly().GetName().Version} started");
|
|
|
|
templates = new List<IAM_SecurityGroupTemplate>();
|
|
}
|
|
|
|
private ResultToken checkRequiredVariables()
|
|
{
|
|
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
|
resultToken.resultErrorId = 0;
|
|
if (String.IsNullOrEmpty(ConfigID))
|
|
{
|
|
resultToken.resultErrorId = 30001;
|
|
resultToken.resultMessage = "Kein ConfigID gewählt ";
|
|
return resultToken;
|
|
}
|
|
if (string.IsNullOrEmpty(username) | String.IsNullOrEmpty(new NetworkCredential("", password).Password) | String.IsNullOrEmpty(domainName))
|
|
{
|
|
resultToken.resultErrorId = 30002;
|
|
resultToken.resultMessage = "Fehlende Anmeldeinformationen";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(groupPrefix))
|
|
{
|
|
resultToken.resultErrorId = 30004;
|
|
resultToken.resultMessage = "Kein Gruppen Präfix angegeben";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(newFolderPath))
|
|
{
|
|
resultToken.resultErrorId = 30005;
|
|
resultToken.resultMessage = "Kein Pfad für neues Verzeichnis angegeben";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(newFolderParent))
|
|
{
|
|
resultToken.resultErrorId = 30006;
|
|
resultToken.resultMessage = "Kein Pfad für neues Übergeordnetesverzeichnis angegeben";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(baseFolder))
|
|
{
|
|
resultToken.resultErrorId = 30007;
|
|
resultToken.resultMessage = "Kein Basisverzeichnis angegeben";
|
|
return resultToken;
|
|
}
|
|
return resultToken;
|
|
}
|
|
public ResultToken createDataArea()
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
|
|
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
|
resultToken.resultErrorId = 0;
|
|
if (checkRequiredVariables().resultErrorId == 0)
|
|
{
|
|
InitializeFolderContext();
|
|
try
|
|
{
|
|
// ImpersonationHelper.Impersonate(domainName, username, new NetworkCredential("", password).Password, delegate
|
|
// {
|
|
if (Connection != null)
|
|
Connection.Dispose();
|
|
|
|
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))
|
|
{
|
|
var folderCheckResult = checkFolder();
|
|
if (folderCheckResult.resultErrorId == 0)
|
|
{
|
|
try
|
|
{
|
|
createADGroups(resultToken);
|
|
try
|
|
{
|
|
resultToken = MergeResultTokens(resultToken, createFolder());
|
|
if (resultToken.resultErrorId == 0)
|
|
{
|
|
try
|
|
{
|
|
resultToken = MergeResultTokens(resultToken, SetTraversePermissions());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
resultToken.resultErrorId = 30200;
|
|
resultToken.resultMessage = "Fehler beim setzen der Traverserechte \n" + e.Message;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
resultToken.resultErrorId = 30200;
|
|
resultToken.resultMessage = "Fehler beim Erstellen der Verzeichnisse \n" + e.Message;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
resultToken.resultErrorId = 30100;
|
|
resultToken.resultMessage = "Fehler beim Erstellen der AD Gruppen \n" + e.Message;
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
resultToken = folderCheckResult;
|
|
}
|
|
/* },
|
|
logonType,
|
|
logonProvider);
|
|
*/
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
resultToken.resultErrorId = 30000;
|
|
resultToken.resultMessage = "Fehler beim Herstellen der Verbindung \n " + e.Message;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return checkRequiredVariables();
|
|
}
|
|
return resultToken;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private ResultToken MergeResultTokens(ResultToken target, ResultToken source)
|
|
{
|
|
if (target == null)
|
|
return source;
|
|
|
|
if (source == null)
|
|
return target;
|
|
|
|
if (source.resultErrorId != 0 || target.resultErrorId == 0)
|
|
target.resultErrorId = source.resultErrorId;
|
|
if (!string.IsNullOrWhiteSpace(source.resultMessage))
|
|
target.resultMessage = source.resultMessage;
|
|
if (!string.IsNullOrWhiteSpace(source.resultFunction))
|
|
target.resultFunction = source.resultFunction;
|
|
target.createdGroups.AddRange(source.createdGroups);
|
|
target.reusedGroups.AddRange(source.reusedGroups);
|
|
target.addedAclEntries.AddRange(source.addedAclEntries);
|
|
target.skippedAclEntries.AddRange(source.skippedAclEntries);
|
|
target.ensuredTraverseGroups.AddRange(source.ensuredTraverseGroups);
|
|
target.warnings.AddRange(source.warnings);
|
|
return target;
|
|
}
|
|
|
|
private ResultToken checkRequiredVariablesForEnsure()
|
|
{
|
|
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
|
resultToken.resultErrorId = 0;
|
|
if (String.IsNullOrEmpty(ConfigID))
|
|
{
|
|
resultToken.resultErrorId = 30001;
|
|
resultToken.resultMessage = "Kein ConfigID gewählt ";
|
|
return resultToken;
|
|
}
|
|
if (string.IsNullOrEmpty(username) | String.IsNullOrEmpty(new NetworkCredential("", password).Password) | String.IsNullOrEmpty(domainName))
|
|
{
|
|
resultToken.resultErrorId = 30002;
|
|
resultToken.resultMessage = "Fehlende Anmeldeinformationen";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(groupPrefix))
|
|
{
|
|
resultToken.resultErrorId = 30004;
|
|
resultToken.resultMessage = "Kein Gruppen Präfix angegeben";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(newFolderPath))
|
|
{
|
|
resultToken.resultErrorId = 30005;
|
|
resultToken.resultMessage = "Kein Pfad für Verzeichnis angegeben";
|
|
return resultToken;
|
|
}
|
|
if (String.IsNullOrEmpty(baseFolder))
|
|
{
|
|
resultToken.resultErrorId = 30007;
|
|
resultToken.resultMessage = "Kein Basisverzeichnis angegeben";
|
|
return resultToken;
|
|
}
|
|
return resultToken;
|
|
}
|
|
|
|
private void InitializeFolderContext()
|
|
{
|
|
newDataArea = new DataArea();
|
|
var folder = new IAM_Folder
|
|
{
|
|
configurationID = ConfigID,
|
|
technicalName = newFolderPath,
|
|
targetType = (int)IAM_TargetType.FileSystem,
|
|
Parent = newFolderParent,
|
|
ParentUID = string.IsNullOrWhiteSpace(newFolderParent) ? string.Empty : DataArea.GetUniqueDataAreaID(newFolderParent),
|
|
baseFolder = baseFolder
|
|
};
|
|
newDataArea.IAM_Folders.Add(folder);
|
|
|
|
newSecurityGroups = new SecurityGroups
|
|
{
|
|
username = username,
|
|
domainName = domainName,
|
|
password = password,
|
|
ForceStrictAdGroupNames = forceStrictAdGroupNames
|
|
};
|
|
}
|
|
|
|
public ResultToken ensureDataAreaPermissions(bool ensureTraverseGroups = false)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
var resultToken = checkRequiredVariablesForEnsure();
|
|
if (resultToken.resultErrorId != 0)
|
|
return resultToken;
|
|
|
|
if (Connection != null)
|
|
Connection.Dispose();
|
|
|
|
using (Connection = new cNetworkConnection(baseFolder, username, new NetworkCredential("", password).Password))
|
|
{
|
|
if (!Directory.Exists(newFolderPath))
|
|
{
|
|
resultToken.resultErrorId = 30203;
|
|
resultToken.resultMessage = "Verzeichnis existiert nicht";
|
|
return resultToken;
|
|
}
|
|
|
|
var parentDirectory = Directory.GetParent(newFolderPath);
|
|
if (string.IsNullOrWhiteSpace(newFolderParent))
|
|
newFolderParent = parentDirectory?.FullName;
|
|
|
|
InitializeFolderContext();
|
|
|
|
ensureADGroups(resultToken);
|
|
resultToken = ensureFolderPermissions(resultToken);
|
|
|
|
if (resultToken.resultErrorId != 0)
|
|
return resultToken;
|
|
|
|
if (ensureTraverseGroups)
|
|
{
|
|
if (WhatIf)
|
|
{
|
|
resultToken.warnings.Add("Traverse group preview is not supported in WhatIf mode for automatic DataArea ensure.");
|
|
resultToken.resultMessage = "Gruppen- und ACL-Vorschau erfolgreich erstellt";
|
|
return resultToken;
|
|
}
|
|
|
|
var traverseResult = SetTraversePermissions();
|
|
if (traverseResult != null)
|
|
{
|
|
resultToken.createdGroups.AddRange(traverseResult.createdGroups);
|
|
resultToken.reusedGroups.AddRange(traverseResult.reusedGroups);
|
|
resultToken.addedAclEntries.AddRange(traverseResult.addedAclEntries);
|
|
resultToken.skippedAclEntries.AddRange(traverseResult.skippedAclEntries);
|
|
resultToken.ensuredTraverseGroups.AddRange(traverseResult.ensuredTraverseGroups);
|
|
resultToken.warnings.AddRange(traverseResult.warnings);
|
|
if (traverseResult.resultErrorId != 0)
|
|
{
|
|
resultToken.resultErrorId = traverseResult.resultErrorId;
|
|
resultToken.resultMessage = traverseResult.resultMessage;
|
|
return resultToken;
|
|
}
|
|
}
|
|
}
|
|
|
|
resultToken.resultMessage = WhatIf
|
|
? "Gruppen- und ACL-Vorschau erfolgreich erstellt"
|
|
: "Gruppen und ACLs erfolgreich sichergestellt";
|
|
return resultToken;
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private ResultToken SetTraversePermissions()
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
|
resultToken.resultErrorId = 0;
|
|
|
|
// Loggen der DomainContext-Parameter
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"DomainName: {domainName}, Username: {username}");
|
|
|
|
if (string.IsNullOrEmpty(domainName) || string.IsNullOrEmpty(username) || password is null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "Eines der DomainContext-Parameter ist null oder leer.");
|
|
return resultToken;
|
|
}
|
|
|
|
var domainContext = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "PrincipalContext erfolgreich erstellt.");
|
|
|
|
// Überprüfen von newDataArea und IAM_Folders
|
|
if (newDataArea == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "newDataArea ist null.");
|
|
return resultToken;
|
|
}
|
|
|
|
if (newDataArea.IAM_Folders == null || newDataArea.IAM_Folders.Count == 0)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "IAM_Folders ist null oder leer.");
|
|
return resultToken;
|
|
}
|
|
|
|
DirectoryInfo newDir = new DirectoryInfo(newDataArea.IAM_Folders[0].technicalName);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Neues Verzeichnis: {newDir.FullName}");
|
|
|
|
DirectoryInfo parent = newDir.Parent;
|
|
if (parent == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "Parent-Verzeichnis ist null.");
|
|
return resultToken;
|
|
}
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Parent-Verzeichnis: {parent.FullName}");
|
|
|
|
var lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Ebene (lvl): {lvl}");
|
|
|
|
// Überprüfen der Templates
|
|
if (templates == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "templates ist null.");
|
|
return resultToken;
|
|
}
|
|
|
|
var traverseGroupTemplate = templates.FirstOrDefault(t => t.Type.Equals(SecurityGroupType.Traverse));
|
|
if (traverseGroupTemplate == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "traverseGroupTemplate ist null.");
|
|
return resultToken;
|
|
}
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseGroupTemplate gefunden");
|
|
|
|
// Überprüfen der traverseGroupTemplate-Eigenschaften
|
|
if (traverseGroupTemplate.WildcardTemplate == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "WildcardTemplate von traverseGroupTemplate ist null.");
|
|
return resultToken;
|
|
}
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseGroupTemplate.WildcardTemplate: {traverseGroupTemplate.WildcardTemplate}");
|
|
|
|
if (traverseGroupTemplate.NamingTemplate == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "NamingTemplate von traverseGroupTemplate ist null.");
|
|
return resultToken;
|
|
}
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseGroupTemplate.NamingTemplate: {traverseGroupTemplate.NamingTemplate}");
|
|
|
|
if (string.IsNullOrEmpty(baseFolder))
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "baseFolder ist null oder leer.");
|
|
return resultToken;
|
|
}
|
|
|
|
GroupPrincipal traverseGroup = null;
|
|
|
|
// Überprüfen, ob createTraverseGroupLvl initialisiert ist
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"createTraverseGroupLvl: {createTraverseGroupLvl}");
|
|
|
|
if (createTraverseGroupLvl == -1)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "createTraverseGroupLvl ist auf -1 gesetzt.");
|
|
return resultToken;
|
|
}
|
|
|
|
for (int i = lvl; i >= createTraverseGroupLvl; i--)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Verarbeite Ebene {i}.");
|
|
|
|
if (parent == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "Parent ist null innerhalb der Schleife.");
|
|
break;
|
|
}
|
|
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Hole ACL für Ordner: {parent.FullName}");
|
|
AuthorizationRuleCollection ACLs = null;
|
|
try
|
|
{
|
|
ACLs = parent.GetAccessControl(AccessControlSections.Access).GetAccessRules(true, true, typeof(NTAccount));
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "ACLs erfolgreich abgerufen.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Abrufen der ACLs: {ex.Message}");
|
|
continue; // Weiter zur nächsten Iteration
|
|
}
|
|
|
|
if (ACLs == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "ACLs ist null.");
|
|
continue;
|
|
}
|
|
|
|
GroupPrincipal parentTraverseGroup = null;
|
|
var parentTraverseAclExists = false;
|
|
string relativePathRaw = DataArea.GetRelativePath(parent.FullName, baseFolder).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
|
relativePathRaw = relativePathRaw.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"relativePath vor Normalisierung: {relativePathRaw}");
|
|
|
|
var relativePathSegments = relativePathRaw.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
|
|
var sanitizedSegments = relativePathSegments.Select(Helper.SanitizePathSegment).ToArray();
|
|
var relativePath = sanitizedSegments.Length > 0 ? string.Join("_", sanitizedSegments) : string.Empty;
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"relativePath nach Normalisierung: {relativePath}");
|
|
var folderName = sanitizedSegments.Length > 0
|
|
? sanitizedSegments[sanitizedSegments.Length - 1]
|
|
: Helper.SanitizePathSegment(Path.GetFileName(parent.FullName.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
|
|
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, relativePath, sanitizedSegments, folderName);
|
|
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, relativePath, sanitizedSegments, folderName);
|
|
|
|
string traverseRegex = null;
|
|
try
|
|
{
|
|
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, relativePath, sanitizedSegments, folderName);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler bei der Erstellung von traverseRegex: {ex.Message}");
|
|
continue;
|
|
}
|
|
|
|
foreach (FileSystemAccessRule acl in ACLs)
|
|
{
|
|
var searchString = acl.IdentityReference.Value;
|
|
var aclSplit = searchString.Split('\\');
|
|
if (aclSplit.Length == 2)
|
|
{
|
|
searchString = aclSplit[1];
|
|
}
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Suche GroupPrincipal für: {searchString}");
|
|
|
|
var princ = GroupPrincipal.FindByIdentity(domainContext, searchString);
|
|
if (princ != null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Gefundene Gruppe: {princ.Name}");
|
|
}
|
|
else
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Keine Gruppe gefunden für: {searchString}");
|
|
}
|
|
|
|
if (princ != null && Regex.IsMatch(princ.Name, traverseRegex, RegexOptions.IgnoreCase))
|
|
{
|
|
parentTraverseGroup = princ;
|
|
parentTraverseAclExists = true;
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"parentTraverseGroup gesetzt: {parentTraverseGroup.Name}");
|
|
}
|
|
if (parentTraverseGroup != null)
|
|
break;
|
|
}
|
|
|
|
if (parentTraverseGroup == null && !string.IsNullOrEmpty(traverseNameTemplate))
|
|
{
|
|
for (var loop = 0; loop < 20; loop++)
|
|
{
|
|
var candidateName = traverseNameTemplate.ReplaceLoopTag(loop);
|
|
parentTraverseGroup = GroupPrincipal.FindByIdentity(domainContext, candidateName);
|
|
if (parentTraverseGroup == null)
|
|
continue;
|
|
|
|
resultToken.reusedGroups.Add(candidateName);
|
|
resultToken.ensuredTraverseGroups.Add(candidateName);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe wiederverwendet: {candidateName}");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (parentTraverseGroup == null && !traverseGroupTemplate.NamingTemplate.Equals(string.Empty))
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "Erstelle neue TraverseGroup.");
|
|
if (newSecurityGroups == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "newSecurityGroups ist null.");
|
|
continue;
|
|
}
|
|
|
|
IAM_SecurityGroup newTraverseGroup = null;
|
|
var loop = 0;
|
|
do
|
|
{
|
|
try
|
|
{
|
|
newTraverseGroup = new IAM_SecurityGroup()
|
|
{
|
|
Name = traverseNameTemplate.ReplaceLoopTag(loop),
|
|
description = traverseDescriptionTemplate.ReplaceLoopTag(loop),
|
|
technicalName = "CN=" + traverseNameTemplate.ReplaceLoopTag(loop) + "," + groupOUPath,
|
|
Scope = traverseGroupTemplate.Scope
|
|
};
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Erstellte TraverseGroup: {newTraverseGroup.Name} (Loop: {loop})");
|
|
loop++;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen von newTraverseGroup: {ex.Message}");
|
|
break;
|
|
}
|
|
} while (newSecurityGroups.GroupAllreadyExisting(newTraverseGroup.Name.ToUpper()) && loop < 20);
|
|
|
|
if (newTraverseGroup != null)
|
|
{
|
|
if (string.IsNullOrEmpty(groupOUPath))
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "groupOUPath ist null oder leer.");
|
|
continue;
|
|
}
|
|
|
|
if (parent.Parent != null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "Parent.Parent ist nicht null. Erstelle AD-Gruppe.");
|
|
if (WhatIf)
|
|
{
|
|
resultToken.createdGroups.Add(newTraverseGroup.Name);
|
|
resultToken.ensuredTraverseGroups.Add(newTraverseGroup.Name);
|
|
resultToken.warnings.Add($"Traverse-Gruppe würde angelegt werden: {newTraverseGroup.Name}");
|
|
resultToken.addedAclEntries.Add(newTraverseGroup.Name);
|
|
parentTraverseAclExists = true;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
newSecurityGroups.CreateADGroup(groupOUPath, newTraverseGroup, null);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"AD-Gruppe erstellt: {newTraverseGroup.Name}");
|
|
resultToken.createdGroups.Add(newTraverseGroup.Name);
|
|
resultToken.ensuredTraverseGroups.Add(newTraverseGroup.Name);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen der AD-Gruppe: {ex.Message}");
|
|
continue;
|
|
}
|
|
|
|
parentTraverseGroup = GroupPrincipal.FindByIdentity(domainContext, newTraverseGroup.Name);
|
|
if (parentTraverseGroup == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"parentTraverseGroup konnte nach Erstellung der Gruppe nicht gefunden werden: {newTraverseGroup.Name}");
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
var accesscontrol = parent.GetAccessControl();
|
|
accesscontrol.AddAccessRule(new FileSystemAccessRule(parentTraverseGroup.Sid,
|
|
FileSystemRights.Read, InheritanceFlags.None, PropagationFlags.None,
|
|
AccessControlType.Allow));
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Setze Traverse-ACL auf: {parent.FullName} für {parentTraverseGroup.DistinguishedName}");
|
|
parent.SetAccessControl(accesscontrol);
|
|
resultToken.addedAclEntries.Add(parentTraverseGroup.Name);
|
|
parentTraverseAclExists = true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Setzen der ACL: {ex.Message}");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "Parent.Parent ist null. Traverse-ACL kann nicht gesetzt werden.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parentTraverseGroup != null && !parentTraverseAclExists)
|
|
{
|
|
try
|
|
{
|
|
var accessControl = parent.GetAccessControl();
|
|
var rules = accessControl.GetAccessRules(true, true, typeof(SecurityIdentifier)).Cast<FileSystemAccessRule>();
|
|
var hasAcl = rules.Any(rule =>
|
|
rule.AccessControlType == AccessControlType.Allow
|
|
&& rule.IdentityReference.Value == parentTraverseGroup.Sid.Value
|
|
&& (rule.FileSystemRights & FileSystemRights.Read) == FileSystemRights.Read);
|
|
|
|
if (hasAcl)
|
|
{
|
|
resultToken.skippedAclEntries.Add(parentTraverseGroup.Name);
|
|
}
|
|
else
|
|
{
|
|
if (!WhatIf)
|
|
{
|
|
accessControl.AddAccessRule(new FileSystemAccessRule(parentTraverseGroup.Sid,
|
|
FileSystemRights.Read, InheritanceFlags.None, PropagationFlags.None,
|
|
AccessControlType.Allow));
|
|
parent.SetAccessControl(accessControl);
|
|
}
|
|
resultToken.addedAclEntries.Add(parentTraverseGroup.Name);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Sicherstellen der Traverse-ACL: {ex.Message}");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (parentTraverseGroup != null)
|
|
{
|
|
if (i == lvl)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
|
|
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
|
|
{
|
|
if (currentSecGroup == null)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, "currentSecGroup ist null.");
|
|
continue;
|
|
}
|
|
if (currentSecGroup.Scope != GroupScope.Global)
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
if (traverseGroup != null && parentTraverseGroup != null)
|
|
{
|
|
try
|
|
{
|
|
if (!parentTraverseGroup.Members.Contains(traverseGroup))
|
|
{
|
|
if (WhatIf)
|
|
{
|
|
resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde verschachtelte Gruppe '{traverseGroup.Name}' erhalten.");
|
|
}
|
|
else
|
|
{
|
|
if (!TryEnsureNestedTraverseGroupMembershipWithRetry(parentTraverseGroup, traverseGroup))
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Hinzufügen der Traverse-Gruppe: {ex.Message}");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
try
|
|
{
|
|
if (!WhatIf)
|
|
{
|
|
parentTraverseGroup.Save();
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"parentTraverseGroup gespeichert: {parentTraverseGroup.Name}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Speichern der parentTraverseGroup: {ex.Message}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "parentTraverseGroup ist null.");
|
|
}
|
|
|
|
if (parentTraverseGroup != null && !resultToken.ensuredTraverseGroups.Contains(parentTraverseGroup.Name))
|
|
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
|
|
|
|
// Aktualisiere parent und lvl für die nächste Iteration
|
|
parent = parent.Parent;
|
|
if (parent != null)
|
|
{
|
|
lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Aktualisierung: {lvl}");
|
|
}
|
|
else
|
|
{
|
|
DefaultLogger.LogEntry(LogLevels.Debug, "Parent nach Aktualisierung ist null.");
|
|
}
|
|
}
|
|
|
|
return resultToken;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private bool TryEnsureGlobalGroupMembershipWithRetry(PrincipalContext domainContext, GroupPrincipal parentTraverseGroup, IAM_SecurityGroup currentSecGroup)
|
|
{
|
|
if (domainContext == null || parentTraverseGroup == null || currentSecGroup == null || string.IsNullOrWhiteSpace(currentSecGroup.UID))
|
|
return false;
|
|
|
|
return RetryTraverseMembershipAction(
|
|
currentSecGroup.Name,
|
|
currentSecGroup.CreatedNewEntry,
|
|
() =>
|
|
{
|
|
using (var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, currentSecGroup.UID))
|
|
{
|
|
if (groupPrincipal == null)
|
|
return false;
|
|
|
|
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<bool> tryAction)
|
|
{
|
|
if (tryAction == null)
|
|
return false;
|
|
|
|
var retryDelaysMs = allowRetry
|
|
? new[] { 0, 250, 500, 1000, 2000, 5000 }
|
|
: new[] { 0 };
|
|
var delayIndex = 0;
|
|
var maxWait = allowRetry ? TimeSpan.FromMinutes(3) : TimeSpan.Zero;
|
|
var waitStopwatch = Stopwatch.StartNew();
|
|
Exception lastException = null;
|
|
|
|
while (true)
|
|
{
|
|
var delayMs = retryDelaysMs[Math.Min(delayIndex, retryDelaysMs.Length - 1)];
|
|
if (delayMs > 0)
|
|
System.Threading.Thread.Sleep(delayMs);
|
|
if (delayIndex < retryDelaysMs.Length - 1)
|
|
delayIndex++;
|
|
|
|
try
|
|
{
|
|
if (tryAction())
|
|
{
|
|
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;
|
|
}
|
|
|
|
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());
|
|
|
|
try
|
|
{
|
|
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
|
resultToken.resultErrorId = 0;
|
|
if (Directory.Exists(newDataArea.IAM_Folders[0].technicalName))
|
|
{
|
|
resultToken.resultMessage = "New folder " + newDataArea.IAM_Folders[0].technicalName + " already exists";
|
|
resultToken.resultErrorId = 30201;
|
|
|
|
}
|
|
return resultToken;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private static bool HasMatchingAccessRule(DirectoryInfo directory, SecurityIdentifier sid, FileSystemRights rights)
|
|
{
|
|
var rules = directory.GetAccessControl(AccessControlSections.Access)
|
|
.GetAccessRules(true, true, typeof(SecurityIdentifier))
|
|
.Cast<FileSystemAccessRule>();
|
|
|
|
foreach (var rule in rules)
|
|
{
|
|
if (rule.AccessControlType != AccessControlType.Allow)
|
|
continue;
|
|
|
|
if (!(rule.IdentityReference is SecurityIdentifier ruleSid))
|
|
continue;
|
|
|
|
if (!string.Equals(ruleSid.Value, sid.Value, StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
|
|
if ((rule.FileSystemRights & rights) == rights)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private ResultToken ensureFolderPermissions(ResultToken resultToken)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
var directory = new DirectoryInfo(newDataArea.IAM_Folders[0].technicalName);
|
|
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
|
|
{
|
|
if (WhatIf && string.IsNullOrWhiteSpace(currentSecGroup?.UID) && currentSecGroup?.CreatedNewEntry == true)
|
|
{
|
|
resultToken.addedAclEntries.Add(currentSecGroup.Name);
|
|
continue;
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(currentSecGroup?.UID))
|
|
{
|
|
resultToken.warnings.Add($"Keine SID für Gruppe '{currentSecGroup?.Name}' verfügbar.");
|
|
continue;
|
|
}
|
|
|
|
if (!(groupPermissionStrategy == PermissionGroupStrategy.AGDLP && currentSecGroup.Scope == GroupScope.Local
|
|
|| groupPermissionStrategy == PermissionGroupStrategy.AGP && currentSecGroup.Scope == GroupScope.Global))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var sid = new SecurityIdentifier(currentSecGroup.UID);
|
|
if (HasMatchingAccessRule(directory, sid, currentSecGroup.rights))
|
|
{
|
|
resultToken.skippedAclEntries.Add(currentSecGroup.Name);
|
|
continue;
|
|
}
|
|
|
|
if (!WhatIf)
|
|
DataArea.AddDirectorySecurity(newDataArea.IAM_Folders[0].baseFolder, newDataArea.IAM_Folders[0].technicalName, sid, currentSecGroup.rights, AccessControlType.Allow);
|
|
|
|
resultToken.addedAclEntries.Add(currentSecGroup.Name);
|
|
}
|
|
|
|
return resultToken;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private void ensureADGroups(ResultToken resultToken)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
newSecurityGroups.IAM_SecurityGroups.Clear();
|
|
newSecurityGroups.GenerateNewSecurityGroups(baseFolder,
|
|
newDataArea.IAM_Folders[0].technicalName,
|
|
groupPrefix,
|
|
groupOUPath,
|
|
groupPermissionStrategy,
|
|
groupTraverseTag,
|
|
groupReadTag,
|
|
groupWriteTag,
|
|
groupOwnerTag,
|
|
groupDLTag,
|
|
groupGTag,
|
|
groupCustomTags,
|
|
templates,
|
|
ReadACLPermission,
|
|
WriteACLPermission,
|
|
OwnerACLPermission,
|
|
0);
|
|
|
|
List<UserPrincipal> owners = getUserPrincipalBySid(ownerUserSids);
|
|
List<UserPrincipal> writers = getUserPrincipalBySid(writerUserSids);
|
|
List<UserPrincipal> readers = getUserPrincipalBySid(readerUserSids);
|
|
|
|
for (int i = 0; newSecurityGroups.IAM_SecurityGroups.Count > i; i++)
|
|
{
|
|
List<UserPrincipal> users;
|
|
if (newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper().EndsWith(groupOwnerTag.ToUpper()))
|
|
users = owners;
|
|
else if (newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper().EndsWith(groupWriteTag.ToUpper()))
|
|
users = writers;
|
|
else if (newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper().EndsWith(groupReadTag.ToUpper()))
|
|
users = readers;
|
|
else
|
|
users = null;
|
|
|
|
if (WhatIf)
|
|
{
|
|
var existingGroup = newSecurityGroups.PreviewADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], newDataArea.IAM_Folders[0].technicalName);
|
|
newSecurityGroups.IAM_SecurityGroups[i].CreatedNewEntry = existingGroup == null;
|
|
}
|
|
else
|
|
{
|
|
newSecurityGroups.EnsureADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], users, newDataArea.IAM_Folders[0].technicalName);
|
|
}
|
|
|
|
if (newSecurityGroups.IAM_SecurityGroups[i].CreatedNewEntry)
|
|
resultToken.createdGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
|
else
|
|
resultToken.reusedGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private ResultToken createFolder()
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
try
|
|
{
|
|
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
|
|
resultToken.resultErrorId = 0;
|
|
|
|
|
|
if (!Directory.Exists(newFolderParent))
|
|
{
|
|
resultToken.resultMessage = "Übergeordnetesverzeichnis " + newDataArea.IAM_Folders[0].Parent + " des neuen Ordners " + newDataArea.IAM_Folders[0].technicalName + " existiert nicht";
|
|
resultToken.resultErrorId = 30202;
|
|
return resultToken;
|
|
}
|
|
else
|
|
{
|
|
if (WhatIf)
|
|
{
|
|
newDataArea.IAM_Folders[0].UID = DataArea.GetUniqueDataAreaID(newDataArea.IAM_Folders[0].technicalName);
|
|
resultToken.warnings.Add($"Verzeichnis würde erstellt werden: {newDataArea.IAM_Folders[0].technicalName}");
|
|
|
|
for (int i = 0; newSecurityGroups.IAM_SecurityGroups.Count > i; i++)
|
|
{
|
|
var currentSecGroup = newSecurityGroups.IAM_SecurityGroups[i];
|
|
if (groupPermissionStrategy == PermissionGroupStrategy.AGDLP && currentSecGroup.Scope == GroupScope.Local
|
|
|| groupPermissionStrategy == PermissionGroupStrategy.AGP && currentSecGroup.Scope == GroupScope.Global)
|
|
{
|
|
resultToken.addedAclEntries.Add(currentSecGroup.Name);
|
|
}
|
|
}
|
|
|
|
resultToken.resultErrorId = 0;
|
|
resultToken.resultMessage = "Verzeichnis-, Gruppen- und ACL-Vorschau erfolgreich erstellt";
|
|
return resultToken;
|
|
}
|
|
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Creating folder: {newDataArea.IAM_Folders[0].technicalName}");
|
|
DirectoryInfo newDir = Directory.CreateDirectory(newDataArea.IAM_Folders[0].technicalName);
|
|
newDataArea.IAM_Folders[0].UID = DataArea.GetUniqueDataAreaID(newDir.FullName);
|
|
for (int i = 0; newSecurityGroups.IAM_SecurityGroups.Count > i; i++)
|
|
{
|
|
var currentSecGroup = newSecurityGroups.IAM_SecurityGroups[i];
|
|
var sid = new SecurityIdentifier(currentSecGroup.UID);
|
|
if (groupPermissionStrategy == PermissionGroupStrategy.AGDLP && currentSecGroup.Scope == GroupScope.Local
|
|
|| groupPermissionStrategy == PermissionGroupStrategy.AGP && currentSecGroup.Scope == GroupScope.Global)
|
|
DataArea.AddDirectorySecurity(newDataArea.IAM_Folders[0].baseFolder, newDataArea.IAM_Folders[0].technicalName, sid, currentSecGroup.rights, AccessControlType.Allow);
|
|
}
|
|
AddDirectorySecurityACLDenyFolderDeletion(newDataArea.IAM_Folders[0].technicalName);
|
|
|
|
resultToken.resultErrorId = 0;
|
|
resultToken.resultMessage = "Verzeichnis erfolgreich erstellt";
|
|
}
|
|
return resultToken;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private void AddDirectorySecurityACLDenyFolderDeletion(string technicalName)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
// Create a new DirectoryInfo object.
|
|
DirectoryInfo dInfo = new DirectoryInfo(technicalName);
|
|
//DirectoryInfo dInfoBaseFolder = new DirectoryInfo(baseFolderTechnicalName);
|
|
|
|
// Get a DirectorySecurity object that represents the
|
|
// current security settings.
|
|
DirectorySecurity dSecurity = dInfo.GetAccessControl();
|
|
|
|
// Add the FileSystemAccessRule to the security settings.
|
|
var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
|
|
|
|
dSecurity.AddAccessRule(new FileSystemAccessRule(everyone,
|
|
FileSystemRights.Delete, InheritanceFlags.None, PropagationFlags.None,
|
|
AccessControlType.Deny));
|
|
// Set the new access settings.
|
|
dInfo.SetAccessControl(dSecurity);
|
|
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
|
|
private void createADGroups(ResultToken resultToken)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
Dictionary<FileSystemRights, string> currentGroupDIC = new Dictionary<FileSystemRights, string>();
|
|
adGroupDic = new Dictionary<FileSystemRights, string>();
|
|
|
|
var existingADGroupCount = 0;
|
|
do
|
|
{
|
|
newSecurityGroups.IAM_SecurityGroups.Clear();
|
|
newSecurityGroups.GenerateNewSecurityGroups(baseFolder,
|
|
newDataArea.IAM_Folders[0].technicalName,
|
|
groupPrefix,
|
|
groupOUPath,
|
|
groupPermissionStrategy,
|
|
groupTraverseTag,
|
|
groupReadTag,
|
|
groupWriteTag,
|
|
groupOwnerTag,
|
|
groupDLTag,
|
|
groupGTag,
|
|
groupCustomTags,
|
|
templates,
|
|
ReadACLPermission,
|
|
WriteACLPermission,
|
|
OwnerACLPermission,
|
|
existingADGroupCount);
|
|
/*
|
|
if (existingADGroupCount > 0 && !templates.All(t => t.Type == SecurityGroupType.Traverse || Regex.IsMatch(t.NamingTemplate, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})")))
|
|
{
|
|
var nt = templates.First(t => t.Type == SecurityGroupType.Traverse || Regex.IsMatch(t.NamingTemplate, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})")).NamingTemplate;
|
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Naming template: {nt}");
|
|
throw new Exception("AD groups already existing and loop tag not found");
|
|
}
|
|
*/
|
|
existingADGroupCount++;
|
|
|
|
} while (newSecurityGroups.GroupsAllreadyExisting(groupOUPath) && existingADGroupCount < 1000);
|
|
if(newSecurityGroups.GroupsAllreadyExisting(groupOUPath) && existingADGroupCount>= 1000)
|
|
{
|
|
throw new Exception("Unique AD Group could not be generated after 1000 iterations");
|
|
}
|
|
List<UserPrincipal> users;
|
|
List<UserPrincipal> owners = getUserPrincipalBySid(ownerUserSids);
|
|
List<UserPrincipal> writers = getUserPrincipalBySid(writerUserSids);
|
|
List<UserPrincipal> readers = getUserPrincipalBySid(readerUserSids);
|
|
for (int i = 0; newSecurityGroups.IAM_SecurityGroups.Count > i; i++)
|
|
{
|
|
if (newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper().EndsWith(groupOwnerTag.ToUpper()))
|
|
users = owners;
|
|
else if (newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper().EndsWith(groupWriteTag.ToUpper()))
|
|
users = writers;
|
|
else if (newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper().EndsWith(groupReadTag.ToUpper()))
|
|
users = readers;
|
|
else
|
|
users = null;
|
|
|
|
if (WhatIf)
|
|
{
|
|
var existingGroup = newSecurityGroups.PreviewADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], newDataArea.IAM_Folders[0].technicalName);
|
|
newSecurityGroups.IAM_SecurityGroups[i].CreatedNewEntry = existingGroup == null;
|
|
}
|
|
else
|
|
{
|
|
newSecurityGroups.CreateADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], users);
|
|
}
|
|
|
|
if (resultToken != null)
|
|
{
|
|
if (newSecurityGroups.IAM_SecurityGroups[i].CreatedNewEntry)
|
|
resultToken.createdGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
|
else
|
|
resultToken.reusedGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private List<UserPrincipal> getUserPrincipalBySid(ICollection<string> UserSids)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
List<UserPrincipal> result = new List<UserPrincipal>();
|
|
if (UserSids != null)
|
|
{
|
|
foreach (var sid in UserSids)
|
|
{
|
|
if (!string.IsNullOrEmpty(sid))
|
|
{
|
|
UserPrincipal user = getUserPrincipalBySid(sid);
|
|
if (user != null && !result.Any(item => item.DistinguishedName == user.DistinguishedName))
|
|
{
|
|
result.Add(user);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
|
|
private UserPrincipal getUserPrincipalBySid(string sid)
|
|
{
|
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
|
|
|
try
|
|
{
|
|
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password);
|
|
UserPrincipal user;
|
|
user = UserPrincipal.FindByIdentity(ctx, IdentityType.Sid, (sid));
|
|
return user;
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
cLogManager.DefaultLogger.LogException(E);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
|
}
|
|
}
|
|
private string getTraverseRegex()
|
|
{
|
|
return groupWildcard
|
|
.Replace("{{PREFIX}}", groupPrefix)
|
|
.Replace("{{SCOPETAG}}", groupDLTag)
|
|
.Replace("{{GROUPTYPEPOSTFIX}}", groupTraverseTag);
|
|
}
|
|
}
|
|
}
|