Allow regex reuse for NTFS ensure groups
This commit is contained in:
@@ -563,7 +563,8 @@ namespace C4IT.LIAM
|
||||
groupReadTag = GetRequiredCustomTag("Filesystem_GroupReadTag"),
|
||||
groupTraverseTag = GetRequiredCustomTag("Filesystem_GroupTraverseTag"),
|
||||
groupDLTag = requiresDomainLocalTag ? GetRequiredCustomTag("Filesystem_GroupDomainLocalTag") : string.Empty,
|
||||
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag")
|
||||
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
|
||||
allowExistingGroupWildcardMatch = IsAdditionalConfigurationEnabled("EnsureNtfsPermissionGroupsAllowRegexMatch")
|
||||
};
|
||||
|
||||
foreach (var template in BuildSecurityGroupTemplates())
|
||||
@@ -572,6 +573,19 @@ namespace C4IT.LIAM
|
||||
return engine;
|
||||
}
|
||||
|
||||
private bool IsAdditionalConfigurationEnabled(string key)
|
||||
{
|
||||
if (AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
|
||||
return false;
|
||||
|
||||
if (!AdditionalConfiguration.TryGetValue(key, out var rawValue) || string.IsNullOrWhiteSpace(rawValue))
|
||||
return false;
|
||||
|
||||
return rawValue.Equals("true", StringComparison.OrdinalIgnoreCase)
|
||||
|| rawValue.Equals("1", StringComparison.OrdinalIgnoreCase)
|
||||
|| rawValue.Equals("yes", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private IEnumerable<IAM_SecurityGroupTemplate> BuildSecurityGroupTemplates()
|
||||
{
|
||||
var templates = new List<IAM_SecurityGroupTemplate>();
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace C4IT_IAM_SET
|
||||
public ICollection<string> ownerUserSids;
|
||||
public ICollection<string> readerUserSids;
|
||||
public ICollection<string> writerUserSids;
|
||||
public bool allowExistingGroupWildcardMatch;
|
||||
|
||||
public int ReadACLPermission = 0x200A9;
|
||||
public int WriteACLPermission = 0x301BF;
|
||||
@@ -144,6 +145,7 @@ namespace C4IT_IAM_SET
|
||||
newSecurityGroups.username = username;
|
||||
newSecurityGroups.domainName = domainName;
|
||||
newSecurityGroups.password = password;
|
||||
newSecurityGroups.AllowExistingGroupWildcardMatch = allowExistingGroupWildcardMatch;
|
||||
try
|
||||
{
|
||||
// ImpersonationHelper.Impersonate(domainName, username, new NetworkCredential("", password).Password, delegate
|
||||
@@ -274,7 +276,8 @@ namespace C4IT_IAM_SET
|
||||
{
|
||||
username = username,
|
||||
domainName = domainName,
|
||||
password = password
|
||||
password = password,
|
||||
AllowExistingGroupWildcardMatch = allowExistingGroupWildcardMatch
|
||||
};
|
||||
}
|
||||
|
||||
@@ -909,9 +912,8 @@ namespace C4IT_IAM_SET
|
||||
else
|
||||
users = null;
|
||||
|
||||
var groupAlreadyExists = newSecurityGroups.GroupAllreadyExisting(newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper());
|
||||
newSecurityGroups.EnsureADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], users);
|
||||
if (groupAlreadyExists)
|
||||
if (newSecurityGroups.IAM_SecurityGroups[i].ReusedExistingEntry)
|
||||
resultToken.reusedGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
||||
else
|
||||
resultToken.createdGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace C4IT_IAM_Engine
|
||||
public string domainName;
|
||||
public string username;
|
||||
public SecureString password;
|
||||
public bool AllowExistingGroupWildcardMatch;
|
||||
|
||||
public List<IAM_SecurityGroup> IAM_SecurityGroups;
|
||||
public string rootUID;
|
||||
@@ -208,6 +209,7 @@ namespace C4IT_IAM_Engine
|
||||
{
|
||||
Name = ownerGlobal.NamingTemplate,
|
||||
description = ownerGlobal.DescriptionTemplate,
|
||||
WildcardPattern = ownerGlobal.WildcardTemplate,
|
||||
|
||||
technicalName = "CN=" + ownerGlobal.NamingTemplate + "," + ouPath,
|
||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||
@@ -221,6 +223,7 @@ namespace C4IT_IAM_Engine
|
||||
{
|
||||
Name = writeGlobal.NamingTemplate,
|
||||
description = writeGlobal.DescriptionTemplate,
|
||||
WildcardPattern = writeGlobal.WildcardTemplate,
|
||||
|
||||
technicalName = "CN=" + writeGlobal.NamingTemplate + "," + ouPath,
|
||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||
@@ -234,6 +237,7 @@ namespace C4IT_IAM_Engine
|
||||
{
|
||||
Name = readGlobal.NamingTemplate,
|
||||
description = readGlobal.DescriptionTemplate,
|
||||
WildcardPattern = readGlobal.WildcardTemplate,
|
||||
|
||||
technicalName = "CN=" + readGlobal.NamingTemplate + "," + ouPath,
|
||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||
@@ -251,6 +255,7 @@ namespace C4IT_IAM_Engine
|
||||
{
|
||||
Name = ownerDL.NamingTemplate,
|
||||
description = ownerDL.DescriptionTemplate,
|
||||
WildcardPattern = ownerDL.WildcardTemplate,
|
||||
|
||||
technicalName = "CN=" + ownerDL.NamingTemplate + "," + ouPath,
|
||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||
@@ -265,6 +270,7 @@ namespace C4IT_IAM_Engine
|
||||
{
|
||||
Name = writeDL.NamingTemplate,
|
||||
description = writeDL.DescriptionTemplate,
|
||||
WildcardPattern = writeDL.WildcardTemplate,
|
||||
|
||||
technicalName = "CN=" + writeDL.NamingTemplate + "," + ouPath,
|
||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||
@@ -279,6 +285,7 @@ namespace C4IT_IAM_Engine
|
||||
{
|
||||
Name = readDL.NamingTemplate,
|
||||
description = readDL.DescriptionTemplate,
|
||||
WildcardPattern = readDL.WildcardTemplate,
|
||||
|
||||
technicalName = "CN=" + readDL.NamingTemplate + "," + ouPath,
|
||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||
@@ -293,6 +300,7 @@ namespace C4IT_IAM_Engine
|
||||
secGroup.description = secGroup.description.ReplaceLoopTag(0);
|
||||
secGroup.Name = secGroup.Name.ReplaceLoopTag(loop);
|
||||
secGroup.technicalName = secGroup.technicalName.ReplaceLoopTag(loop);
|
||||
secGroup.WildcardPattern = secGroup.WildcardPattern.ReplaceLoopTag(loop);
|
||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Security group generated: {secGroup.technicalName}");
|
||||
}
|
||||
}
|
||||
@@ -398,6 +406,92 @@ namespace C4IT_IAM_Engine
|
||||
return groupEntry;
|
||||
}
|
||||
|
||||
private DirectoryEntry FindGroupEntryByWildcard(string ouPath, string wildcardPattern)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(wildcardPattern))
|
||||
return null;
|
||||
|
||||
Regex wildcardRegex;
|
||||
try
|
||||
{
|
||||
wildcardRegex = new Regex(wildcardPattern, RegexOptions.IgnoreCase);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
cLogManager.DefaultLogger.LogException(E);
|
||||
return null;
|
||||
}
|
||||
|
||||
var basePath = "LDAP://" + domainName;
|
||||
if (!string.IsNullOrWhiteSpace(ouPath))
|
||||
basePath += "/" + ouPath;
|
||||
|
||||
DirectoryEntry entry = new DirectoryEntry
|
||||
{
|
||||
Path = basePath,
|
||||
Username = username,
|
||||
Password = new NetworkCredential("", password).Password,
|
||||
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
|
||||
};
|
||||
|
||||
DirectorySearcher search = new DirectorySearcher(entry)
|
||||
{
|
||||
Filter = "(objectClass=group)"
|
||||
};
|
||||
search.PageSize = 100000;
|
||||
search.PropertiesToLoad.Add("sAMAccountName");
|
||||
search.PropertiesToLoad.Add("distinguishedName");
|
||||
|
||||
string matchedName = null;
|
||||
string matchedDistinguishedName = null;
|
||||
var matchCount = 0;
|
||||
|
||||
foreach (SearchResult result in search.FindAll())
|
||||
{
|
||||
if (!result.Properties.Contains("sAMAccountName") || result.Properties["sAMAccountName"].Count == 0)
|
||||
continue;
|
||||
|
||||
var samAccountName = result.Properties["sAMAccountName"][0]?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(samAccountName) || !wildcardRegex.IsMatch(samAccountName))
|
||||
continue;
|
||||
|
||||
matchCount++;
|
||||
if (matchCount > 1)
|
||||
{
|
||||
DefaultLogger.LogEntry(LogLevels.Warning, $"Multiple AD groups matched wildcard '{wildcardPattern}' in '{basePath}'. Regex-based reuse is skipped.");
|
||||
search.Dispose();
|
||||
entry.Dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
matchedName = samAccountName;
|
||||
matchedDistinguishedName = result.Properties.Contains("distinguishedName") && result.Properties["distinguishedName"].Count > 0
|
||||
? result.Properties["distinguishedName"][0]?.ToString()
|
||||
: null;
|
||||
}
|
||||
|
||||
search.Dispose();
|
||||
entry.Dispose();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(matchedDistinguishedName))
|
||||
return null;
|
||||
|
||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Reusing existing AD group '{matchedName}' via wildcard '{wildcardPattern}'.");
|
||||
return new DirectoryEntry("LDAP://" + domainName + "/" + matchedDistinguishedName, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
||||
}
|
||||
|
||||
private void ApplyExistingGroup(IAM_SecurityGroup secGroup, DirectoryEntry existingGroup)
|
||||
{
|
||||
secGroup.ReusedExistingEntry = true;
|
||||
secGroup.UID = getSID(existingGroup);
|
||||
|
||||
if (existingGroup.Properties.Contains("sAMAccountName") && existingGroup.Properties["sAMAccountName"].Count > 0)
|
||||
secGroup.Name = existingGroup.Properties["sAMAccountName"][0]?.ToString();
|
||||
|
||||
if (existingGroup.Properties.Contains("distinguishedName") && existingGroup.Properties["distinguishedName"].Count > 0)
|
||||
secGroup.technicalName = existingGroup.Properties["distinguishedName"][0]?.ToString();
|
||||
}
|
||||
|
||||
private static bool HasMember(PropertyValueCollection members, string distinguishedName)
|
||||
{
|
||||
foreach (var member in members)
|
||||
@@ -450,13 +544,16 @@ namespace C4IT_IAM_Engine
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
secGroup.ReusedExistingEntry = false;
|
||||
var existingGroup = FindGroupEntry(secGroup.Name);
|
||||
if (existingGroup == null && AllowExistingGroupWildcardMatch)
|
||||
existingGroup = FindGroupEntryByWildcard(ouPath, secGroup.WildcardPattern);
|
||||
|
||||
if (existingGroup == null)
|
||||
return CreateADGroup(ouPath, secGroup, users);
|
||||
|
||||
AddMissingMembers(existingGroup, secGroup, users);
|
||||
var objectid = getSID(existingGroup);
|
||||
secGroup.UID = objectid;
|
||||
ApplyExistingGroup(secGroup, existingGroup);
|
||||
return existingGroup;
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -475,6 +572,7 @@ namespace C4IT_IAM_Engine
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
secGroup.ReusedExistingEntry = false;
|
||||
if (!GroupAllreadyExisting(secGroup.Name.ToUpper()))
|
||||
{
|
||||
|
||||
@@ -518,9 +616,8 @@ namespace C4IT_IAM_Engine
|
||||
DirectoryEntry e = FindGroupEntry(secGroup.Name);
|
||||
if (e == null)
|
||||
return null;
|
||||
var objectid = getSID(e);
|
||||
secGroup.UID = objectid;
|
||||
AddMissingMembers(e, secGroup, users);
|
||||
ApplyExistingGroup(secGroup, e);
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
@@ -588,6 +685,8 @@ namespace C4IT_IAM_Engine
|
||||
public string UID;
|
||||
public string Parent = "";
|
||||
public string description;
|
||||
public string WildcardPattern;
|
||||
public bool ReusedExistingEntry;
|
||||
public List<IAM_SecurityGroup> memberGroups;
|
||||
public string Name;
|
||||
public string technicalName;
|
||||
|
||||
Reference in New Issue
Block a user