Compare commits
2 Commits
d95f2385ac
...
32021dcfd8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32021dcfd8 | ||
|
|
d28cfe008c |
@@ -32,6 +32,7 @@ namespace C4IT.LIAM
|
|||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
NtfsShare = 101,
|
NtfsShare = 101,
|
||||||
NtfsFolder = 102,
|
NtfsFolder = 102,
|
||||||
|
DfsNamespaceRoot = 103,
|
||||||
MsTeamsTeam = 401,
|
MsTeamsTeam = 401,
|
||||||
MsTeamsChannel = 402,
|
MsTeamsChannel = 402,
|
||||||
MsTeamsFolder = 403,
|
MsTeamsFolder = 403,
|
||||||
@@ -396,4 +397,4 @@ namespace C4IT.LIAM
|
|||||||
|
|
||||||
public bool SupportsPermissions { get; set; } = false;
|
public bool SupportsPermissions { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
using C4IT.Logging;
|
using C4IT.Logging;
|
||||||
using C4IT.Matrix42.ServerInfo;
|
using C4IT.Matrix42.ServerInfo;
|
||||||
|
using C4IT_IAM;
|
||||||
using C4IT_IAM_Engine;
|
using C4IT_IAM_Engine;
|
||||||
using C4IT_IAM_SET;
|
using C4IT_IAM_SET;
|
||||||
using LiamNtfs;
|
using LiamNtfs;
|
||||||
@@ -30,9 +31,30 @@ namespace C4IT.LIAM
|
|||||||
|
|
||||||
public class cLiamProviderNtfs : cLiamProviderBase
|
public class cLiamProviderNtfs : cLiamProviderBase
|
||||||
{
|
{
|
||||||
|
private enum eNtfsPathKind
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
ServerRoot = 1,
|
||||||
|
ClassicShare = 2,
|
||||||
|
DfsNamespaceRoot = 3,
|
||||||
|
DfsLink = 4,
|
||||||
|
Folder = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class cNtfsPathClassification
|
||||||
|
{
|
||||||
|
public string NormalizedPath { get; set; } = string.Empty;
|
||||||
|
public eNtfsPathKind Kind { get; set; } = eNtfsPathKind.Unknown;
|
||||||
|
public string BoundaryPath { get; set; } = string.Empty;
|
||||||
|
public string ParentBoundaryPath { get; set; } = string.Empty;
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
public int Level { get; set; } = -1;
|
||||||
|
}
|
||||||
|
|
||||||
public static Guid nftsModuleId = new Guid("77e213a1-6517-ea11-4881-000c2980fd94");
|
public static Guid nftsModuleId = new Guid("77e213a1-6517-ea11-4881-000c2980fd94");
|
||||||
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);
|
||||||
|
|
||||||
//public readonly bool WithoutPrivateFolders = true;
|
//public readonly bool WithoutPrivateFolders = true;
|
||||||
|
|
||||||
@@ -145,40 +167,15 @@ namespace C4IT.LIAM
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var DataAreas = new List<cLiamDataAreaBase>();
|
var DataAreas = new List<cLiamDataAreaBase>();
|
||||||
|
var rootClassification = ClassifyPath(this.RootPath);
|
||||||
|
var rootDataArea = await BuildDataAreaAsync(rootClassification);
|
||||||
|
if (rootDataArea == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
var rootpathSplit = this.RootPath.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
|
DataAreas.Add(rootDataArea);
|
||||||
cLiamNtfsShare share = null;
|
|
||||||
cLiamNtfsFolder NtfsRootFolder = null;
|
if (Depth == 0)
|
||||||
switch (rootpathSplit.Length)
|
return DataAreas;
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
return null;
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
share = new cLiamNtfsShare(this, new cNtfsResultShare()
|
|
||||||
{
|
|
||||||
DisplayName = rootpathSplit.Last(),
|
|
||||||
Path = RootPath,
|
|
||||||
Level = 0
|
|
||||||
});
|
|
||||||
await share.ResolvePermissionGroupsAsync(share.TechnicalName);
|
|
||||||
DataAreas.Add(share);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
NtfsRootFolder = new cLiamNtfsFolder(this, null, null, new cNtfsResultFolder()
|
|
||||||
{
|
|
||||||
DisplayName = rootpathSplit.Last(),
|
|
||||||
Path = RootPath,
|
|
||||||
Level = 0
|
|
||||||
});
|
|
||||||
await NtfsRootFolder.ResolvePermissionGroupsAsync(NtfsRootFolder.TechnicalName);
|
|
||||||
DataAreas.Add(NtfsRootFolder);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var DAL = await ntfsBase.RequestFoldersListAsync(this.RootPath, Depth);
|
var DAL = await ntfsBase.RequestFoldersListAsync(this.RootPath, Depth);
|
||||||
if (DAL == null)
|
if (DAL == null)
|
||||||
@@ -189,10 +186,10 @@ namespace C4IT.LIAM
|
|||||||
if (!string.IsNullOrEmpty(this.DataAreaRegEx) && !Regex.Match(Entry.Value.DisplayName, this.DataAreaRegEx).Success)
|
if (!string.IsNullOrEmpty(this.DataAreaRegEx) && !Regex.Match(Entry.Value.DisplayName, this.DataAreaRegEx).Success)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
var classification = ClassifyPath(Entry.Value.Path);
|
||||||
var Folder = new cLiamNtfsFolder(this, share, NtfsRootFolder, (cNtfsResultFolder)Entry.Value);
|
var dataArea = await BuildDataAreaAsync(classification, Entry.Value as cNtfsResultFolder);
|
||||||
await Folder.ResolvePermissionGroupsAsync(Folder.TechnicalName);
|
if (dataArea != null)
|
||||||
DataAreas.Add(Folder);
|
DataAreas.Add(dataArea);
|
||||||
}
|
}
|
||||||
return DataAreas;
|
return DataAreas;
|
||||||
}
|
}
|
||||||
@@ -209,7 +206,6 @@ namespace C4IT.LIAM
|
|||||||
}
|
}
|
||||||
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
||||||
{
|
{
|
||||||
//TODO implement LoadDataArea
|
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
try
|
try
|
||||||
@@ -222,36 +218,8 @@ namespace C4IT.LIAM
|
|||||||
}
|
}
|
||||||
if (!await LogonAsync())
|
if (!await LogonAsync())
|
||||||
return null;
|
return null;
|
||||||
var splt = UID.Split(System.IO.Path.DirectorySeparatorChar);
|
var classification = ClassifyPath(UID);
|
||||||
var name = Path.GetDirectoryName(UID);
|
return await BuildDataAreaAsync(classification);
|
||||||
switch (splt.Length)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
return null;
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
var share = new cLiamNtfsShare(this, new cNtfsResultShare()
|
|
||||||
{
|
|
||||||
DisplayName = name,
|
|
||||||
Path = UID,
|
|
||||||
Level = getDepth(UID)
|
|
||||||
});
|
|
||||||
await share.ResolvePermissionGroupsAsync(share.TechnicalName);
|
|
||||||
return share;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
var folder = new cLiamNtfsFolder(this, null, null, new cNtfsResultFolder()
|
|
||||||
{
|
|
||||||
DisplayName = name,
|
|
||||||
Path = UID,
|
|
||||||
Level = getDepth(UID)
|
|
||||||
});
|
|
||||||
await folder.ResolvePermissionGroupsAsync(folder.TechnicalName);
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
@@ -265,6 +233,208 @@ namespace C4IT.LIAM
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<cLiamDataAreaBase> BuildDataAreaAsync(cNtfsPathClassification classification, cNtfsResultFolder folderResult = null)
|
||||||
|
{
|
||||||
|
if (classification == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (classification.Kind)
|
||||||
|
{
|
||||||
|
case eNtfsPathKind.ClassicShare:
|
||||||
|
case eNtfsPathKind.DfsLink:
|
||||||
|
{
|
||||||
|
var share = new cLiamNtfsShare(this, new cNtfsResultShare()
|
||||||
|
{
|
||||||
|
DisplayName = classification.DisplayName,
|
||||||
|
Path = classification.NormalizedPath,
|
||||||
|
Level = classification.Level
|
||||||
|
}, classification.ParentBoundaryPath);
|
||||||
|
await share.ResolvePermissionGroupsAsync(share.TechnicalName);
|
||||||
|
return share;
|
||||||
|
}
|
||||||
|
case eNtfsPathKind.DfsNamespaceRoot:
|
||||||
|
{
|
||||||
|
var namespaceRoot = new cLiamNtfsDfsNamespaceRoot(this, new cNtfsResultShare()
|
||||||
|
{
|
||||||
|
DisplayName = classification.DisplayName,
|
||||||
|
Path = classification.NormalizedPath,
|
||||||
|
Level = classification.Level
|
||||||
|
});
|
||||||
|
await namespaceRoot.ResolvePermissionGroupsAsync(namespaceRoot.TechnicalName);
|
||||||
|
return namespaceRoot;
|
||||||
|
}
|
||||||
|
case eNtfsPathKind.Folder:
|
||||||
|
{
|
||||||
|
var folderData = folderResult ?? new cNtfsResultFolder()
|
||||||
|
{
|
||||||
|
DisplayName = classification.DisplayName,
|
||||||
|
Path = classification.NormalizedPath,
|
||||||
|
Level = classification.Level,
|
||||||
|
CreatedDate = Directory.Exists(classification.NormalizedPath)
|
||||||
|
? new DirectoryInfo(classification.NormalizedPath).CreationTimeUtc.ToString("s")
|
||||||
|
: DateTime.MinValue.ToString("s")
|
||||||
|
};
|
||||||
|
var folder = new cLiamNtfsFolder(this, null, null, folderData, classification.ParentBoundaryPath);
|
||||||
|
await folder.ResolvePermissionGroupsAsync(folder.TechnicalName);
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private cNtfsPathClassification ClassifyPath(string path)
|
||||||
|
{
|
||||||
|
var normalizedPath = NormalizeUncPath(path);
|
||||||
|
var segments = GetUncSegments(normalizedPath);
|
||||||
|
var classification = new cNtfsPathClassification()
|
||||||
|
{
|
||||||
|
NormalizedPath = normalizedPath,
|
||||||
|
DisplayName = GetDisplayName(normalizedPath),
|
||||||
|
Level = getDepth(normalizedPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (segments.Length == 1)
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.ServerRoot;
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segments.Length < 2)
|
||||||
|
return classification;
|
||||||
|
|
||||||
|
var serverName = segments[0];
|
||||||
|
var publishedShares = GetPublishedShareNames(serverName);
|
||||||
|
var firstBoundaryPath = BuildUncPath(segments, 2);
|
||||||
|
|
||||||
|
if (segments.Length == 2)
|
||||||
|
{
|
||||||
|
if (publishedShares.Contains(segments[1]))
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.ClassicShare;
|
||||||
|
classification.BoundaryPath = normalizedPath;
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(normalizedPath))
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.DfsNamespaceRoot;
|
||||||
|
classification.BoundaryPath = normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publishedShares.Contains(segments[1]))
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.Folder;
|
||||||
|
classification.BoundaryPath = firstBoundaryPath;
|
||||||
|
classification.ParentBoundaryPath = segments.Length == 3
|
||||||
|
? firstBoundaryPath
|
||||||
|
: BuildUncPath(segments, segments.Length - 1);
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(firstBoundaryPath))
|
||||||
|
{
|
||||||
|
if (segments.Length == 3)
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.DfsLink;
|
||||||
|
classification.BoundaryPath = normalizedPath;
|
||||||
|
classification.ParentBoundaryPath = firstBoundaryPath;
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
classification.Kind = eNtfsPathKind.Folder;
|
||||||
|
classification.BoundaryPath = BuildUncPath(segments, 3);
|
||||||
|
classification.ParentBoundaryPath = segments.Length == 4
|
||||||
|
? BuildUncPath(segments, 3)
|
||||||
|
: BuildUncPath(segments, segments.Length - 1);
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string NormalizeUncPath(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var segments = path.Trim().Replace('/', '\\').Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (segments.Length == 0)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return @"\\" + string.Join("\\", segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string[] GetUncSegments(string path)
|
||||||
|
{
|
||||||
|
var normalized = NormalizeUncPath(path);
|
||||||
|
return normalized.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildUncPath(string[] segments, int segmentCount)
|
||||||
|
{
|
||||||
|
if (segments == null || segmentCount <= 0 || segments.Length < segmentCount)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return @"\\" + string.Join("\\", segments.Take(segmentCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetDisplayName(string path)
|
||||||
|
{
|
||||||
|
var segments = GetUncSegments(path);
|
||||||
|
if (segments.Length == 0)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return segments.Last();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<string> GetPublishedShareNames(string serverName)
|
||||||
|
{
|
||||||
|
HashSet<string> shares;
|
||||||
|
if (publishedShareCache.TryGetValue(serverName, out shares))
|
||||||
|
return shares;
|
||||||
|
|
||||||
|
shares = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var connection = new cNetworkConnection(this.RootPath, this.Credential?.Identification, this.Credential?.Secret))
|
||||||
|
{
|
||||||
|
foreach (var share in connection.EnumNetShares(serverName))
|
||||||
|
{
|
||||||
|
if (!IsVisibleDiskShare(share))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
shares.Add(share.shi1_netname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
publishedShareCache[serverName] = shares;
|
||||||
|
return shares;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsVisibleDiskShare(C4IT_IAM.SHARE_INFO_1 share)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(share.shi1_netname))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (share.shi1_netname.StartsWith("ERROR=", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (share.shi1_netname.EndsWith("$", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var shareType = share.shi1_type & 0xFF;
|
||||||
|
return shareType == (uint)C4IT_IAM.SHARE_TYPE.STYPE_DISKTREE;
|
||||||
|
}
|
||||||
|
|
||||||
public override async Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
public override async Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -393,7 +563,8 @@ namespace C4IT.LIAM
|
|||||||
groupReadTag = GetRequiredCustomTag("Filesystem_GroupReadTag"),
|
groupReadTag = GetRequiredCustomTag("Filesystem_GroupReadTag"),
|
||||||
groupTraverseTag = GetRequiredCustomTag("Filesystem_GroupTraverseTag"),
|
groupTraverseTag = GetRequiredCustomTag("Filesystem_GroupTraverseTag"),
|
||||||
groupDLTag = requiresDomainLocalTag ? GetRequiredCustomTag("Filesystem_GroupDomainLocalTag") : string.Empty,
|
groupDLTag = requiresDomainLocalTag ? GetRequiredCustomTag("Filesystem_GroupDomainLocalTag") : string.Empty,
|
||||||
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag")
|
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
|
||||||
|
allowExistingGroupWildcardMatch = IsAdditionalConfigurationEnabled("EnsureNtfsPermissionGroupsAllowRegexMatch")
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var template in BuildSecurityGroupTemplates())
|
foreach (var template in BuildSecurityGroupTemplates())
|
||||||
@@ -402,6 +573,19 @@ namespace C4IT.LIAM
|
|||||||
return engine;
|
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()
|
private IEnumerable<IAM_SecurityGroupTemplate> BuildSecurityGroupTemplates()
|
||||||
{
|
{
|
||||||
var templates = new List<IAM_SecurityGroupTemplate>();
|
var templates = new List<IAM_SecurityGroupTemplate>();
|
||||||
@@ -689,7 +873,7 @@ namespace C4IT.LIAM
|
|||||||
{
|
{
|
||||||
private readonly cNtfsResultBase Share = null;
|
private readonly cNtfsResultBase Share = null;
|
||||||
|
|
||||||
public cLiamNtfsShare(cLiamProviderNtfs Provider, cNtfsResultBase Share) :
|
public cLiamNtfsShare(cLiamProviderNtfs Provider, cNtfsResultBase Share, string parentPath = null) :
|
||||||
base(Provider)
|
base(Provider)
|
||||||
{
|
{
|
||||||
this.Share = Share;
|
this.Share = Share;
|
||||||
@@ -701,6 +885,8 @@ namespace C4IT.LIAM
|
|||||||
this.DataType = eLiamDataAreaTypes.NtfsShare;
|
this.DataType = eLiamDataAreaTypes.NtfsShare;
|
||||||
if (Directory.Exists(Share.Path))
|
if (Directory.Exists(Share.Path))
|
||||||
this.CreatedDate = new DirectoryInfo(Share.Path).CreationTimeUtc.ToString("s");
|
this.CreatedDate = new DirectoryInfo(Share.Path).CreationTimeUtc.ToString("s");
|
||||||
|
if (!string.IsNullOrWhiteSpace(parentPath))
|
||||||
|
this.ParentUID = cLiamNtfsFolder.GetUniqueDataAreaID(parentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<List<cLiamDataAreaBase>> getFolders()
|
internal async Task<List<cLiamDataAreaBase>> getFolders()
|
||||||
@@ -746,6 +932,30 @@ namespace C4IT.LIAM
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public class cLiamNtfsDfsNamespaceRoot : cLiamNtfsPermissionDataAreaBase
|
||||||
|
{
|
||||||
|
private readonly cNtfsResultBase NamespaceRoot = null;
|
||||||
|
|
||||||
|
public cLiamNtfsDfsNamespaceRoot(cLiamProviderNtfs Provider, cNtfsResultBase NamespaceRoot) :
|
||||||
|
base(Provider)
|
||||||
|
{
|
||||||
|
this.NamespaceRoot = NamespaceRoot;
|
||||||
|
|
||||||
|
this.DisplayName = NamespaceRoot.Path.Split('\\').Last();
|
||||||
|
this.TechnicalName = NamespaceRoot.Path;
|
||||||
|
this.UID = cLiamNtfsFolder.GetUniqueDataAreaID(NamespaceRoot.Path);
|
||||||
|
this.Level = NamespaceRoot.Level;
|
||||||
|
this.DataType = eLiamDataAreaTypes.DfsNamespaceRoot;
|
||||||
|
if (Directory.Exists(NamespaceRoot.Path))
|
||||||
|
this.CreatedDate = new DirectoryInfo(NamespaceRoot.Path).CreationTimeUtc.ToString("s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
}
|
||||||
public class cLiamAdGroup : cLiamDataAreaBase
|
public class cLiamAdGroup : cLiamDataAreaBase
|
||||||
{
|
{
|
||||||
public new readonly cLiamProviderNtfs Provider = null;
|
public new readonly cLiamProviderNtfs Provider = null;
|
||||||
@@ -768,7 +978,7 @@ namespace C4IT.LIAM
|
|||||||
{
|
{
|
||||||
public readonly cLiamNtfsShare Share = null;
|
public readonly cLiamNtfsShare Share = null;
|
||||||
public readonly cLiamNtfsFolder NtfsRootFolder = null;
|
public readonly cLiamNtfsFolder NtfsRootFolder = null;
|
||||||
public cLiamNtfsFolder(cLiamProviderNtfs Provider, cLiamNtfsShare share, cLiamNtfsFolder ntfsRootFolder, cNtfsResultFolder NtfsFolder) : base(Provider)
|
public cLiamNtfsFolder(cLiamProviderNtfs Provider, cLiamNtfsShare share, cLiamNtfsFolder ntfsRootFolder, cNtfsResultFolder NtfsFolder, string parentPathOverride = null) : base(Provider)
|
||||||
{
|
{
|
||||||
var ntfsParent = NtfsFolder.Parent;
|
var ntfsParent = NtfsFolder.Parent;
|
||||||
this.NtfsRootFolder = ntfsRootFolder;
|
this.NtfsRootFolder = ntfsRootFolder;
|
||||||
@@ -787,6 +997,8 @@ namespace C4IT.LIAM
|
|||||||
{
|
{
|
||||||
this.ParentUID = GetUniqueDataAreaID(this.Provider.RootPath);
|
this.ParentUID = GetUniqueDataAreaID(this.Provider.RootPath);
|
||||||
}
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(this.ParentUID) && !string.IsNullOrWhiteSpace(parentPathOverride))
|
||||||
|
this.ParentUID = GetUniqueDataAreaID(parentPathOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetUniqueDataAreaID(string fullPath)
|
public static string GetUniqueDataAreaID(string fullPath)
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ namespace C4IT_IAM_SET
|
|||||||
public ICollection<string> ownerUserSids;
|
public ICollection<string> ownerUserSids;
|
||||||
public ICollection<string> readerUserSids;
|
public ICollection<string> readerUserSids;
|
||||||
public ICollection<string> writerUserSids;
|
public ICollection<string> writerUserSids;
|
||||||
|
public bool allowExistingGroupWildcardMatch;
|
||||||
|
|
||||||
public int ReadACLPermission = 0x200A9;
|
public int ReadACLPermission = 0x200A9;
|
||||||
public int WriteACLPermission = 0x301BF;
|
public int WriteACLPermission = 0x301BF;
|
||||||
@@ -144,6 +145,7 @@ namespace C4IT_IAM_SET
|
|||||||
newSecurityGroups.username = username;
|
newSecurityGroups.username = username;
|
||||||
newSecurityGroups.domainName = domainName;
|
newSecurityGroups.domainName = domainName;
|
||||||
newSecurityGroups.password = password;
|
newSecurityGroups.password = password;
|
||||||
|
newSecurityGroups.AllowExistingGroupWildcardMatch = allowExistingGroupWildcardMatch;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// ImpersonationHelper.Impersonate(domainName, username, new NetworkCredential("", password).Password, delegate
|
// ImpersonationHelper.Impersonate(domainName, username, new NetworkCredential("", password).Password, delegate
|
||||||
@@ -274,7 +276,8 @@ namespace C4IT_IAM_SET
|
|||||||
{
|
{
|
||||||
username = username,
|
username = username,
|
||||||
domainName = domainName,
|
domainName = domainName,
|
||||||
password = password
|
password = password,
|
||||||
|
AllowExistingGroupWildcardMatch = allowExistingGroupWildcardMatch
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,9 +912,8 @@ namespace C4IT_IAM_SET
|
|||||||
else
|
else
|
||||||
users = null;
|
users = null;
|
||||||
|
|
||||||
var groupAlreadyExists = newSecurityGroups.GroupAllreadyExisting(newSecurityGroups.IAM_SecurityGroups[i].Name.ToUpper());
|
|
||||||
newSecurityGroups.EnsureADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], users);
|
newSecurityGroups.EnsureADGroup(groupOUPath, newSecurityGroups.IAM_SecurityGroups[i], users);
|
||||||
if (groupAlreadyExists)
|
if (newSecurityGroups.IAM_SecurityGroups[i].ReusedExistingEntry)
|
||||||
resultToken.reusedGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
resultToken.reusedGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
||||||
else
|
else
|
||||||
resultToken.createdGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
resultToken.createdGroups.Add(newSecurityGroups.IAM_SecurityGroups[i].Name);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace C4IT_IAM_Engine
|
|||||||
public string domainName;
|
public string domainName;
|
||||||
public string username;
|
public string username;
|
||||||
public SecureString password;
|
public SecureString password;
|
||||||
|
public bool AllowExistingGroupWildcardMatch;
|
||||||
|
|
||||||
public List<IAM_SecurityGroup> IAM_SecurityGroups;
|
public List<IAM_SecurityGroup> IAM_SecurityGroups;
|
||||||
public string rootUID;
|
public string rootUID;
|
||||||
@@ -208,6 +209,7 @@ namespace C4IT_IAM_Engine
|
|||||||
{
|
{
|
||||||
Name = ownerGlobal.NamingTemplate,
|
Name = ownerGlobal.NamingTemplate,
|
||||||
description = ownerGlobal.DescriptionTemplate,
|
description = ownerGlobal.DescriptionTemplate,
|
||||||
|
WildcardPattern = ownerGlobal.WildcardTemplate,
|
||||||
|
|
||||||
technicalName = "CN=" + ownerGlobal.NamingTemplate + "," + ouPath,
|
technicalName = "CN=" + ownerGlobal.NamingTemplate + "," + ouPath,
|
||||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||||
@@ -221,6 +223,7 @@ namespace C4IT_IAM_Engine
|
|||||||
{
|
{
|
||||||
Name = writeGlobal.NamingTemplate,
|
Name = writeGlobal.NamingTemplate,
|
||||||
description = writeGlobal.DescriptionTemplate,
|
description = writeGlobal.DescriptionTemplate,
|
||||||
|
WildcardPattern = writeGlobal.WildcardTemplate,
|
||||||
|
|
||||||
technicalName = "CN=" + writeGlobal.NamingTemplate + "," + ouPath,
|
technicalName = "CN=" + writeGlobal.NamingTemplate + "," + ouPath,
|
||||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||||
@@ -234,6 +237,7 @@ namespace C4IT_IAM_Engine
|
|||||||
{
|
{
|
||||||
Name = readGlobal.NamingTemplate,
|
Name = readGlobal.NamingTemplate,
|
||||||
description = readGlobal.DescriptionTemplate,
|
description = readGlobal.DescriptionTemplate,
|
||||||
|
WildcardPattern = readGlobal.WildcardTemplate,
|
||||||
|
|
||||||
technicalName = "CN=" + readGlobal.NamingTemplate + "," + ouPath,
|
technicalName = "CN=" + readGlobal.NamingTemplate + "," + ouPath,
|
||||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||||
@@ -251,6 +255,7 @@ namespace C4IT_IAM_Engine
|
|||||||
{
|
{
|
||||||
Name = ownerDL.NamingTemplate,
|
Name = ownerDL.NamingTemplate,
|
||||||
description = ownerDL.DescriptionTemplate,
|
description = ownerDL.DescriptionTemplate,
|
||||||
|
WildcardPattern = ownerDL.WildcardTemplate,
|
||||||
|
|
||||||
technicalName = "CN=" + ownerDL.NamingTemplate + "," + ouPath,
|
technicalName = "CN=" + ownerDL.NamingTemplate + "," + ouPath,
|
||||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||||
@@ -265,6 +270,7 @@ namespace C4IT_IAM_Engine
|
|||||||
{
|
{
|
||||||
Name = writeDL.NamingTemplate,
|
Name = writeDL.NamingTemplate,
|
||||||
description = writeDL.DescriptionTemplate,
|
description = writeDL.DescriptionTemplate,
|
||||||
|
WildcardPattern = writeDL.WildcardTemplate,
|
||||||
|
|
||||||
technicalName = "CN=" + writeDL.NamingTemplate + "," + ouPath,
|
technicalName = "CN=" + writeDL.NamingTemplate + "," + ouPath,
|
||||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||||
@@ -279,6 +285,7 @@ namespace C4IT_IAM_Engine
|
|||||||
{
|
{
|
||||||
Name = readDL.NamingTemplate,
|
Name = readDL.NamingTemplate,
|
||||||
description = readDL.DescriptionTemplate,
|
description = readDL.DescriptionTemplate,
|
||||||
|
WildcardPattern = readDL.WildcardTemplate,
|
||||||
|
|
||||||
technicalName = "CN=" + readDL.NamingTemplate + "," + ouPath,
|
technicalName = "CN=" + readDL.NamingTemplate + "," + ouPath,
|
||||||
targetTyp = (int)IAM_TargetType.FileSystem,
|
targetTyp = (int)IAM_TargetType.FileSystem,
|
||||||
@@ -293,6 +300,7 @@ namespace C4IT_IAM_Engine
|
|||||||
secGroup.description = secGroup.description.ReplaceLoopTag(0);
|
secGroup.description = secGroup.description.ReplaceLoopTag(0);
|
||||||
secGroup.Name = secGroup.Name.ReplaceLoopTag(loop);
|
secGroup.Name = secGroup.Name.ReplaceLoopTag(loop);
|
||||||
secGroup.technicalName = secGroup.technicalName.ReplaceLoopTag(loop);
|
secGroup.technicalName = secGroup.technicalName.ReplaceLoopTag(loop);
|
||||||
|
secGroup.WildcardPattern = secGroup.WildcardPattern.ReplaceLoopTag(loop);
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Security group generated: {secGroup.technicalName}");
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Security group generated: {secGroup.technicalName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,6 +406,92 @@ namespace C4IT_IAM_Engine
|
|||||||
return groupEntry;
|
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)
|
private static bool HasMember(PropertyValueCollection members, string distinguishedName)
|
||||||
{
|
{
|
||||||
foreach (var member in members)
|
foreach (var member in members)
|
||||||
@@ -450,13 +544,16 @@ namespace C4IT_IAM_Engine
|
|||||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
secGroup.ReusedExistingEntry = false;
|
||||||
var existingGroup = FindGroupEntry(secGroup.Name);
|
var existingGroup = FindGroupEntry(secGroup.Name);
|
||||||
|
if (existingGroup == null && AllowExistingGroupWildcardMatch)
|
||||||
|
existingGroup = FindGroupEntryByWildcard(ouPath, secGroup.WildcardPattern);
|
||||||
|
|
||||||
if (existingGroup == null)
|
if (existingGroup == null)
|
||||||
return CreateADGroup(ouPath, secGroup, users);
|
return CreateADGroup(ouPath, secGroup, users);
|
||||||
|
|
||||||
AddMissingMembers(existingGroup, secGroup, users);
|
AddMissingMembers(existingGroup, secGroup, users);
|
||||||
var objectid = getSID(existingGroup);
|
ApplyExistingGroup(secGroup, existingGroup);
|
||||||
secGroup.UID = objectid;
|
|
||||||
return existingGroup;
|
return existingGroup;
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
@@ -475,6 +572,7 @@ namespace C4IT_IAM_Engine
|
|||||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
secGroup.ReusedExistingEntry = false;
|
||||||
if (!GroupAllreadyExisting(secGroup.Name.ToUpper()))
|
if (!GroupAllreadyExisting(secGroup.Name.ToUpper()))
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -518,9 +616,8 @@ namespace C4IT_IAM_Engine
|
|||||||
DirectoryEntry e = FindGroupEntry(secGroup.Name);
|
DirectoryEntry e = FindGroupEntry(secGroup.Name);
|
||||||
if (e == null)
|
if (e == null)
|
||||||
return null;
|
return null;
|
||||||
var objectid = getSID(e);
|
|
||||||
secGroup.UID = objectid;
|
|
||||||
AddMissingMembers(e, secGroup, users);
|
AddMissingMembers(e, secGroup, users);
|
||||||
|
ApplyExistingGroup(secGroup, e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -588,6 +685,8 @@ namespace C4IT_IAM_Engine
|
|||||||
public string UID;
|
public string UID;
|
||||||
public string Parent = "";
|
public string Parent = "";
|
||||||
public string description;
|
public string description;
|
||||||
|
public string WildcardPattern;
|
||||||
|
public bool ReusedExistingEntry;
|
||||||
public List<IAM_SecurityGroup> memberGroups;
|
public List<IAM_SecurityGroup> memberGroups;
|
||||||
public string Name;
|
public string Name;
|
||||||
public string technicalName;
|
public string technicalName;
|
||||||
|
|||||||
@@ -628,7 +628,7 @@ namespace LiamWorkflowActivities
|
|||||||
if (!IsAdditionalConfigurationEnabled(providerEntry.Provider, "EnsureNtfsPermissionGroups"))
|
if (!IsAdditionalConfigurationEnabled(providerEntry.Provider, "EnsureNtfsPermissionGroups"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
foreach (var ntfsArea in dataAreas.OfType<cLiamNtfsPermissionDataAreaBase>())
|
foreach (var ntfsArea in dataAreas.OfType<cLiamNtfsFolder>())
|
||||||
{
|
{
|
||||||
var folderPath = ntfsArea.TechnicalName;
|
var folderPath = ntfsArea.TechnicalName;
|
||||||
if (string.IsNullOrWhiteSpace(folderPath))
|
if (string.IsNullOrWhiteSpace(folderPath))
|
||||||
|
|||||||
Reference in New Issue
Block a user