Generalize NTFS path policy
This commit is contained in:
@@ -53,6 +53,8 @@ namespace C4IT.LIAM
|
||||
}
|
||||
|
||||
public static Guid nftsModuleId = new Guid("77e213a1-6517-ea11-4881-000c2980fd94");
|
||||
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
|
||||
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
|
||||
public readonly cNtfsBase ntfsBase = new cNtfsBase();
|
||||
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||
private readonly Dictionary<string, HashSet<string>> publishedShareCache = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
@@ -208,6 +210,9 @@ namespace C4IT.LIAM
|
||||
if (!await LogonAsync())
|
||||
return null;
|
||||
var classification = ClassifyPath(UID);
|
||||
if (!PathsEqual(classification?.NormalizedPath, this.RootPath) && !ShouldIncludeDataArea(classification))
|
||||
return null;
|
||||
|
||||
return await BuildDataAreaAsync(classification);
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -434,13 +439,13 @@ namespace C4IT.LIAM
|
||||
|
||||
string matchingConfigurationKey;
|
||||
string matchingRule;
|
||||
if (IsBlacklistedFolderPath(classification, out matchingConfigurationKey, out matchingRule))
|
||||
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
|
||||
{
|
||||
LogEntry($"Skip NTFS path '{classification.NormalizedPath}' due to AdditionalConfiguration rule '{matchingConfigurationKey}={matchingRule}'", LogLevels.Debug);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsWhitelistedFolderPath(classification, true, out matchingConfigurationKey, out matchingRule))
|
||||
if (!IsPathWhitelisted(classification, true, out matchingConfigurationKey, out matchingRule))
|
||||
{
|
||||
LogEntry($"Skip NTFS path '{classification.NormalizedPath}' because no AdditionalConfiguration whitelist matched", LogLevels.Debug);
|
||||
return false;
|
||||
@@ -456,25 +461,19 @@ namespace C4IT.LIAM
|
||||
|
||||
string matchingConfigurationKey;
|
||||
string matchingRule;
|
||||
if (IsBlacklistedFolderPath(classification, out matchingConfigurationKey, out matchingRule))
|
||||
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
|
||||
{
|
||||
LogEntry($"Skip NTFS subtree '{classification.NormalizedPath}' due to AdditionalConfiguration rule '{matchingConfigurationKey}={matchingRule}'", LogLevels.Debug);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasAdditionalConfigurationValues("NtfsIncludeFolderNames"))
|
||||
if (!HasAdditionalConfigurationValues(AdditionalConfigurationIncludePathsKey))
|
||||
return true;
|
||||
|
||||
if (!HasAdditionalConfigurationValues("NtfsIncludeRelativePaths"))
|
||||
if (IsPathWhitelisted(classification, true, out matchingConfigurationKey, out matchingRule))
|
||||
return true;
|
||||
|
||||
if (classification.Kind != eNtfsPathKind.Folder)
|
||||
return true;
|
||||
|
||||
if (IsWhitelistedFolderPath(classification, true, out matchingConfigurationKey, out matchingRule))
|
||||
return true;
|
||||
|
||||
LogEntry($"Skip NTFS subtree '{classification.NormalizedPath}' because it is outside AdditionalConfiguration whitelist 'NtfsIncludeRelativePaths'", LogLevels.Debug);
|
||||
LogEntry($"Skip NTFS subtree '{classification.NormalizedPath}' because it is outside AdditionalConfiguration whitelist '{AdditionalConfigurationIncludePathsKey}'", LogLevels.Debug);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -486,85 +485,57 @@ namespace C4IT.LIAM
|
||||
return Regex.Match(displayName ?? string.Empty, this.DataAreaRegEx).Success;
|
||||
}
|
||||
|
||||
private bool IsBlacklistedFolderPath(cNtfsPathClassification classification, out string matchingConfigurationKey, out string matchingRule)
|
||||
private bool IsPathBlacklisted(cNtfsPathClassification classification, out string matchingConfigurationKey, out string matchingRule)
|
||||
{
|
||||
matchingConfigurationKey = null;
|
||||
matchingRule = null;
|
||||
|
||||
if (classification == null || classification.Kind != eNtfsPathKind.Folder)
|
||||
return false;
|
||||
|
||||
foreach (var excludedFolderName in GetAdditionalConfigurationValues("NtfsExcludeFolderNames"))
|
||||
{
|
||||
if (!MatchesAdditionalConfigurationPattern(classification.DisplayName, excludedFolderName))
|
||||
continue;
|
||||
|
||||
matchingConfigurationKey = "NtfsExcludeFolderNames";
|
||||
matchingRule = excludedFolderName;
|
||||
return true;
|
||||
}
|
||||
|
||||
var relativePath = GetRelativePathFromRoot(classification.NormalizedPath);
|
||||
foreach (var excludedRelativePath in GetAdditionalConfigurationValues("NtfsExcludeRelativePaths"))
|
||||
{
|
||||
if (!MatchesAdditionalConfigurationPattern(relativePath, excludedRelativePath))
|
||||
continue;
|
||||
|
||||
matchingConfigurationKey = "NtfsExcludeRelativePaths";
|
||||
matchingRule = excludedRelativePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return TryMatchPathPolicy(classification, AdditionalConfigurationExcludePathsKey, false, out matchingConfigurationKey, out matchingRule);
|
||||
}
|
||||
|
||||
private bool IsWhitelistedFolderPath(cNtfsPathClassification classification, bool allowRelativePathAncestorMatches, out string matchingConfigurationKey, out string matchingRule)
|
||||
private bool IsPathWhitelisted(cNtfsPathClassification classification, bool allowPathAncestorMatches, out string matchingConfigurationKey, out string matchingRule)
|
||||
{
|
||||
matchingConfigurationKey = null;
|
||||
matchingRule = null;
|
||||
|
||||
if (classification == null || classification.Kind != eNtfsPathKind.Folder)
|
||||
if (!HasAdditionalConfigurationValues(AdditionalConfigurationIncludePathsKey))
|
||||
return true;
|
||||
|
||||
var hasIncludeFolderNames = HasAdditionalConfigurationValues("NtfsIncludeFolderNames");
|
||||
var hasIncludeRelativePaths = HasAdditionalConfigurationValues("NtfsIncludeRelativePaths");
|
||||
if (!hasIncludeFolderNames && !hasIncludeRelativePaths)
|
||||
return true;
|
||||
return TryMatchPathPolicy(classification, AdditionalConfigurationIncludePathsKey, allowPathAncestorMatches, out matchingConfigurationKey, out matchingRule);
|
||||
}
|
||||
|
||||
foreach (var includedFolderName in GetAdditionalConfigurationValues("NtfsIncludeFolderNames"))
|
||||
private bool TryMatchPathPolicy(cNtfsPathClassification classification, string key, bool allowPathAncestorMatches, out string matchingConfigurationKey, out string matchingRule)
|
||||
{
|
||||
matchingConfigurationKey = null;
|
||||
matchingRule = null;
|
||||
|
||||
if (classification == null || string.IsNullOrWhiteSpace(key))
|
||||
return false;
|
||||
|
||||
var patterns = GetAdditionalConfigurationValues(key).ToList();
|
||||
if (patterns.Count == 0)
|
||||
return false;
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
if (!MatchesAdditionalConfigurationPattern(classification.DisplayName, includedFolderName))
|
||||
if (!MatchesPathPolicy(classification, pattern))
|
||||
continue;
|
||||
|
||||
matchingConfigurationKey = "NtfsIncludeFolderNames";
|
||||
matchingRule = includedFolderName;
|
||||
matchingConfigurationKey = key;
|
||||
matchingRule = pattern;
|
||||
return true;
|
||||
}
|
||||
|
||||
var relativePath = GetRelativePathFromRoot(classification.NormalizedPath);
|
||||
foreach (var includedRelativePath in GetAdditionalConfigurationValues("NtfsIncludeRelativePaths"))
|
||||
if (!allowPathAncestorMatches)
|
||||
return false;
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
if (!MatchesAdditionalConfigurationPattern(relativePath, includedRelativePath))
|
||||
if (!CanPathLeadToPattern(classification, pattern))
|
||||
continue;
|
||||
|
||||
matchingConfigurationKey = "NtfsIncludeRelativePaths";
|
||||
matchingRule = includedRelativePath;
|
||||
matchingConfigurationKey = key;
|
||||
matchingRule = pattern;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (allowRelativePathAncestorMatches)
|
||||
{
|
||||
foreach (var includedRelativePath in GetAdditionalConfigurationValues("NtfsIncludeRelativePaths"))
|
||||
{
|
||||
if (!IsRelativePathAncestorOfPattern(relativePath, includedRelativePath))
|
||||
continue;
|
||||
|
||||
matchingConfigurationKey = "NtfsIncludeRelativePaths";
|
||||
matchingRule = includedRelativePath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -611,12 +582,45 @@ namespace C4IT.LIAM
|
||||
.Replace('/', '\\');
|
||||
}
|
||||
|
||||
private bool MatchesPathPolicy(cNtfsPathClassification classification, string pattern)
|
||||
{
|
||||
if (classification == null || string.IsNullOrWhiteSpace(pattern))
|
||||
return false;
|
||||
|
||||
foreach (var candidate in GetPathPolicyCandidates(classification))
|
||||
{
|
||||
if (MatchesAdditionalConfigurationPattern(candidate, pattern))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetPathPolicyCandidates(cNtfsPathClassification classification)
|
||||
{
|
||||
if (classification == null)
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
var candidates = new List<string>();
|
||||
var relativePath = GetRelativePathFromRoot(classification.NormalizedPath);
|
||||
if (!string.IsNullOrWhiteSpace(relativePath))
|
||||
candidates.Add(relativePath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(classification.NormalizedPath))
|
||||
candidates.Add(classification.NormalizedPath);
|
||||
|
||||
return candidates
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private bool MatchesAdditionalConfigurationPattern(string value, string pattern)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value) || string.IsNullOrWhiteSpace(pattern))
|
||||
return false;
|
||||
|
||||
var normalizedValue = value.Trim().Replace('/', '\\');
|
||||
var normalizedValue = value.Trim().Replace('/', '\\').Trim('\\');
|
||||
var normalizedPattern = pattern.Trim().Replace('/', '\\').Trim('\\');
|
||||
if (string.IsNullOrWhiteSpace(normalizedPattern))
|
||||
return false;
|
||||
@@ -625,27 +629,51 @@ namespace C4IT.LIAM
|
||||
return Regex.IsMatch(normalizedValue, regexPattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
}
|
||||
|
||||
private bool IsRelativePathAncestorOfPattern(string relativePath, string pattern)
|
||||
private bool CanPathLeadToPattern(cNtfsPathClassification classification, string pattern)
|
||||
{
|
||||
var normalizedRelativePath = (relativePath ?? string.Empty).Trim().Replace('/', '\\').Trim('\\');
|
||||
if (string.IsNullOrWhiteSpace(normalizedRelativePath) || string.IsNullOrWhiteSpace(pattern))
|
||||
if (classification == null || string.IsNullOrWhiteSpace(pattern))
|
||||
return false;
|
||||
|
||||
var prefixSegments = new List<string>();
|
||||
foreach (var patternSegment in pattern.Trim().Replace('/', '\\').Trim('\\').Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
foreach (var candidate in GetPathPolicyCandidates(classification))
|
||||
{
|
||||
if (patternSegment.Contains("*"))
|
||||
break;
|
||||
|
||||
prefixSegments.Add(patternSegment);
|
||||
if (IsPathAncestorOfPattern(candidate, pattern))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prefixSegments.Count == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsPathAncestorOfPattern(string path, string pattern)
|
||||
{
|
||||
var normalizedPath = (path ?? string.Empty).Trim().Replace('/', '\\').Trim('\\');
|
||||
var normalizedPattern = (pattern ?? string.Empty).Trim().Replace('/', '\\').Trim('\\');
|
||||
if (string.IsNullOrWhiteSpace(normalizedPath) || string.IsNullOrWhiteSpace(normalizedPattern))
|
||||
return false;
|
||||
|
||||
var normalizedPatternPrefix = string.Join("\\", prefixSegments);
|
||||
return normalizedPatternPrefix.Equals(normalizedRelativePath, StringComparison.OrdinalIgnoreCase)
|
||||
|| normalizedPatternPrefix.StartsWith(normalizedRelativePath + "\\", StringComparison.OrdinalIgnoreCase);
|
||||
var pathSegments = normalizedPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var patternSegments = normalizedPattern.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (pathSegments.Length > patternSegments.Length)
|
||||
return false;
|
||||
|
||||
for (var segmentIndex = 0; segmentIndex < pathSegments.Length; segmentIndex++)
|
||||
{
|
||||
if (segmentIndex >= patternSegments.Length)
|
||||
return false;
|
||||
|
||||
if (!MatchesPatternSegment(pathSegments[segmentIndex], patternSegments[segmentIndex]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool MatchesPatternSegment(string valueSegment, string patternSegment)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(valueSegment) || string.IsNullOrWhiteSpace(patternSegment))
|
||||
return false;
|
||||
|
||||
var regexPattern = "^" + Regex.Escape(patternSegment).Replace("\\*", ".*") + "$";
|
||||
return Regex.IsMatch(valueSegment, regexPattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
}
|
||||
|
||||
private List<string> GetDfsObjectPrefixes(string path)
|
||||
@@ -964,10 +992,10 @@ namespace C4IT.LIAM
|
||||
|
||||
string matchingConfigurationKey;
|
||||
string matchingRule;
|
||||
if (IsBlacklistedFolderPath(classification, out matchingConfigurationKey, out matchingRule))
|
||||
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
|
||||
return false;
|
||||
|
||||
return IsWhitelistedFolderPath(classification, false, out matchingConfigurationKey, out matchingRule);
|
||||
return IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule);
|
||||
}
|
||||
|
||||
private IEnumerable<IAM_SecurityGroupTemplate> BuildSecurityGroupTemplates()
|
||||
|
||||
Reference in New Issue
Block a user