18 Commits

Author SHA1 Message Date
Meik
e0a1fc9595 Document NTFS naming convention placeholders 2026-06-16 11:38:07 +02:00
Meik
8d43d47b82 Bump shared assembly version to 3.3.2 2026-06-16 11:34:29 +02:00
Meik
8394d1e67e Fix README table pipe escaping 2026-05-19 20:39:08 +02:00
Meik
0c16e8a5b1 Document additional provider parameters 2026-05-19 20:35:51 +02:00
Meik
a9b4cfe10b Pin Active Directory provider to domain controller 2026-05-19 20:01:52 +02:00
Meik
723eae1018 Log NTFS ACL naming matches 2026-05-19 19:20:25 +02:00
Meik
0cad46ddef Pin NTFS AD operations to domain controller 2026-05-19 19:12:33 +02:00
Meik
ea0517d1dc Select Consulting4IT signing certificate 2026-05-12 13:03:12 +02:00
Meik
b5c5c12523 Bump version to 3.3.1 2026-05-12 12:50:17 +02:00
Meik
8db5a5d2e6 Derive NTFS traverse scope from group strategy 2026-05-09 23:25:15 +02:00
Meik
2a290b5f86 Sanitize AD unsafe NTFS group name characters 2026-05-08 23:19:54 +02:00
Meik
2b460ccc1a Add configurable NTFS group name formatting 2026-05-08 21:45:36 +02:00
Meik
b9edd16cab Add NTFS root path naming placeholders 2026-05-08 21:34:38 +02:00
Meik
123aa5bf2d Document NTFS traverse ensure configuration 2026-05-08 21:27:42 +02:00
Meik
fc8e907011 Align NTFS ensure traverse handling 2026-05-08 21:25:00 +02:00
Meik
898ed7dd8e Add LIAM permission validation script 2026-05-04 13:54:27 +02:00
Meik
fc64573491 Update LIAM setup installer 2026-05-04 13:52:21 +02:00
Meik
d0a788fa10 Add Bruker delta setup package 2026-03-31 09:03:35 +02:00
40 changed files with 15097 additions and 122 deletions

View File

@@ -30,6 +30,8 @@ namespace C4IT.LIAM
public class cLiamProviderAD : cLiamProviderBase
{
public static Guid adModuleId = new Guid("e820a625-0653-ee11-b886-00155d300101");
private const string AdditionalConfigurationAdDomainControllersKey = "AdDomainControllers";
private const string AdditionalConfigurationActiveDirectoryDomainControllersKey = "ActiveDirectoryDomainControllers";
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
private readonly ADServiceGroupCreator _serviceGroupCreator;
@@ -76,6 +78,7 @@ namespace C4IT.LIAM
var LI = new cADLogonInfo()
{
Domain = Domain,
DomainControllers = GetConfiguredDomainControllers(),
User = Credential?.Identification,
UserSecret = Credential?.Secret,
TargetGroupPath = this.GroupPath
@@ -95,6 +98,26 @@ namespace C4IT.LIAM
return false;
}
private string GetConfiguredDomainControllers()
{
var value = GetAdditionalConfigurationValue(AdditionalConfigurationAdDomainControllersKey);
if (!string.IsNullOrWhiteSpace(value))
return value;
return GetAdditionalConfigurationValue(AdditionalConfigurationActiveDirectoryDomainControllersKey);
}
private string GetAdditionalConfigurationValue(string key)
{
if (AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
return string.Empty;
if (!AdditionalConfiguration.TryGetValue(key, out var rawValue) || string.IsNullOrWhiteSpace(rawValue))
return string.Empty;
return rawValue.Trim();
}
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int Depth = -1)
{
var CM = MethodBase.GetCurrentMethod();
@@ -368,4 +391,4 @@ namespace C4IT.LIAM
this.scope = secGroup.Scope.ToString();
}
}
}
}

View File

@@ -52,6 +52,7 @@ namespace LiamAD
public class cADLogonInfo
{
public string Domain;
public string DomainControllers;
public string User;
public string UserSecret;
public string TargetGroupPath;

View File

@@ -19,7 +19,6 @@ namespace LiamAD
{
private readonly cLiamProviderAD _provider;
private readonly cActiveDirectoryBase _adBase;
private readonly string _ldapRoot;
private readonly string _user;
private readonly string _password;
public enum ADGroupType
@@ -31,11 +30,25 @@ namespace LiamAD
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
_adBase = provider.activeDirectoryBase;
_ldapRoot = $"LDAP://{provider.Domain}/{provider.GroupPath}";
_user = provider.Credential.Identification;
_password = new System.Net.NetworkCredential(_user, provider.Credential.Secret).Password;
}
private string GetLdapServer()
{
return string.IsNullOrWhiteSpace(_adBase.EffectiveDomainController) ? _provider.Domain : _adBase.EffectiveDomainController;
}
private string GetLdapRoot()
{
return $"LDAP://{GetLdapServer()}/{_provider.GroupPath}";
}
private string GetLdapDomainRoot()
{
return $"LDAP://{GetLdapServer()}";
}
/// <summary>
/// Erstellt oder findet beide AD-Gruppen (Member & Owner) für einen Service.
/// Neu mit: gruppenbereich (Scope) und gruppentyp (für Member-Gruppe).
@@ -115,7 +128,7 @@ namespace LiamAD
if (sidList == null) return;
// Basis für die Suche: komplette Domäne, nicht nur der OU-Pfad
string domainRoot = $"LDAP://{_provider.Domain}";
string domainRoot = GetLdapDomainRoot();
using (var root = new DirectoryEntry(domainRoot, _user, _password, AuthenticationTypes.Secure))
using (var grpSearch = new DirectorySearcher(root))
{
@@ -185,7 +198,7 @@ namespace LiamAD
private string GetSid(string name)
{
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
using (var root = new DirectoryEntry(GetLdapRoot(), _user, _password, AuthenticationTypes.Secure))
using (var ds = new DirectorySearcher(root))
{
ds.Filter = $"(&(objectCategory=group)(sAMAccountName={name}))";
@@ -219,7 +232,7 @@ namespace LiamAD
{
if (!GroupExists(groupName))
{
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
using (var root = new DirectoryEntry(GetLdapRoot(), _user, _password, AuthenticationTypes.Secure))
{
var grp = root.Children.Add("CN=" + groupName, "group");
grp.Properties["sAMAccountName"].Value = groupName;
@@ -261,7 +274,7 @@ namespace LiamAD
private string GetDistinguishedName(string name)
{
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
using (var root = new DirectoryEntry(GetLdapRoot(), _user, _password, AuthenticationTypes.Secure))
using (var ds = new DirectorySearcher(root))
{
ds.Filter = "(&(objectClass=group)(sAMAccountName=" + name + "))";
@@ -285,4 +298,4 @@ namespace LiamAD
}
}
}
}
}

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices.AccountManagement;
using System.IO;
using System.Linq;
@@ -25,6 +26,7 @@ namespace LiamAD
private cADLogonInfo privLogonInfo = null;
public PrincipalContext adContext = null;
public DirectoryEntry directoryEntry = null;
public string EffectiveDomainController { get; private set; } = null;
public Exception LastException { get; private set; } = null;
public string LastErrorMessage { get; private set; } = null;
@@ -50,8 +52,12 @@ namespace LiamAD
//TODO: remove dummy delay?
await Task.Delay(0);
ResetError();
adContext = new PrincipalContext(ContextType.Domain, LogonInfo.Domain, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
var ldapPath = $"LDAP://{LogonInfo.Domain}/{LogonInfo.TargetGroupPath}";
var adServer = ResolveEffectiveDomainController(LogonInfo);
adContext = new PrincipalContext(ContextType.Domain, adServer, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
EffectiveDomainController = adContext.ConnectedServer ?? adServer;
LogEntry($"AD provider domain controller pinned to '{EffectiveDomainController}' for domain '{LogonInfo.Domain}'.", LogLevels.Debug);
var ldapPath = $"LDAP://{EffectiveDomainController}/{LogonInfo.TargetGroupPath}";
directoryEntry = new DirectoryEntry
{
Path = ldapPath,
@@ -70,6 +76,78 @@ namespace LiamAD
return false;
}
private string ResolveEffectiveDomainController(cADLogonInfo logonInfo)
{
var configuredDomainControllers = ParseDomainControllers(logonInfo?.DomainControllers);
foreach (var domainController in configuredDomainControllers)
{
if (CanConnectToDomainController(domainController, logonInfo))
return domainController;
LogEntry($"Configured AD provider domain controller '{domainController}' is not reachable. Trying next candidate.", LogLevels.Warning);
}
var pdc = TryGetPdcRoleOwner(logonInfo);
if (!string.IsNullOrWhiteSpace(pdc))
return pdc;
LogEntry($"Could not determine PDC emulator for domain '{logonInfo?.Domain}'. Falling back to domain locator.", LogLevels.Warning);
return logonInfo?.Domain;
}
private static IEnumerable<string> ParseDomainControllers(string domainControllers)
{
if (string.IsNullOrWhiteSpace(domainControllers))
return Enumerable.Empty<string>();
return domainControllers
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i));
}
private bool CanConnectToDomainController(string domainController, cADLogonInfo logonInfo)
{
try
{
using (var context = new PrincipalContext(ContextType.Domain, domainController, logonInfo.User, new NetworkCredential("", logonInfo.UserSecret).Password))
return !string.IsNullOrWhiteSpace(context.ConnectedServer);
}
catch (Exception E)
{
LogException(E, LogLevels.Debug);
return false;
}
}
private string TryGetPdcRoleOwner(cADLogonInfo logonInfo)
{
try
{
var credentials = new DirectoryContext(
DirectoryContextType.Domain,
logonInfo.Domain,
logonInfo.User,
new NetworkCredential("", logonInfo.UserSecret).Password);
using (var domain = Domain.GetDomain(credentials))
return domain?.PdcRoleOwner?.Name;
}
catch (Exception E)
{
LogException(E, LogLevels.Debug);
return null;
}
}
private string GetAdServer()
{
if (!string.IsNullOrWhiteSpace(EffectiveDomainController))
return EffectiveDomainController;
return privLogonInfo?.Domain;
}
private async Task<bool> privRelogon()
{
if (privLogonInfo == null)
@@ -193,7 +271,7 @@ namespace LiamAD
string managedByDn = k.Properties["managedBy"][0].ToString();
// Erstellen eines DirectoryEntry-Objekts für den managedBy-DN
using (DirectoryEntry managedByEntry = new DirectoryEntry($"LDAP://{managedByDn}"))
using (DirectoryEntry managedByEntry = new DirectoryEntry($"LDAP://{GetAdServer()}/{managedByDn}", privLogonInfo.User, new NetworkCredential("", privLogonInfo.UserSecret).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing))
{
if (managedByEntry.Properties.Contains("objectSid") && managedByEntry.Properties["objectSid"].Count > 0)
{
@@ -513,4 +591,4 @@ namespace LiamAD
return null;
}
}
}
}

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<NewDataSet>
<BasicSchemaObjectClass>
<ID>72d6dc7b-bc2b-f111-2986-00155d320605</ID>
<Name>C4IT_LIAMDataAreaClassification</Name>
<IsSchemaObject>0</IsSchemaObject>
<Schema-MetaInfo>
<Name>DisplayExpression</Name>
<Value>DisplayString</Value>
</Schema-MetaInfo>
<DisplayName>C4IT - LIAM - Data Area Classification</DisplayName>
<BasicSchemaObjectClass-CI>
<LCID>7</LCID>
<DisplayName>C4IT - LIAM - Data Area Classification</DisplayName>
</BasicSchemaObjectClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<ClassType>4</ClassType>
<DisableHistory>1</DisableHistory>
<BasicSchemaAttributeClass>
<ID>75d6dc7b-bc2b-f111-2986-00155d320605</ID>
<Name>Position</Name>
<IsSchemaObject>0</IsSchemaObject>
<Description>Position for the pickup</Description>
<DisplayName>Position</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<Description>Position for the pickup</Description>
<DisplayName>Position</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>2</ValueType>
<AttributeLength>4</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>73d6dc7b-bc2b-f111-2986-00155d320605</ID>
<Name>DisplayString</Name>
<IsSchemaObject>0</IsSchemaObject>
<Description>Display value for the pickup</Description>
<DisplayName>Display String</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<Description>Display value for the pickup</Description>
<DisplayName>Display String</DisplayName>
</BasicSchemaAttributeClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>0</ValueType>
<AttributeLength>50</AttributeLength>
<LanguageDependent>1</LanguageDependent>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>74d6dc7b-bc2b-f111-2986-00155d320605</ID>
<Name>Value</Name>
<IsSchemaObject>0</IsSchemaObject>
<Description>ID value for the pickup</Description>
<DisplayName>Value</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<Description>ID value for the pickup</Description>
<DisplayName>Value</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>0</AllowNull>
<ValueType>2</ValueType>
<AttributeLength>4</AttributeLength>
</BasicSchemaAttributeClass>
</BasicSchemaObjectClass>
</NewDataSet>

View File

@@ -0,0 +1,464 @@
<NewDataSet>
<C4IT_LIAMDataAreaClassification>
<ID>f1402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>NtfsServerRoot</DisplayString>
<Value>100</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>f3402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>Unknown</DisplayString>
<Value>0</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>f5402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>NtfsShare</DisplayString>
<Value>101</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>f7402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>NtfsFolder</DisplayString>
<Value>102</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>f9402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>DfsNamespaceRoot</DisplayString>
<Value>103</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>fb402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>MsTeamsTeam</DisplayString>
<Value>401</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>fd402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>MsTeamsChannel</DisplayString>
<Value>402</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>ff402d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>MsTeamsFolder</DisplayString>
<Value>403</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>01412d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>ActiveDirectoryGroup</DisplayString>
<Value>501</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>03412d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>ExchangeSharedMailbox</DisplayString>
<Value>601</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification>
<ID>05412d06-bd2b-f111-2986-00155d320605</ID>
<DisplayString>ExchangeDistributionGroup</DisplayString>
<Value>602</Value>
<Hidden>0</Hidden>
</C4IT_LIAMDataAreaClassification>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fb402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fc402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Team</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fb402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fc402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Team</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fd402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fe402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Channel</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fb402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fc402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Team</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fd402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fe402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Channel</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>ff402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>00412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fb402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fc402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Team</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fd402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fe402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Channel</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>ff402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>00412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>01412d06-bd2b-f111-2986-00155d320605</Owner>
<ID>02412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>ActiveDirectory Group</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fb402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fc402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Team</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fd402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fe402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Channel</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>ff402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>00412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>01412d06-bd2b-f111-2986-00155d320605</Owner>
<ID>02412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>ActiveDirectory Group</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>03412d06-bd2b-f111-2986-00155d320605</Owner>
<ID>04412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Exchange SharedMailbox</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f1402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f2402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Server Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f3402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f4402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Unknown</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f5402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f6402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Share</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f7402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>f8402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Ntfs Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>f9402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fa402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Dfs Namespace Root</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fb402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fc402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Team</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>fd402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>fe402d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Channel</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>ff402d06-bd2b-f111-2986-00155d320605</Owner>
<ID>00412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>MsTeams Folder</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>01412d06-bd2b-f111-2986-00155d320605</Owner>
<ID>02412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>ActiveDirectory Group</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>03412d06-bd2b-f111-2986-00155d320605</Owner>
<ID>04412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Exchange SharedMailbox</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
<C4IT_LIAMDataAreaClassification-CI>
<Owner>05412d06-bd2b-f111-2986-00155d320605</Owner>
<ID>06412d06-bd2b-f111-2986-00155d320605</ID>
<LCID>7</LCID>
<DisplayString>Exchange DistributionGroup</DisplayString>
</C4IT_LIAMDataAreaClassification-CI>
</NewDataSet>

View File

@@ -0,0 +1,221 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<NewDataSet>
<BasicSchemaObjectClass>
<ID>dc38719c-6317-ea11-4881-000c2980fd94</ID>
<Name>C4IT_DataAreaClassBase</Name>
<IsSchemaObject>0</IsSchemaObject>
<Schema-MetaInfo>
<Name>DisplayExpression</Name>
<Value>DisplayName</Value>
</Schema-MetaInfo>
<DisplayName>Data Area Class Base</DisplayName>
<BasicSchemaObjectClass-CI>
<LCID>7</LCID>
<DisplayName>C4IT - LIAM - Data Area Class Base</DisplayName>
</BasicSchemaObjectClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<ClassType>3</ClassType>
<DisableHistory>1</DisableHistory>
<BasicSchemaAttributeClass>
<ID>a05bf2c5-6317-ea11-4881-000c2980fd94</ID>
<Name>technicalName</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Technical Name</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Technischer Name</DisplayName>
</BasicSchemaAttributeClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>0</ValueType>
<AttributeLength>500</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>defe7e43-bd2b-f111-2986-00155d320605</ID>
<Name>C4IT_Classification</Name>
<IsSchemaObject>0</IsSchemaObject>
<Description />
<DisplayName>Klassifikation</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<Description />
<DisplayName>Classification</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>2</ValueType>
<AttributeLength>4</AttributeLength>
<PickupClass>72d6dc7b-bc2b-f111-2986-00155d320605</PickupClass>
<PickupAttribute>Value</PickupAttribute>
<DefaultValue>0</DefaultValue>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>667d9968-8149-ea11-4981-000c2980fd94</ID>
<Name>level</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Level</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Level</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>2</ValueType>
<AttributeLength>0</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>0abc7ef9-601a-ea11-4881-000c2980fd94</ID>
<Name>ImportDate</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Import Date</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Importdatum</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>3</ValueType>
<AttributeLength>0</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>9a5bf2c5-6317-ea11-4881-000c2980fd94</ID>
<Name>displayname</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Displayname</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Anzeigename</DisplayName>
</BasicSchemaAttributeClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>0</ValueType>
<AttributeLength>500</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>9d5bf2c5-6317-ea11-4881-000c2980fd94</ID>
<Name>description</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Description</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Beschreibung</DisplayName>
</BasicSchemaAttributeClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>8</ValueType>
<AttributeLength>0</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>e43190f2-de03-f011-9484-00155d320629</ID>
<Name>isHiddenService</Name>
<IsSchemaObject>0</IsSchemaObject>
<Description />
<DisplayName>Is Hidden Service</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<Description />
<DisplayName>Is Hidden Service</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>0</AllowNull>
<ValueType>9</ValueType>
<AttributeLength>1</AttributeLength>
<DefaultValue>0</DefaultValue>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>36bb15cb-6517-ea11-4881-000c2980fd94</ID>
<Name>targetType</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Target Type</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Zieltyp</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>2</ValueType>
<AttributeLength>0</AttributeLength>
<PickupClass>709c986b-6517-ea11-4881-000c2980fd94</PickupClass>
<PickupAttribute>Value</PickupAttribute>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>043b6b40-0318-ea11-4881-000c2980fd94</ID>
<Name>uniqueID</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>uniqueID</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>uniqueID</DisplayName>
</BasicSchemaAttributeClass-CI>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>0</ValueType>
<AttributeLength>500</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>a92f0d2d-0c4c-ea11-4981-000c2980fd94</ID>
<Name>ConfigurationID</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>ConfigurationID</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>ConfigurationID</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>1</ValueType>
<AttributeLength>0</AttributeLength>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>a68f3f50-7e6f-ef11-7984-00155d320616</ID>
<Name>C4IT_ManagedManually</Name>
<IsSchemaObject>0</IsSchemaObject>
<Description />
<DisplayName>Managed Manually</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<Description />
<DisplayName>Manuell verwaltet</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>0</AllowNull>
<ValueType>9</ValueType>
<AttributeLength>1</AttributeLength>
<DefaultValue>0</DefaultValue>
</BasicSchemaAttributeClass>
<BasicSchemaAttributeClass>
<ID>0dbc7ef9-601a-ea11-4881-000c2980fd94</ID>
<Name>CreationTime</Name>
<IsSchemaObject>0</IsSchemaObject>
<DisplayName>Creation Time</DisplayName>
<BasicSchemaAttributeClass-CI>
<LCID>7</LCID>
<DisplayName>Erstelldatum</DisplayName>
</BasicSchemaAttributeClass-CI>
<DisableHistory>1</DisableHistory>
<ProtectionLevel>4</ProtectionLevel>
<DataProtectionIgnored>0</DataProtectionIgnored>
<AllowNull>1</AllowNull>
<ValueType>3</ValueType>
<AttributeLength>0</AttributeLength>
</BasicSchemaAttributeClass>
</BasicSchemaObjectClass>
</NewDataSet>

View File

@@ -0,0 +1,66 @@
<NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="C4IT_Liam_ConfigClassBase">
<xs:complexType>
<xs:sequence>
<xs:element name="encryptionKey" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="100" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="liamEngine" type="xs:base64Binary" minOccurs="0" />
<xs:element name="ID" msdata:DataType="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" />
<xs:element name="Name" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="100" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Version" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="100" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="UsedInTypeC4IT_LIAMConfigurationType" msdata:DataType="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="C4IT_LIAMConfigurationType">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" msdata:DataType="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//C4IT_Liam_ConfigClassBase" />
<xs:field xpath="ID" />
</xs:unique>
<xs:unique name="C4IT_LIAMConfigurationType_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//C4IT_LIAMConfigurationType" />
<xs:field xpath="ID" />
</xs:unique>
</xs:element>
</xs:schema>
<C4IT_Liam_ConfigClassBase>
<liamEngine></liamEngine>
<ID>d033bf66-6c23-eb11-5481-000c299eb325</ID>
<Name>LIAM</Name>
<Version>3.0.2.0</Version>
<encryptionKey></encryptionKey>
<UsedInTypeC4IT_LIAMConfigurationType>41205ba4-5f49-ca19-488a-08d885904833</UsedInTypeC4IT_LIAMConfigurationType>
</C4IT_Liam_ConfigClassBase>
<C4IT_LIAMConfigurationType>
<ID>41205ba4-5f49-ca19-488a-08d885904833</ID>
</C4IT_LIAMConfigurationType>
</NewDataSet>

View File

@@ -0,0 +1,402 @@
<NewDataSet>
<PDRDataQueryType>
<ID>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</ID>
</PDRDataQueryType>
<PDRDataQueryClassColumn>
<ID>22b86d74-932c-4303-a9e4-0daec33d3dda</ID>
<Expression>targetType</Expression>
<Name>targetType</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Target Type</Title>
<Sorting>0</Sorting>
<Position>25</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>200</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>432acf59-d701-41a1-971a-0de9679a62f2</ID>
<Expression>Owner</Expression>
<Name>Owner</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Owner</Title>
<Sorting>0</Sorting>
<Position>30</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>125</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>1</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>4bfb3d37-581b-40a8-9f05-1a01a07b1404</ID>
<Expression>T(SPSCommonClassBase).Validity</Expression>
<Name>state</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>State</Title>
<Sorting>0</Sorting>
<Position>90</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>150</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>f8572a61-d1a7-46ef-adab-327f8a0148ce</ID>
<Expression>level</Expression>
<Name>level</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Level</Title>
<Sorting>0</Sorting>
<Position>70</Position>
<Alignment>2</Alignment>
<Visibility>0</Visibility>
<Width>75</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>90671323-c941-4a9d-9e8e-328abedf3e04</ID>
<Expression>Read</Expression>
<Name>Read</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Read</Title>
<Sorting>0</Sorting>
<Position>40</Position>
<Alignment>0</Alignment>
<Width>125</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>1</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>dfae2238-9ac8-4d4f-a21a-40bc6ca5e125</ID>
<Expression>displayname</Expression>
<Name>displayname</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Display Name</Title>
<Sorting>0</Sorting>
<Position>10</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>150</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>4738e80c-da40-4e37-995b-5d7c7ff76305</ID>
<Expression>technicalName</Expression>
<Name>technicalName</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Technical Name</Title>
<Sorting>0</Sorting>
<Position>15</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>150</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>3806abba-25bc-455b-97a4-6974f3c448a5</ID>
<Expression>Write</Expression>
<Name>Write</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Write</Title>
<Sorting>0</Sorting>
<Position>35</Position>
<Alignment>0</Alignment>
<Width>125</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>1</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>4d9e7fd4-e98e-4111-876e-86355db545f5</ID>
<Expression>CreationTime</Expression>
<Name>CreationTime</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Creation Time</Title>
<Sorting>0</Sorting>
<Position>65</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>100</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>1</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>8e3fd586-3a37-4893-997d-97831ebbd629</ID>
<Expression>DataAreaConfiguration</Expression>
<Name>DataAreaConfiguration</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Sorting>0</Sorting>
<Position>100</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>200</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>1</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>2881b59c-8998-4cd0-ba64-9eabb6b0d57e</ID>
<Expression>uniqueID</Expression>
<Name>uniqueID</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Unique Id</Title>
<Sorting>0</Sorting>
<Position>55</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>150</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>1</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>c0ca3a8c-63ba-4364-9250-d1732c2b2e7f</ID>
<Expression>ImportDate</Expression>
<Name>ImportDate</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Import Date</Title>
<Sorting>0</Sorting>
<Position>60</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>100</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>d729f3d2-2f50-479d-8b68-e7f4cc19a65e</ID>
<Expression>parent</Expression>
<Name>parent</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Parent</Title>
<Sorting>0</Sorting>
<Position>50</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>125</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>8898b212-c592-4a59-901a-f0ddfd67dbf3</ID>
<Expression>C4IT_Classification</Expression>
<Name>C4IT_Classification</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>Classification</Title>
<Sorting>0</Sorting>
<Position>27</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>120</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>0</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn>
<ID>372fc4e0-130a-4a41-bc55-f55c423e8436</ID>
<Expression>cast(configurationid,string)</Expression>
<Name>configid</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsSystem>0</IsSystem>
<Title>ConfigID</Title>
<Sorting>0</Sorting>
<Position>80</Position>
<Alignment>0</Alignment>
<Visibility>0</Visibility>
<Width>150</Width>
<ShowFilter>0</ShowFilter>
<DisplayType>1</DisplayType>
<TitleType>0</TitleType>
<DisplayImage>0</DisplayImage>
<SearchDisplayType>0</SearchDisplayType>
<IsKeyword>0</IsKeyword>
</PDRDataQueryClassColumn>
<PDRDataQueryClassColumn-CI>
<ID>3e491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>22b86d74-932c-4303-a9e4-0daec33d3dda</Owner>
<LCID>7</LCID>
<Title>Zieltyp</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>3f491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>432acf59-d701-41a1-971a-0de9679a62f2</Owner>
<LCID>7</LCID>
<Title>Owner</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>0ffdec1c-cd8a-ea11-5b83-000c2981464e</ID>
<Owner>4bfb3d37-581b-40a8-9f05-1a01a07b1404</Owner>
<LCID>7</LCID>
<Title>Status</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>95463f4f-f94b-ea11-4981-000c2980fd94</ID>
<Owner>f8572a61-d1a7-46ef-adab-327f8a0148ce</Owner>
<LCID>7</LCID>
<Title>Ebene</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>41491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>90671323-c941-4a9d-9e8e-328abedf3e04</Owner>
<LCID>7</LCID>
<Title>Read</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>3b491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>dfae2238-9ac8-4d4f-a21a-40bc6ca5e125</Owner>
<LCID>7</LCID>
<Title>Anzeigename</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>3c491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>4738e80c-da40-4e37-995b-5d7c7ff76305</Owner>
<LCID>7</LCID>
<Title>Technischer Name</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>40491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>3806abba-25bc-455b-97a4-6974f3c448a5</Owner>
<LCID>7</LCID>
<Title>Write</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>94463f4f-f94b-ea11-4981-000c2980fd94</ID>
<Owner>4d9e7fd4-e98e-4111-876e-86355db545f5</Owner>
<LCID>7</LCID>
<Title>Erstelldatum</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>0cd8153d-708e-ec11-5a84-00155d300101</ID>
<Owner>8e3fd586-3a37-4893-997d-97831ebbd629</Owner>
<LCID>7</LCID>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>92463f4f-f94b-ea11-4981-000c2980fd94</ID>
<Owner>2881b59c-8998-4cd0-ba64-9eabb6b0d57e</Owner>
<LCID>7</LCID>
<Title>uniqueD</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>93463f4f-f94b-ea11-4981-000c2980fd94</ID>
<Owner>c0ca3a8c-63ba-4364-9250-d1732c2b2e7f</Owner>
<LCID>7</LCID>
<Title>Importdatum</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>91463f4f-f94b-ea11-4981-000c2980fd94</ID>
<Owner>d729f3d2-2f50-479d-8b68-e7f4cc19a65e</Owner>
<LCID>7</LCID>
<Title>Übergeordnet</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>120e3cb6-bd2b-f111-2986-00155d320605</ID>
<Owner>8898b212-c592-4a59-901a-f0ddfd67dbf3</Owner>
<LCID>7</LCID>
<Title>Klassifikation</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassColumn-CI>
<ID>8da15e45-0d4c-ea11-4981-000c2980fd94</ID>
<Owner>372fc4e0-130a-4a41-bc55-f55c423e8436</Owner>
<LCID>7</LCID>
<Title>ConfigID</Title>
</PDRDataQueryClassColumn-CI>
<PDRDataQueryClassBase>
<ID>2e491456-6617-ea11-4881-000c2980fd94</ID>
<SchemaClassName>C4IT_DataAreaClassBase</SchemaClassName>
<Name>C4IT LIAM - Data Area</Name>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
<IsDefault>1</IsDefault>
<ImplementationType>d</ImplementationType>
<AllowCache>0</AllowCache>
<CultureSensitive>0</CultureSensitive>
<CacheInterval>60</CacheInterval>
<Tag>2df140c9-a676-4377-ae87-e004bd8db9e7</Tag>
<Priority>0</Priority>
</PDRDataQueryClassBase>
<PDRDataQueryClassBase-CI>
<ID>3a491456-6617-ea11-4881-000c2980fd94</ID>
<Owner>2e491456-6617-ea11-4881-000c2980fd94</Owner>
<LCID>7</LCID>
</PDRDataQueryClassBase-CI>
<PDRAudienceClass>
<ID>cdaf5ef9-e1a4-4afe-819b-708430ec9721</ID>
<Unrestricted>1</Unrestricted>
<Configured>1</Configured>
<ConsiderRelated>0</ConsiderRelated>
<StrictAdminControl>1</StrictAdminControl>
<UsedInTypePDRDataQueryType>2b3d0515-1e4a-c42d-ea1d-08d7798a331c</UsedInTypePDRDataQueryType>
</PDRAudienceClass>
</NewDataSet>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,254 @@
<NewDataSet>
<GDIEImportType>
<ID>da44b12e-d036-a669-debe-76da2b0ce41d</ID>
</GDIEImportType>
<GDIEImportClassAction>
<ID>b1061b84-8449-ea11-4981-000c2980fd94</ID>
<DestClass>f7816b37-6417-ea11-4881-000c2980fd94</DestClass>
<Insert>1</Insert>
<IsType>1</IsType>
<Update>1</Update>
<Delete>0</Delete>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
</GDIEImportClassAction>
<GDIEImportClassBase>
<ID>c9061b84-8449-ea11-4981-000c2980fd94</ID>
<Created>2020-02-07T08:33:29.93Z</Created>
<LastAccessed>2026-03-29T22:22:42.173Z</LastAccessed>
<Name>C4IT - LIAM - DataArea (Import_Update)</Name>
<DestTypeID>f7816b37-6417-ea11-4881-000c2980fd94</DestTypeID>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<IsComplexTable>0</IsComplexTable>
<LastResult>1</LastResult>
<IsSimpleMode>0</IsSimpleMode>
<TimeZoneInfoId>UTC</TimeZoneInfoId>
</GDIEImportClassBase>
<GDIEImportClassBase-CI>
<ID>73990b01-b480-ea11-5481-000c299eb325</ID>
<Owner>c9061b84-8449-ea11-4981-000c2980fd94</Owner>
<LCID>7</LCID>
<Name>C4IT - LIAM - DataArea (Import_Update)</Name>
</GDIEImportClassBase-CI>
<SPSCommonClassBase>
<ID>ca061b84-8449-ea11-4981-000c2980fd94</ID>
<UsedInType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInType>
<TypeID>5842d0e4-4625-4e58-a700-23a3dfaa8293</TypeID>
<CostCenter>816361e3-13e6-4b44-96a9-fb44c63a8e36</CostCenter>
<Location>cf060d4d-5c47-462f-b5d1-7df6c865fd91</Location>
<OU>4df735f2-b4bc-4ce8-92ee-60f40fcf5653</OU>
<Security-OU>4df735f2-b4bc-4ce8-92ee-60f40fcf5653</Security-OU>
<Security-Location>cf060d4d-5c47-462f-b5d1-7df6c865fd91</Security-Location>
<Security-CostCenter>816361e3-13e6-4b44-96a9-fb44c63a8e36</Security-CostCenter>
<Category>3</Category>
</SPSCommonClassBase>
<GDIEImportClassSourceObject>
<ID>a5061b84-8449-ea11-4981-000c2980fd94</ID>
<ObjectType>3</ObjectType>
<Alias>res</Alias>
<IsMainObject>1</IsMainObject>
<Expression>/objects/object</Expression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<IsAttribCentric>0</IsAttribCentric>
</GDIEImportClassSourceObject>
<GDIEImportClassMapRule>
<ID>a7061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>DisplayName</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>displayname</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>a8061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>TechnicalName</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>technicalName</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>aa061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>Owner</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<RelatedAttribName>uniqueID</RelatedAttribName>
<DestAttribName>Owner</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>ab061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>Write</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<RelatedAttribName>uniqueID</RelatedAttribName>
<DestAttribName>Write</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>ac061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>Read</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<RelatedAttribName>uniqueID</RelatedAttribName>
<DestAttribName>Read</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>ad061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>CreatedDate</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>CreationTime</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>ae061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>Level</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>level</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>af061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>TargetType</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<RelatedAttribName>Value</RelatedAttribName>
<DestAttribName>targetType</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>b0061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>ImportDate</DestAttribName>
<RuleType>2</RuleType>
<Order>0</Order>
<TransformExpression>GETDATE()</TransformExpression>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>01e4bada-0c4c-ea11-4981-000c2980fd94</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>ConfigurationId</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>ConfigurationID</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>c422900a-7c42-ec11-5b8c-00155d300101</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>UID</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>1</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>uniqueID</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>563a3205-c047-ec11-9984-00155d300101</ID>
<MatchExpression>Production.UsedInTypeC4IT_GCC_DataAreaCollectorType</MatchExpression>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>ConfigurationId</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>1</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<DestAttribName>DataAreaConfiguration</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassMapRule>
<ID>5a2e298b-bd2b-f111-2986-00155d320605</ID>
<SourceObject>a5061b84-8449-ea11-4981-000c2980fd94</SourceObject>
<SourceColumnName>DataAreaTypeId</SourceColumnName>
<IsClassMatch>0</IsClassMatch>
<IsTypeMatch>0</IsTypeMatch>
<DestClass>dc38719c-6317-ea11-4881-000c2980fd94</DestClass>
<IsStaticColumn>0</IsStaticColumn>
<IsMatchExpression>0</IsMatchExpression>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<RelatedAttribName>Value</RelatedAttribName>
<DestAttribName>C4IT_Classification</DestAttribName>
<RuleType>0</RuleType>
<Order>0</Order>
</GDIEImportClassMapRule>
<GDIEImportClassSourceFile>
<ID>a4061b84-8449-ea11-4981-000c2980fd94</ID>
<UrlType>2</UrlType>
<FileUrl>..\Messages\Data\DataAreacollector\LastResult\C4IT_LIAM_DataArea_FS.xml</FileUrl>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
</GDIEImportClassSourceFile>
<GDIEImportClassDatabase>
<ID>c8061b84-8449-ea11-4981-000c2980fd94</ID>
<SourceType>4</SourceType>
<DataCulture>de-DE</DataCulture>
<UsedInTypeGDIEImportType>da44b12e-d036-a669-debe-76da2b0ce41d</UsedInTypeGDIEImportType>
<UseApplicationDb>0</UseApplicationDb>
</GDIEImportClassDatabase>
</NewDataSet>

View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<C4IT-M42-SchemaInstaller>
<Variables>
<!-- <Variable Name="USE_WF_Worker" Type="SQL" Default="0">select case when ( SELECT count([Version]) FROM [SchemaProductVersion] where [Version] > '10.1') >=1 and (select top 1 c.WorkflowEngineType from SPSGlobalConfigurationClassBase c) = 1 then 1 else 0 end as useWFWorker</Variable> -->
<!-- <Variable Name="WF_STATE" Type="SQL" Default="0">select case when ( SELECT count([Version]) FROM [SchemaProductVersion] where [Version] > '10.1') >=1 and (select top 1 c.WorkflowEngineType from SPSGlobalConfigurationClassBase c) = 1 then 10102 else 10101 end as wfstate</Variable> -->
</Variables>
<UpdateInfo>
<!-- objects, which will not be removed within an update installation -->
<NoRemovement Type="PDRNavigationItemType" ID="8702a16c-cdc6-c810-b02c-08d5cb9d6f63" Ignore="true"/> <!-- C4IT root navigation object in administration -->
<NoRemovement Type="PDRNavigationItemType" ID="125d587d-f51e-cfd7-ca63-08d653beaaef" Ignore="true"/> <!-- C4IT root navigation object in assets -->
<NoRemovement Type="PDRNavigationItemType" ID="a33503d6-160c-c2fb-9656-08d6667e6094" Ignore="true"/> <!-- C4IT root navigation object in service catalog -->
<NoRemovement Type="PDRNavigationItemType" ID="72aa66c3-61cd-ccf4-57e1-08d65f6d24bb" Ignore="true"/> <!-- C4IT root navigation object in service desk -->
<NoRemovement Type="PLSLXamlComponentType" ID="*"/> <!-- all workflows -->
<NoRemovement Type="PLSLWorkflowConfigurationType" ID="*"/> <!-- all workflows Configurations -->
<NoRemovement Type="PLBEActivationType" ID="*"/> <!-- all engine activations -->
<NoRemovement Type="PLSLServiceTypeWebAPI" ID="*"/> <!-- all web services -->
<NoRemovement Type="PLSLWebServiceOperationType" ID="*"/> <!-- all web service operations -->
<NoRemovement Type="SPSArticleTypeService" ID="*"/> <!-- all services -->
<NoRemovement Type="SVCServiceTypeBundle" ID="*"/> <!-- all service bundles -->
<NoRemovement Type="SVCServiceTypeConfigGroup" ID="*"/> <!-- all service groups -->
<NoRemovement Type="SPSArticleCategoryType" ID="*"/> <!-- all article categories -->
<NoRemovement Type="SVCServiceProvisioningTypeCreateWFChange" ID="*"/> <!-- all 'Provisioning - Create WF Change' objects -->
<NoRemovement Type="SPSActivityTemplateClassBase" ID="*"/> <!-- all activity templates -->
<NoRemovement Type="PLSLWorkflowAssemblyLibraryType" ID="*"/> <!-- all activity assemblies -->
</UpdateInfo>
<Removements>
<!-- removement of unnecessary, disturbing content -->
<Remove>Data/SPSContentClassObjectDialogTab/PublishingUser</Remove>
<Remove>NewDataSet/PDRContentWidgetTemplateView/Owner</Remove>
<Remove>NewDataSet/PDRContentWidgetTemplateCustom/Owner</Remove>
<Remove>NewDataSet/PDRContentWidgetTemplateClassViewCustom/Owner</Remove>
<Remove>NewDataSet/PLSLComponentClassBase/CreatedBy</Remove>
<Remove>NewDataSet/PLSLComponentClassBase/LockedBy</Remove>
<Remove>NewDataSet/PLSLXamlComponentClassVersion/CreatedBy</Remove>
<Remove>NewDataSet/PLSLXamlComponentClassVersion/PublishedBy</Remove>
<Remove>NewDataSet/PLSLXamlComponentClassVersion/PublishedDate</Remove>
<Remove>NewDataSet/GDIEImportClassBase/LastResult</Remove>
<Remove>NewDataSet/GDIEImportClassBase/LastAccessed</Remove>
<Remove>NewDataSet/SchemaRelation-PLSLXamlComponentClassVersion2PLSLComponentClassBase</Remove>
<Remove>NewDataSet/CUSTLM42WizardChangeObjectValueClassBase</Remove>
<!-- version dependend corrections -->
<Remove>NewDataSet/PDRContentWidgetClassBase/Tag</Remove>
<Remove>NewDataSet/PDRDataQueryClassBase/Tag</Remove>
<Remove>NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element/xs:complexType/xs:sequence/xs:element[@name='Tag']</Remove>
<Remove>NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='SPSAssetClassBase']/xs:complexType/xs:sequence/xs:element[@name='UsedInTypeSPSAssetTypeLicenseOEM']</Remove>
<Remove>NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='SPSAssetClassOrder']/xs:complexType/xs:sequence/xs:element[@name='UsedInTypeSPSAssetTypeLicenseOEM']</Remove>
<Remove>NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='SPSAssetClassBase']/xs:complexType/xs:sequence/xs:element[@name='UsedInTypeSPSAssetTypeLicenseUpdate']</Remove>
<Remove>NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='SPSAssetClassOrder']/xs:complexType/xs:sequence/xs:element[@name='UsedInTypeSPSAssetTypeLicenseUpdate']</Remove>
<!-- Attributes only available in v10 -->
<Remove>
<VersionRange From="*.*.*.*" To="9.1.3.2754"/>
NewDataSet/PLSLXamlComponentClassBase/UseWorkflowWorker
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="9.1.3.2754"/>
NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='PLSLXamlComponentClassBase']/xs:complexType/xs:sequence/xs:element[@name='UseWorkflowWorker']
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="9.1.3.2754"/>
NewDataSet/PLSLXamlComponentClassBase/AllowCloudWorker
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="9.1.3.2754"/>
NewDataSet/PLSLXamlComponentClassBase/MonitoringLevel
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="9.1.3.2754"/>
NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='PLSLXamlComponentClassBase']/xs:complexType/xs:sequence/xs:element[@name='AllowCloudWorker']
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="9.1.3.2754"/>
NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element[@name='PLSLXamlComponentClassBase']/xs:complexType/xs:sequence/xs:element[@name='MonitoringLevel']
</Remove>
<Remove>
<VersionRange From="9.0.3.0" To="*.*.*.*"/>
NewDataSet/PDRContentWidgetTemplateClassViewCustom/OriginalBase
</Remove>
<Remove>
<VersionRange From="9.0.3.0" To="*.*.*.*"/>
NewDataSet/xs:schema/xs:element/xs:complexType/xs:choice/xs:element/xs:complexType/xs:sequence/xs:element[@name='OriginalBase']
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="12.0.0.*"/>
//PDRAudienceClass[UsedInTypePDRDataQueryType] | //SchemaRelation-PDRAudienceClass2SPSUserClassBase[Users = //PDRAudienceClass[UsedInTypePDRDataQueryType]/ID] | //SchemaRelation-PDRAudienceClass2SPSSecurityClassRole[Roles = //PDRAudienceClass[UsedInTypePDRDataQueryType]/ID] | //SchemaRelation-PDRAudienceClass2SPSOrgUnitClassBase[OUs = //PDRAudienceClass[UsedInTypePDRDataQueryType]/ID] | //SchemaRelation-PDRAudienceClass2SPSLocationClassBase[Locations = //PDRAudienceClass[UsedInTypePDRDataQueryType]/ID] | //SchemaRelation-PDRAudienceClass2PDRAudienceClass[ApplyTo = //PDRAudienceClass[UsedInTypePDRDataQueryType]/ID]
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="12.0.0.*"/>
//PDRDataQueryClassBase/Priority
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="12.0.0.*"/>
//xs:element[@name='PDRDataQueryClassBase']//xs:element[@name='Priority']
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="12.0.0.*"/>
//xs:element[@name='PDRAudienceClass']//xs:element[@name='UsedInTypePDRDataQueryType']
</Remove>
<Remove>
<VersionRange From="*.*.*.*" To="12.0.1.1123"/>
NewDataSet/PDRActionClassBase/ReloadPageOnSuccess
</Remove>
<!-- removement of object ids -->
<Remove>NewDataSet/SPSArticleClassBase/ArticleID</Remove>
<Remove>NewDataSet/SPSOrgUnitClassBase/ObjectId</Remove>
<Remove>NewDataSet/SPSCostCenterClassBase/ObjectId</Remove>
<Remove>NewDataSet/SPSLocationClassBase/ObjectId</Remove>
<Remove>NewDataSet/SPSSupplierClassBase/ObjectId</Remove>
<Remove>NewDataSet/SPSStockKeepingUnitClassBase/ObjectId</Remove>
<Remove>NewDataSet/SPSAssetClassBase/ObjectId</Remove>
<Remove>NewDataSet/SVCServiceProvisioningClassBaseCreateWFChange/ConfigurationID</Remove>
<Remove>NewDataSet/SPSActivityTemplateClassBase/ObjectId</Remove>
<Remove>NewDataSet/SPSArticleCategoryClassBase/ObjectId</Remove>
<!-- set all new installed workflows to state 'new' (10101) -->
<Replace Value="1">/NewDataSet/PLSLXamlComponentClassBase/UseWorkflowWorker</Replace>
<Replace Value="10102">NewDataSet/SPSCommonClassBase[TypeID='b11c6ae9-3d91-e111-489e-6cf049029115']/State</Replace>
<!-- set all new installed compliance rules to state 'inactive' (2036) -->
<Replace Value="2036">NewDataSet/SPSCommonClassBase[TypeID='4083df94-6f60-4cf9-a80c-11522313eebe']/State</Replace>
<Replace Value="%M42ServerInfo_SqlDatabase%">/NewDataSet/GDIEImportClassDatabase/Database</Replace>
<Replace Value="%M42ServerInfo_SqlServer%">/NewDataSet/GDIEImportClassDatabase/Server</Replace>
<!-- set all new installed workflow monitoring level to 0 -->
<Replace Value="0">NewDataSet/PLSLXamlComponentClassBase/MonitoringLevel</Replace>
<!-- set all new installed workflow debug mode to 0 -->
<Replace Value="0">NewDataSet/PLSLXamlComponentClassBase/DebugMode</Replace>
</Removements>
</C4IT-M42-SchemaInstaller>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<C4IT-M42-SchemaInstaller>
<Removements>
<!-- replacements for ownership assignments (replaces all ownerships with the global nodes) -->
<Replace Value="cf060d4d-5c47-462f-b5d1-7df6c865fd91">NewDataSet/SPSCommonClassBase/Location</Replace>
<Replace Value="cf060d4d-5c47-462f-b5d1-7df6c865fd91">NewDataSet/SPSCommonClassBase/Security-Location</Replace>
<Replace Value="4df735f2-b4bc-4ce8-92ee-60f40fcf5653">NewDataSet/SPSCommonClassBase/OU</Replace>
<Replace Value="4df735f2-b4bc-4ce8-92ee-60f40fcf5653">NewDataSet/SPSCommonClassBase/Security-OU</Replace>
<Replace Value="816361e3-13e6-4b44-96a9-fb44c63a8e36">NewDataSet/SPSCommonClassBase/CostCenter</Replace>
<Replace Value="816361e3-13e6-4b44-96a9-fb44c63a8e36">NewDataSet/SPSCommonClassBase/Security-CostCenter</Replace>
<!-- same for root node "Data": replacements for ownership assignments (replaces all ownerships with the global nodes) -->
<Replace Value="cf060d4d-5c47-462f-b5d1-7df6c865fd91">Data/SPSCommonClassBase/Location</Replace>
<Replace Value="cf060d4d-5c47-462f-b5d1-7df6c865fd91">Data/SPSCommonClassBase/Security-Location</Replace>
<Replace Value="4df735f2-b4bc-4ce8-92ee-60f40fcf5653">Data/SPSCommonClassBase/OU</Replace>
<Replace Value="4df735f2-b4bc-4ce8-92ee-60f40fcf5653">Data/SPSCommonClassBase/Security-OU</Replace>
<Replace Value="816361e3-13e6-4b44-96a9-fb44c63a8e36">Data/SPSCommonClassBase/CostCenter</Replace>
<Replace Value="816361e3-13e6-4b44-96a9-fb44c63a8e36">Data/SPSCommonClassBase/Security-CostCenter</Replace>
</Removements>
</C4IT-M42-SchemaInstaller>

Binary file not shown.

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
</configuration>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<C4IT-M42-SchemaInstaller Product="C4IT LIAM" Version="3.0.2.0">
<Include>C4IT-M42-SchemaInstaller-Global.xml</Include>
<Include>C4IT-M42-SchemaInstaller-OwnershipCleanup.xml</Include>
<SupportedVersions>
<Version>9.1.2</Version>
<Version>9.1.3</Version>
</SupportedVersions>
<Variables>
<Variable Name="ENCRYPTION_KEY" Type="XMLFILE" Default="">
<FilePath>@M42INSTALLATIONPATH@bin\securityCryptographyConfiguration.config</FilePath>
<XPath>/securityCryptographyConfiguration/databaseEncryption</XPath>
<XAttribute>key</XAttribute>
</Variable>
</Variables>
<UpdateInfo>
<NoRemovement Type="C4IT_SQValidatorPasswordType_Pickup" ID="*"/>
<NoRemovement Type="C4IT_SecurityQuestion_Pickup" ID="*"/>
<NoRemovement Type="C4IT_DurationPeriodPickupType" ID="*"/>
<NoRemovement Type="CTMAppointmentPickupClassType" ID="*"/>
<NoRemovement Type="SPSGenericConnectorType" ID="*"/>
<NoRemovement Type="C4IT_SCPlus_limitedServiceType" ID="66a18f89-ff73-cc79-b9a8-08d73298dcfa"/>
<NoRemovement Type="C4IT_SCPlusConfigurationType" ID="*"/>
<NoRemovement Type="C4IT_LIAMConfigurationType" ID="*"/>
<NoRemovement Type="C4IT_LIAMNamingConventionType" ID="*"/>
<NoRemovement Type="C4IT_GCC_DataAreaCollectorType" ID="*"/>
<NoRemovement Type="SVCServiceProvisioningTypeAssignADGroup" ID="55ffd91e-539f-c08d-4565-08d7385290d1"/>
<NoRemovement Type="PLSCTypeRule" ID="*"/>
<VersionSqlGet>
SELECT version FROM [C4IT_Liam_ConfigClassBase]
WHERE ID='d033bf66-6c23-eb11-5481-000c299eb325'
</VersionSqlGet>
<VersionSqlSet>
UPDATE [C4IT_Liam_ConfigClassBase] SET version=@version
WHERE ID='d033bf66-6c23-eb11-5481-000c299eb325'
</VersionSqlSet>
</UpdateInfo>
<Removements>
<Replace Value="%ENCRYPTION_KEY%">NewDataSet/C4IT_Liam_ConfigClassBase/encryptionKey</Replace>
</Removements>
</C4IT-M42-SchemaInstaller>

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,3 @@
@echo off
cd /D %~dp0
start ..\C4IT-M42-SchemaInstaller.exe develop

View File

@@ -0,0 +1,3 @@
@echo off
cd /D %~dp0
start ..\C4IT-M42-SchemaInstaller.exe enhanced

Binary file not shown.

View File

@@ -0,0 +1,9 @@
[MRU List]
MRU1=C:\Users\dm134\AppData\Local\Temp\tmpDF2B.tmp.exe
MRU2=C:\Users\dm134\AppData\Local\Temp\tmpDE6D.tmp.exe
MRU3=C:\Users\dm134\AppData\Local\Temp\tmpE01D.tmp.exe
MRU4=C:\Users\dm134\AppData\Local\Temp\tmpDE64.tmp.exe
MRU5=C:\Users\dm134\AppData\Local\Temp\tmpDEA2.tmp.exe
MRU6=C:\Users\dm134\AppData\Local\Temp\tmpDDE4.tmp.exe
MRU7=C:\Users\dm134\AppData\Local\Temp\tmpB1CE.tmp.exe
MRU8=C:\Users\dm134\AppData\Local\Temp\tmpB064.tmp.exe

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

View File

@@ -55,6 +55,10 @@ namespace C4IT.LIAM
public static Guid nftsModuleId = new Guid("77e213a1-6517-ea11-4881-000c2980fd94");
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
private const string AdditionalConfigurationTraverseBoundaryPathKey = "NtfsTraverseBoundaryPath";
private const string AdditionalConfigurationGroupNameSanitizeReplacementKey = "NtfsGroupNameSanitizeReplacement";
private const string AdditionalConfigurationPreserveAdGroupNameCaseKey = "PreserveNtfsAdGroupNameCase";
private const string AdditionalConfigurationAdDomainControllersKey = "NtfsAdDomainControllers";
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);
@@ -134,6 +138,7 @@ namespace C4IT.LIAM
var LI = new cNtfsLogonInfo()
{
Domain = Domain,
DomainControllers = GetAdditionalConfigurationValue(AdditionalConfigurationAdDomainControllersKey),
User = Credential?.Identification,
UserSecret = Credential?.Secret,
TargetNetworkName = RootPath,
@@ -977,6 +982,7 @@ namespace C4IT.LIAM
{
ConfigID = "manual",
domainName = this.Domain,
effectiveDomainController = activeDirectoryBase.EffectiveDomainController,
username = this.Credential.Identification,
password = new NetworkCredential("", this.Credential.Secret).SecurePassword,
baseFolder = this.RootPath,
@@ -996,8 +1002,14 @@ namespace C4IT.LIAM
groupDLTag = requiresDomainLocalTag ? GetRequiredCustomTag("Filesystem_GroupDomainLocalTag") : string.Empty,
groupGTag = GetRequiredCustomTag("Filesystem_GroupGlobalTag"),
CanManagePermissionsForPath = IsPermissionManagedFolderPath,
forceStrictAdGroupNames = IsAdditionalConfigurationEnabled("ForceStrictAdGroupNames")
CanManageTraversePermissionsForPath = IsTraversePermissionManagedPath,
forceStrictAdGroupNames = IsAdditionalConfigurationEnabled("ForceStrictAdGroupNames"),
groupNameSanitizeReplacement = GetAdditionalConfigurationValueOrDefault(
AdditionalConfigurationGroupNameSanitizeReplacementKey,
Helper.DefaultGroupNameSanitizeReplacement),
preserveAdGroupNameCase = IsAdditionalConfigurationEnabled(AdditionalConfigurationPreserveAdGroupNameCaseKey)
};
engine.traverseBoundaryPath = GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey);
foreach (var template in BuildSecurityGroupTemplates())
engine.templates.Add(template);
@@ -1018,6 +1030,28 @@ namespace C4IT.LIAM
|| rawValue.Equals("yes", StringComparison.OrdinalIgnoreCase);
}
private string GetAdditionalConfigurationValue(string key)
{
if (AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
return string.Empty;
if (!AdditionalConfiguration.TryGetValue(key, out var rawValue) || string.IsNullOrWhiteSpace(rawValue))
return string.Empty;
return rawValue.Trim();
}
private string GetAdditionalConfigurationValueOrDefault(string key, string defaultValue)
{
if (AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
return defaultValue;
if (!AdditionalConfiguration.TryGetValue(key, out var rawValue))
return defaultValue;
return rawValue == null ? string.Empty : rawValue.Trim();
}
public bool IsPermissionManagedFolderPath(string path)
{
return IsPermissionManagedPath(path, eNtfsPathKind.Folder);
@@ -1042,6 +1076,23 @@ namespace C4IT.LIAM
return IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule);
}
private bool IsTraversePermissionManagedPath(string path)
{
if (string.IsNullOrWhiteSpace(GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey)))
return IsPermissionManagedFolderPath(path);
var classification = ClassifyPath(path);
if (classification == null || classification.Kind == eNtfsPathKind.ServerRoot || classification.Kind == eNtfsPathKind.Unknown)
return false;
string matchingConfigurationKey;
string matchingRule;
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
return false;
return Directory.Exists(path);
}
private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds)
{
if (classification == null || supportedKinds == null || supportedKinds.Length == 0)
@@ -1053,11 +1104,24 @@ namespace C4IT.LIAM
private IEnumerable<IAM_SecurityGroupTemplate> BuildSecurityGroupTemplates()
{
var templates = new List<IAM_SecurityGroupTemplate>();
foreach (var namingConvention in NamingConventions ?? Enumerable.Empty<cLiamNamingConvention>())
var namingConventions = (NamingConventions ?? Enumerable.Empty<cLiamNamingConvention>()).ToList();
var hasStrategyMatchingTraverseConvention = namingConventions.Any(i =>
TryMapSecurityGroupType(i.AccessRole, out var securityGroupType)
&& securityGroupType == SecurityGroupType.Traverse
&& IsStrategyMatchingTraverseScope(i.Scope));
foreach (var namingConvention in namingConventions)
{
if (!TryMapSecurityGroupType(namingConvention.AccessRole, out var securityGroupType))
continue;
if (securityGroupType == SecurityGroupType.Traverse
&& hasStrategyMatchingTraverseConvention
&& !IsStrategyMatchingTraverseScope(namingConvention.Scope))
{
continue;
}
if (!TryMapGroupScope(namingConvention.Scope, securityGroupType, out var groupScope))
continue;
@@ -1097,6 +1161,12 @@ namespace C4IT.LIAM
private bool TryMapGroupScope(eLiamAccessRoleScopes scope, SecurityGroupType type, out GroupScope groupScope)
{
groupScope = GroupScope.Global;
if (type == SecurityGroupType.Traverse)
{
groupScope = GetStrategyTraverseGroupScope();
return true;
}
switch (scope)
{
case eLiamAccessRoleScopes.Global:
@@ -1106,17 +1176,30 @@ namespace C4IT.LIAM
groupScope = GroupScope.Local;
return true;
case eLiamAccessRoleScopes.Unknown:
if (type == SecurityGroupType.Traverse)
{
groupScope = this.GroupStrategy == eLiamGroupStrategies.Ntfs_AGDLP ? GroupScope.Local : GroupScope.Global;
return true;
}
return false;
default:
return false;
}
}
private GroupScope GetStrategyTraverseGroupScope()
{
return this.GroupStrategy == eLiamGroupStrategies.Ntfs_AGDLP
? GroupScope.Local
: GroupScope.Global;
}
private bool IsStrategyMatchingTraverseScope(eLiamAccessRoleScopes scope)
{
if (scope == eLiamAccessRoleScopes.Unknown)
return true;
var strategyScope = GetStrategyTraverseGroupScope();
return strategyScope == GroupScope.Local
? scope == eLiamAccessRoleScopes.DomainLocal
: scope == eLiamAccessRoleScopes.Global;
}
private string GetRequiredCustomTag(string key)
{
if (CustomTags.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value))
@@ -1267,72 +1350,110 @@ namespace C4IT.LIAM
var traverseNamingConvention = Provider.NamingConventions.First(i => i.AccessRole == eLiamAccessRoles.Traverse);
foreach (FileSystemAccessRule rule in ACLs)
{
if (rule.IdentityReference.Value == "S-1-1-0")
var aclSid = rule.IdentityReference.Value;
if (aclSid == "S-1-1-0")
continue;
GroupPrincipal grp = GroupPrincipal.FindByIdentity(Provider.activeDirectoryBase.adContext, IdentityType.Sid, rule.IdentityReference.Value);
GroupPrincipal grp = GroupPrincipal.FindByIdentity(Provider.activeDirectoryBase.adContext, IdentityType.Sid, aclSid);
if (grp == null)
continue;
DefaultLogger.LogEntry(LogLevels.Debug, $"Try matching: {grp.Name}");
if (Regex.IsMatch(grp.SamAccountName, ownerNamingConvention.Wildcard, RegexOptions.IgnoreCase))
{
this.OwnerGroupIdentifier = rule.IdentityReference.Value;
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' could not be resolved to an AD group. Naming convention matching skipped.");
continue;
}
var samAccountName = grp.SamAccountName ?? string.Empty;
if (string.IsNullOrWhiteSpace(samAccountName))
{
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' resolved to '{grp.Name}', but no sAMAccountName is available. Naming convention matching skipped.");
continue;
}
if (Regex.IsMatch(samAccountName, ownerNamingConvention.Wildcard, RegexOptions.IgnoreCase))
{
this.OwnerGroupIdentifier = aclSid;
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' resolved to '{samAccountName}' and matched Owner naming convention '{ownerNamingConvention.Wildcard}'.");
if (Provider.GroupStrategy == eLiamGroupStrategies.Ntfs_AGDLP)
{
var ldapFilter = String.Format("memberOf={0}", grp.DistinguishedName);
var res = await Provider.activeDirectoryBase.RequestSecurityGroupsListAsync(ldapFilter);
var ownerNamingConventionGlobal = Provider.NamingConventions.First(i => i.AccessRole == eLiamAccessRoles.Owner && i.Scope == eLiamAccessRoleScopes.Global);
var matchedGlobalGroup = false;
foreach (var memberItem in res)
foreach (var memberItem in res ?? new cADCollectionBase())
{
var SecurityGroup = new cLiamAdGroup(this.Provider, (cSecurityGroupResult)memberItem.Value);
if (Regex.IsMatch(SecurityGroup.TechnicalName, ownerNamingConventionGlobal.Wildcard, RegexOptions.IgnoreCase))
{
this.OwnerGroupIdentifier = SecurityGroup.UID;
matchedGlobalGroup = true;
DefaultLogger.LogEntry(LogLevels.Debug, $"AGDLP Owner ACL group '{samAccountName}' resolved to global group '{SecurityGroup.TechnicalName}' with SID '{SecurityGroup.UID}'.");
}
}
if (!matchedGlobalGroup)
DefaultLogger.LogEntry(LogLevels.Debug, $"AGDLP Owner ACL group '{samAccountName}' matched, but no nested global group matched naming convention '{ownerNamingConventionGlobal.Wildcard}'. Keeping ACL SID '{aclSid}'.");
}
}
else if (Regex.IsMatch(grp.SamAccountName, writeNamingConvention.Wildcard, RegexOptions.IgnoreCase))
else if (Regex.IsMatch(samAccountName, writeNamingConvention.Wildcard, RegexOptions.IgnoreCase))
{
this.WriteGroupIdentifier = rule.IdentityReference.Value;
this.WriteGroupIdentifier = aclSid;
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' resolved to '{samAccountName}' and matched Write naming convention '{writeNamingConvention.Wildcard}'.");
if (Provider.GroupStrategy == eLiamGroupStrategies.Ntfs_AGDLP)
{
var ldapFilter = String.Format("memberOf={0}", grp.DistinguishedName);
var res = await Provider.activeDirectoryBase.RequestSecurityGroupsListAsync(ldapFilter);
var writeNamingConventionGlobal = Provider.NamingConventions.First(i => i.AccessRole == eLiamAccessRoles.Write && i.Scope == eLiamAccessRoleScopes.Global);
var matchedGlobalGroup = false;
foreach (var memberItem in res)
foreach (var memberItem in res ?? new cADCollectionBase())
{
var SecurityGroup = new cLiamAdGroup(this.Provider, (cSecurityGroupResult)memberItem.Value);
if (Regex.IsMatch(SecurityGroup.TechnicalName, writeNamingConventionGlobal.Wildcard, RegexOptions.IgnoreCase))
{
this.WriteGroupIdentifier = SecurityGroup.UID;
matchedGlobalGroup = true;
DefaultLogger.LogEntry(LogLevels.Debug, $"AGDLP Write ACL group '{samAccountName}' resolved to global group '{SecurityGroup.TechnicalName}' with SID '{SecurityGroup.UID}'.");
}
}
if (!matchedGlobalGroup)
DefaultLogger.LogEntry(LogLevels.Debug, $"AGDLP Write ACL group '{samAccountName}' matched, but no nested global group matched naming convention '{writeNamingConventionGlobal.Wildcard}'. Keeping ACL SID '{aclSid}'.");
}
}
else if (Regex.IsMatch(grp.SamAccountName, readNamingConvention.Wildcard, RegexOptions.IgnoreCase))
else if (Regex.IsMatch(samAccountName, readNamingConvention.Wildcard, RegexOptions.IgnoreCase))
{
this.ReadGroupIdentifier = rule.IdentityReference.Value;
this.ReadGroupIdentifier = aclSid;
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' resolved to '{samAccountName}' and matched Read naming convention '{readNamingConvention.Wildcard}'.");
if (Provider.GroupStrategy == eLiamGroupStrategies.Ntfs_AGDLP)
{
var ldapFilter = String.Format("memberOf={0}", grp.DistinguishedName);
var res = await Provider.activeDirectoryBase.RequestSecurityGroupsListAsync(ldapFilter);
var readNamingConventionGlobal = Provider.NamingConventions.First(i => i.AccessRole == eLiamAccessRoles.Read && i.Scope == eLiamAccessRoleScopes.Global);
var matchedGlobalGroup = false;
foreach (var memberItem in res)
foreach (var memberItem in res ?? new cADCollectionBase())
{
var SecurityGroup = new cLiamAdGroup(this.Provider, (cSecurityGroupResult)memberItem.Value);
if (Regex.IsMatch(SecurityGroup.TechnicalName, readNamingConventionGlobal.Wildcard, RegexOptions.IgnoreCase))
{
this.ReadGroupIdentifier = SecurityGroup.UID;
matchedGlobalGroup = true;
DefaultLogger.LogEntry(LogLevels.Debug, $"AGDLP Read ACL group '{samAccountName}' resolved to global group '{SecurityGroup.TechnicalName}' with SID '{SecurityGroup.UID}'.");
}
}
if (!matchedGlobalGroup)
DefaultLogger.LogEntry(LogLevels.Debug, $"AGDLP Read ACL group '{samAccountName}' matched, but no nested global group matched naming convention '{readNamingConventionGlobal.Wildcard}'. Keeping ACL SID '{aclSid}'.");
}
}
else if (Regex.IsMatch(grp.SamAccountName, traverseNamingConvention.Wildcard, RegexOptions.IgnoreCase))
else if (Regex.IsMatch(samAccountName, traverseNamingConvention.Wildcard, RegexOptions.IgnoreCase))
{
this.TraverseGroupIdentifier = rule.IdentityReference.Value;
this.TraverseGroupIdentifier = aclSid;
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' resolved to '{samAccountName}' and matched Traverse naming convention '{traverseNamingConvention.Wildcard}'.");
}
else
{
DefaultLogger.LogEntry(LogLevels.Debug, $"No match for: {grp.Name}");
DefaultLogger.LogEntry(LogLevels.Debug, $"ACL SID '{aclSid}' on '{path}' resolved to '{samAccountName}', but did not match Owner/Write/Read/Traverse naming conventions.");
}
}
}

View File

@@ -27,6 +27,7 @@ namespace C4IT_IAM_SET
public const string constApplicationDataPath = "%ProgramData%\\Consulting4IT GmbH\\LIAM";
public string domainName;
public string effectiveDomainController;
public string username;
public SecureString password;
private cNetworkConnection Connection;
@@ -53,7 +54,11 @@ namespace C4IT_IAM_SET
public ICollection<string> readerUserSids;
public ICollection<string> writerUserSids;
public Func<string, bool> CanManagePermissionsForPath;
public Func<string, bool> CanManageTraversePermissionsForPath;
public string traverseBoundaryPath;
public bool forceStrictAdGroupNames;
public string groupNameSanitizeReplacement = Helper.DefaultGroupNameSanitizeReplacement;
public bool preserveAdGroupNameCase;
public bool WhatIf;
public int ReadACLPermission = 0x200A9;
@@ -83,6 +88,11 @@ namespace C4IT_IAM_SET
templates = new List<IAM_SecurityGroupTemplate>();
}
private string GetAdServer()
{
return string.IsNullOrWhiteSpace(effectiveDomainController) ? domainName : effectiveDomainController;
}
private ResultToken checkRequiredVariables()
{
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
@@ -147,6 +157,10 @@ namespace C4IT_IAM_SET
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 traverseBoundaryResult = ValidateTraverseBoundaryForCurrentFolder();
if (traverseBoundaryResult.resultErrorId != 0)
return traverseBoundaryResult;
var folderCheckResult = checkFolder();
if (folderCheckResult.resultErrorId == 0)
{
@@ -294,11 +308,46 @@ namespace C4IT_IAM_SET
{
username = username,
domainName = domainName,
effectiveDomainController = effectiveDomainController,
password = password,
ForceStrictAdGroupNames = forceStrictAdGroupNames
ForceStrictAdGroupNames = forceStrictAdGroupNames,
PreserveAdGroupNameCase = preserveAdGroupNameCase
};
}
private ResultToken ValidateTraverseBoundaryForCurrentFolder()
{
var resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
resultToken.resultErrorId = 0;
var boundaryPath = GetNormalizedTraverseBoundaryPath();
if (string.IsNullOrWhiteSpace(boundaryPath))
return resultToken;
var targetParent = new DirectoryInfo(newFolderPath).Parent;
if (targetParent == null)
{
resultToken.resultErrorId = 30009;
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' cannot be validated because '{newFolderPath}' has no parent directory.";
return resultToken;
}
if (!Directory.Exists(boundaryPath))
{
resultToken.resultErrorId = 30009;
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' does not exist or is not reachable.";
return resultToken;
}
if (!IsSameOrAncestorPath(boundaryPath, targetParent.FullName))
{
resultToken.resultErrorId = 30009;
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' is not a parent path of '{newFolderPath}'.";
}
return resultToken;
}
public ResultToken ensureDataAreaPermissions(bool ensureTraverseGroups = false)
{
LogMethodBegin(MethodBase.GetCurrentMethod());
@@ -327,6 +376,10 @@ namespace C4IT_IAM_SET
InitializeFolderContext();
var traverseBoundaryResult = ValidateTraverseBoundaryForCurrentFolder();
if (traverseBoundaryResult.resultErrorId != 0)
return traverseBoundaryResult;
ensureADGroups(resultToken);
resultToken = ensureFolderPermissions(resultToken);
@@ -395,7 +448,7 @@ namespace C4IT_IAM_SET
return resultToken;
}
var domainContext = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password);
var domainContext = new PrincipalContext(ContextType.Domain, GetAdServer(), username, new NetworkCredential("", password).Password);
DefaultLogger.LogEntry(LogLevels.Debug, "PrincipalContext erfolgreich erstellt.");
// Überprüfen von newDataArea und IAM_Folders
@@ -424,6 +477,10 @@ namespace C4IT_IAM_SET
var lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
DefaultLogger.LogEntry(LogLevels.Debug, $"Ebene (lvl): {lvl}");
var currentTraverseLevel = lvl;
var defaultTraverseLoopIndex = lvl;
var hasTraverseBoundary = !string.IsNullOrWhiteSpace(GetNormalizedTraverseBoundaryPath());
var processedNearestTraverseParent = false;
// Überprüfen der Templates
if (templates == null)
@@ -472,9 +529,9 @@ namespace C4IT_IAM_SET
return resultToken;
}
for (int i = lvl; i >= createTraverseGroupLvl; i--)
while (parent != null && (hasTraverseBoundary || defaultTraverseLoopIndex >= createTraverseGroupLvl))
{
DefaultLogger.LogEntry(LogLevels.Debug, $"Verarbeite Ebene {i}.");
DefaultLogger.LogEntry(LogLevels.Debug, $"Verarbeite Ebene {currentTraverseLevel}.");
if (parent == null)
{
@@ -482,14 +539,22 @@ namespace C4IT_IAM_SET
break;
}
if (CanManagePermissionsForPath != null && !CanManagePermissionsForPath(parent.FullName))
var canManageTraversePath = CanManageTraversePermissionsForPath ?? CanManagePermissionsForPath;
if (canManageTraversePath != null && !canManageTraversePath(parent.FullName))
{
DefaultLogger.LogEntry(LogLevels.Debug, $"Überspringe Traverse-Verarbeitung für nicht verwaltbaren NTFS-Pfad: {parent.FullName}");
if (IsTraverseBoundaryPath(parent.FullName))
break;
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 Überspringen: {lvl}");
currentTraverseLevel = hasTraverseBoundary
? currentTraverseLevel + 1
: DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
if (!hasTraverseBoundary)
defaultTraverseLoopIndex--;
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Überspringen: {currentTraverseLevel}");
}
else
{
@@ -524,44 +589,59 @@ namespace C4IT_IAM_SET
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;
var sanitizedSegments = relativePathSegments.Select(i => Helper.SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
var relativePath = sanitizedSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(sanitizedSegments, groupNameSanitizeReplacement) : 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)));
: Helper.SanitizePathSegment(Path.GetFileName(parent.FullName.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)), groupNameSanitizeReplacement);
var traverseTags = GetTraverseReplacementTags(parent.FullName);
var rootContext = Helper.GetRootPathTemplateContext(baseFolder, groupNameSanitizeReplacement);
var boundedTraverseContext = Helper.GetBoundedAdGroupTemplateContext(
traverseGroupTemplate.NamingTemplate,
true,
relativePath,
sanitizedSegments,
folderName,
null,
traverseTags,
Helper.MaxAdGroupNameLength,
$"Traverse fuer '{parent.FullName}'");
$"Traverse fuer '{parent.FullName}'",
"AD-Gruppenname",
rootContext,
preserveAdGroupNameCase,
groupNameSanitizeReplacement);
var boundedTraverseDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
traverseGroupTemplate.DescriptionTemplate,
true,
relativePath,
sanitizedSegments,
folderName,
null,
traverseTags,
Helper.MaxAdGroupDescriptionLength,
$"Traverse fuer '{parent.FullName}'",
"AD-Gruppenbeschreibung");
"AD-Gruppenbeschreibung",
rootContext,
preserveAdGroupNameCase,
groupNameSanitizeReplacement);
var adjustedTraverseSegments = boundedTraverseContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedTraverseRelativePath = adjustedTraverseSegments.Length > 0 ? string.Join("_", adjustedTraverseSegments) : string.Empty;
var adjustedTraverseRelativePath = adjustedTraverseSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedTraverseSegments, groupNameSanitizeReplacement) : string.Empty;
var adjustedTraverseFolderName = boundedTraverseContext.FolderName;
var adjustedTraverseDescriptionSegments = boundedTraverseDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedTraverseDescriptionRelativePath = adjustedTraverseDescriptionSegments.Length > 0 ? string.Join("_", adjustedTraverseDescriptionSegments) : string.Empty;
var adjustedTraverseDescriptionRelativePath = adjustedTraverseDescriptionSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedTraverseDescriptionSegments, groupNameSanitizeReplacement) : string.Empty;
var adjustedTraverseDescriptionFolderName = boundedTraverseDescriptionContext.FolderName;
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName);
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName);
var traverseNameTemplate = Helper.ApplyAdGroupNameCasing(
Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext, groupNameSanitizeReplacement).ReplaceTags(traverseTags),
preserveAdGroupNameCase);
var traverseDescriptionTemplate = Helper.ApplyAdGroupNameCasing(
Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName, rootContext, groupNameSanitizeReplacement).ReplaceTags(traverseTags),
preserveAdGroupNameCase);
string traverseRegex = null;
try
{
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName);
traverseRegex = Helper.ApplyAdGroupNameCasing(
Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext, groupNameSanitizeReplacement).ReplaceTags(traverseTags),
preserveAdGroupNameCase);
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
}
catch (Exception ex)
@@ -570,8 +650,12 @@ namespace C4IT_IAM_SET
continue;
}
var hasTraverseWildcard = !string.IsNullOrWhiteSpace(traverseRegex);
foreach (FileSystemAccessRule acl in ACLs)
{
if (!hasTraverseWildcard)
break;
var searchString = acl.IdentityReference.Value;
var aclSplit = searchString.Split('\\');
if (aclSplit.Length == 2)
@@ -600,7 +684,18 @@ namespace C4IT_IAM_SET
break;
}
if (parentTraverseGroup == null && !string.IsNullOrEmpty(traverseNameTemplate))
if (parentTraverseGroup == null && hasTraverseWildcard && !forceStrictAdGroupNames)
{
parentTraverseGroup = FindTraverseGroupByWildcard(domainContext, traverseRegex);
if (parentTraverseGroup != null)
{
resultToken.reusedGroups.Add(parentTraverseGroup.Name);
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe per Wildcard wiederverwendet: {parentTraverseGroup.Name}");
}
}
if (parentTraverseGroup == null && !string.IsNullOrWhiteSpace(traverseNameTemplate))
{
for (var loop = 0; loop < 20; loop++)
{
@@ -616,7 +711,7 @@ namespace C4IT_IAM_SET
}
}
if (parentTraverseGroup == null && !traverseGroupTemplate.NamingTemplate.Equals(string.Empty))
if (parentTraverseGroup == null && !string.IsNullOrWhiteSpace(traverseNameTemplate))
{
DefaultLogger.LogEntry(LogLevels.Debug, "Erstelle neue TraverseGroup.");
if (newSecurityGroups == null)
@@ -646,7 +741,7 @@ namespace C4IT_IAM_SET
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen von newTraverseGroup: {ex.Message}");
break;
}
} while (newSecurityGroups.GroupAllreadyExisting(newTraverseGroup.Name.ToUpper()) && loop < 20);
} while (newSecurityGroups.GroupAllreadyExisting(newTraverseGroup.Name) && loop < 20);
if (newTraverseGroup != null)
{
@@ -750,7 +845,7 @@ namespace C4IT_IAM_SET
if (parentTraverseGroup != null)
{
if (i == lvl)
if (!processedNearestTraverseParent)
{
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
@@ -773,6 +868,7 @@ namespace C4IT_IAM_SET
continue;
}
traverseGroup = parentTraverseGroup;
processedNearestTraverseParent = true;
}
else
{
@@ -821,12 +917,19 @@ namespace C4IT_IAM_SET
if (parentTraverseGroup != null && !resultToken.ensuredTraverseGroups.Contains(parentTraverseGroup.Name))
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
if (IsTraverseBoundaryPath(parent.FullName))
break;
// 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}");
currentTraverseLevel = hasTraverseBoundary
? currentTraverseLevel + 1
: DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
if (!hasTraverseBoundary)
defaultTraverseLoopIndex--;
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue Ebene (lvl) nach Aktualisierung: {currentTraverseLevel}");
}
else
{
@@ -847,6 +950,177 @@ namespace C4IT_IAM_SET
}
}
private string GetNormalizedTraverseBoundaryPath()
{
return NormalizeDirectoryPath(traverseBoundaryPath);
}
private bool IsTraverseBoundaryPath(string path)
{
var boundaryPath = GetNormalizedTraverseBoundaryPath();
return !string.IsNullOrWhiteSpace(boundaryPath)
&& PathsEqual(boundaryPath, path);
}
private Dictionary<string, string> GetTraverseReplacementTags(string currentPath)
{
var visibleSegments = GetVisibleTraversePathSegments(currentPath);
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "TRAVERSE_NAME", Helper.SanitizePathSegment(GetLastPathSegment(currentPath), groupNameSanitizeReplacement) },
{ "TRAVERSE_VISIBLEPATH", Helper.JoinSanitizedPathSegments(visibleSegments.Select(i => Helper.SanitizePathSegment(i, groupNameSanitizeReplacement)), groupNameSanitizeReplacement) }
};
}
private IEnumerable<string> GetVisibleTraversePathSegments(string currentPath)
{
var normalizedCurrentPath = NormalizeDirectoryPath(currentPath);
var boundaryPath = GetNormalizedTraverseBoundaryPath();
if (string.IsNullOrWhiteSpace(boundaryPath))
boundaryPath = NormalizeDirectoryPath(baseFolder);
var visibleRoot = GetParentPath(boundaryPath);
if (string.IsNullOrWhiteSpace(visibleRoot))
visibleRoot = boundaryPath;
var currentSegments = SplitPathSegments(normalizedCurrentPath);
var rootSegments = SplitPathSegments(visibleRoot);
if (currentSegments.Length <= rootSegments.Length)
return currentSegments;
var isRootPrefix = rootSegments
.Select((segment, index) => new { segment, index })
.All(i => string.Equals(i.segment, currentSegments[i.index], StringComparison.OrdinalIgnoreCase));
return isRootPrefix
? currentSegments.Skip(rootSegments.Length)
: currentSegments;
}
private GroupPrincipal FindTraverseGroupByWildcard(PrincipalContext domainContext, string wildcardPattern)
{
if (domainContext == null || 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://" + GetAdServer();
if (!string.IsNullOrWhiteSpace(groupOUPath))
basePath += "/" + groupOUPath;
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("objectSid");
string matchedSid = null;
string matchedName = 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 traverse wildcard '{wildcardPattern}' in '{basePath}'. Regex-based reuse is skipped.");
search.Dispose();
entry.Dispose();
return null;
}
matchedName = samAccountName;
matchedSid = result.Properties.Contains("objectSid") && result.Properties["objectSid"].Count > 0
? new SecurityIdentifier((byte[])result.Properties["objectSid"][0], 0).Value
: null;
}
search.Dispose();
entry.Dispose();
if (string.IsNullOrWhiteSpace(matchedSid))
return null;
DefaultLogger.LogEntry(LogLevels.Debug, $"Reusing existing traverse AD group '{matchedName}' via wildcard '{wildcardPattern}'.");
return GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, matchedSid);
}
private static string NormalizeDirectoryPath(string path)
{
if (string.IsNullOrWhiteSpace(path))
return string.Empty;
var normalized = path.Trim().Replace('/', '\\').TrimEnd('\\');
if (normalized.StartsWith(@"\\", StringComparison.Ordinal))
return @"\\" + string.Join("\\", SplitPathSegments(normalized));
return normalized;
}
private static bool PathsEqual(string left, string right)
{
return string.Equals(NormalizeDirectoryPath(left), NormalizeDirectoryPath(right), StringComparison.OrdinalIgnoreCase);
}
private static bool IsSameOrAncestorPath(string ancestorPath, string path)
{
var ancestor = NormalizeDirectoryPath(ancestorPath);
var current = NormalizeDirectoryPath(path);
return string.Equals(ancestor, current, StringComparison.OrdinalIgnoreCase)
|| current.StartsWith(ancestor + "\\", StringComparison.OrdinalIgnoreCase);
}
private static string GetParentPath(string path)
{
var segments = SplitPathSegments(path);
if (segments.Length <= 1)
return string.Empty;
if (NormalizeDirectoryPath(path).StartsWith(@"\\", StringComparison.Ordinal))
return @"\\" + string.Join("\\", segments.Take(segments.Length - 1));
return string.Join("\\", segments.Take(segments.Length - 1));
}
private static string GetLastPathSegment(string path)
{
var segments = SplitPathSegments(path);
return segments.Length == 0 ? string.Empty : segments[segments.Length - 1];
}
private static string[] SplitPathSegments(string path)
{
return (path ?? string.Empty)
.Trim()
.Replace('/', '\\')
.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
}
private bool TryEnsureGlobalGroupMembershipWithRetry(PrincipalContext domainContext, GroupPrincipal parentTraverseGroup, IAM_SecurityGroup currentSecGroup)
{
if (domainContext == null || parentTraverseGroup == null || currentSecGroup == null || string.IsNullOrWhiteSpace(currentSecGroup.UID))
@@ -946,6 +1220,7 @@ namespace C4IT_IAM_SET
{
ResultToken resultToken = new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString());
resultToken.resultErrorId = 0;
newSecurityGroups.effectiveDomainController = effectiveDomainController;
if (Directory.Exists(newDataArea.IAM_Folders[0].technicalName))
{
resultToken.resultMessage = "New folder " + newDataArea.IAM_Folders[0].technicalName + " already exists";
@@ -1065,7 +1340,10 @@ namespace C4IT_IAM_SET
ReadACLPermission,
WriteACLPermission,
OwnerACLPermission,
0);
0,
0,
groupNameSanitizeReplacement,
preserveAdGroupNameCase);
List<UserPrincipal> owners = getUserPrincipalBySid(ownerUserSids);
List<UserPrincipal> writers = getUserPrincipalBySid(writerUserSids);
@@ -1228,7 +1506,10 @@ namespace C4IT_IAM_SET
ReadACLPermission,
WriteACLPermission,
OwnerACLPermission,
existingADGroupCount);
existingADGroupCount,
0,
groupNameSanitizeReplacement,
preserveAdGroupNameCase);
/*
if (existingADGroupCount > 0 && !templates.All(t => t.Type == SecurityGroupType.Traverse || Regex.IsMatch(t.NamingTemplate, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})")))
{
@@ -1329,7 +1610,7 @@ namespace C4IT_IAM_SET
try
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password);
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, GetAdServer(), username, new NetworkCredential("", password).Password);
UserPrincipal user;
user = UserPrincipal.FindByIdentity(ctx, IdentityType.Sid, (sid));
return user;

View File

@@ -14,6 +14,8 @@ namespace C4IT_IAM_Engine
public const int MaxAdGroupNameLength = 64;
public const int MaxAdGroupDescriptionLength = 1024;
public const int MaxAdGroupLoopDigits = 3;
public const string DefaultGroupNameSanitizeReplacement = "_";
private const string AdUnsafeGroupNameCharactersPattern = @"[\x00-\x1F\s\-\/\\\[\]:;\|=,\+\*\?<>\@()'""]";
private const int MinLeadingRelativePathSegmentLength = 3;
private const int MinSingleLeadingRelativePathSegmentLength = 2;
private const int MinLastRelativePathSegmentLength = 12;
@@ -28,6 +30,15 @@ namespace C4IT_IAM_Engine
public string Strategy { get; set; } = string.Empty;
}
public sealed class RootPathTemplateContext
{
public string Server { get; set; } = string.Empty;
public string[] Segments { get; set; } = Array.Empty<string>();
public string Name { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string PathSegmentSeparator { get; set; } = DefaultGroupNameSanitizeReplacement;
}
public static string ReplaceLoopTag(this string str, int loop)
{
return Regex.Replace(str, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})", loop <= 0 ? "" : "${prefix}" + loop + "${postfix}");
@@ -40,11 +51,22 @@ namespace C4IT_IAM_Engine
current.Replace("{{" + value.Key + "}}", value.Value));
}
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName)
{
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, null, DefaultGroupNameSanitizeReplacement);
}
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName, RootPathTemplateContext rootContext)
{
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext, DefaultGroupNameSanitizeReplacement);
}
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName, RootPathTemplateContext rootContext, string pathSegmentSeparator)
{
if (templateValue == null)
return string.Empty;
var result = Regex.Replace(templateValue, @"{{\s*NAME\s*}}", folderName ?? string.Empty, RegexOptions.IgnoreCase);
result = ApplyRootPathPlaceholders(result, rootContext);
if (allowRelativePath)
{
@@ -61,12 +83,39 @@ namespace C4IT_IAM_Engine
var segmentCount = Math.Min(sanitizedSegments.Length, segmentIndex + 1);
var skip = sanitizedSegments.Length - segmentCount;
return string.Join("_", sanitizedSegments.Skip(skip));
return JoinSanitizedPathSegments(sanitizedSegments.Skip(skip), pathSegmentSeparator);
}, RegexOptions.IgnoreCase);
}
return result;
}
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath)
{
return GetRootPathTemplateContext(rootPath, DefaultGroupNameSanitizeReplacement);
}
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath, string groupNameSanitizeReplacement)
{
var segments = SplitPathSegments(rootPath);
if (segments.Length == 0)
return new RootPathTemplateContext();
var isUncPath = (rootPath ?? string.Empty).Trim().Replace('/', '\\').StartsWith(@"\\", StringComparison.Ordinal);
var server = isUncPath ? SanitizePathSegment(segments[0], groupNameSanitizeReplacement) : string.Empty;
var pathSegments = isUncPath ? segments.Skip(1).ToArray() : segments;
var sanitizedPathSegments = pathSegments.Select(i => SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
return new RootPathTemplateContext
{
Server = server,
Segments = sanitizedPathSegments,
Name = sanitizedPathSegments.Length == 0 ? string.Empty : sanitizedPathSegments[sanitizedPathSegments.Length - 1],
Path = sanitizedPathSegments.Length == 0 ? string.Empty : JoinSanitizedPathSegments(sanitizedPathSegments, groupNameSanitizeReplacement),
PathSegmentSeparator = NormalizeGroupNameSanitizeReplacement(groupNameSanitizeReplacement)
};
}
public static BoundedTemplateContext GetBoundedAdGroupTemplateContext(
string templateValue,
bool allowRelativePath,
@@ -76,13 +125,16 @@ namespace C4IT_IAM_Engine
IDictionary<string, string> replacementTags,
int maxLength,
string logContext,
string valueLabel = "AD-Gruppenname")
string valueLabel = "AD-Gruppenname",
RootPathTemplateContext rootContext = null,
bool preserveCase = false,
string pathSegmentSeparator = DefaultGroupNameSanitizeReplacement)
{
var effectiveSegments = (sanitizedSegments ?? Array.Empty<string>()).Where(i => i != null).ToArray();
var effectiveFolderName = folderName ?? string.Empty;
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath, pathSegmentSeparator);
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
var usesRelativePath = allowRelativePath && Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*RELATIVEPATH", RegexOptions.IgnoreCase);
var usesName = Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*NAME\s*}}", RegexOptions.IgnoreCase);
var strategy = string.Empty;
@@ -108,18 +160,21 @@ namespace C4IT_IAM_Engine
if (!changed)
break;
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath, pathSegmentSeparator);
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator);
}
var initialValue = MaterializeTemplateValue(
templateValue,
allowRelativePath,
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath),
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath, pathSegmentSeparator),
sanitizedSegments,
folderName,
replacementTags);
replacementTags,
rootContext,
preserveCase,
pathSegmentSeparator);
var result = new BoundedTemplateContext
{
SanitizedSegments = effectiveSegments,
@@ -147,11 +202,50 @@ namespace C4IT_IAM_Engine
return result;
}
public static string SanitizePathSegment(string segment)
{
return SanitizePathSegment(segment, DefaultGroupNameSanitizeReplacement);
}
public static string SanitizePathSegment(string segment, string groupNameSanitizeReplacement)
{
if (string.IsNullOrEmpty(segment))
return string.Empty;
return Regex.Replace(segment, @"[\s\-]", "_");
var replacement = NormalizeGroupNameSanitizeReplacement(groupNameSanitizeReplacement);
return Regex.Replace(segment, AdUnsafeGroupNameCharactersPattern, match => replacement);
}
public static string NormalizeGroupNameSanitizeReplacement(string replacement)
{
if (replacement == null)
return DefaultGroupNameSanitizeReplacement;
var trimmed = replacement.Trim();
if (trimmed.Equals("<empty>", StringComparison.OrdinalIgnoreCase)
|| trimmed.Equals("empty", StringComparison.OrdinalIgnoreCase)
|| trimmed.Equals("none", StringComparison.OrdinalIgnoreCase)
|| trimmed.Equals("remove", StringComparison.OrdinalIgnoreCase))
{
return string.Empty;
}
return trimmed;
}
public static string JoinSanitizedPathSegments(IEnumerable<string> sanitizedSegments, string groupNameSanitizeReplacement)
{
if (sanitizedSegments == null)
return string.Empty;
return string.Join(NormalizeGroupNameSanitizeReplacement(groupNameSanitizeReplacement), sanitizedSegments);
}
public static string ApplyAdGroupNameCasing(string value, bool preserveCase)
{
if (value == null)
return string.Empty;
return preserveCase ? value : value.ToUpper();
}
public static void CreatePathWithWriteAccess(string FilePath)
{
@@ -181,11 +275,15 @@ namespace C4IT_IAM_Engine
string defaultRelativePath,
string[] sanitizedSegments,
string folderName,
IDictionary<string, string> replacementTags)
IDictionary<string, string> replacementTags,
RootPathTemplateContext rootContext,
bool preserveCase,
string pathSegmentSeparator)
{
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName)
.ReplaceTags(replacementTags)
.ToUpper();
var materializedValue = ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext, pathSegmentSeparator)
.ReplaceTags(replacementTags);
return ApplyAdGroupNameCasing(materializedValue, preserveCase);
}
private static string MaterializeTemplateValueForLength(
@@ -194,10 +292,45 @@ namespace C4IT_IAM_Engine
string defaultRelativePath,
string[] sanitizedSegments,
string folderName,
IDictionary<string, string> replacementTags)
IDictionary<string, string> replacementTags,
RootPathTemplateContext rootContext,
bool preserveCase,
string pathSegmentSeparator)
{
return NormalizeLoopPlaceholderLength(
MaterializeTemplateValue(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, replacementTags));
MaterializeTemplateValue(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, replacementTags, rootContext, preserveCase, pathSegmentSeparator));
}
private static string ApplyRootPathPlaceholders(string templateValue, RootPathTemplateContext rootContext)
{
if (templateValue == null)
return string.Empty;
var context = rootContext ?? new RootPathTemplateContext();
var result = Regex.Replace(templateValue, @"{{\s*ROOT_SERVER\s*}}", context.Server ?? string.Empty, RegexOptions.IgnoreCase);
result = Regex.Replace(result, @"{{\s*ROOT_NAME\s*}}", context.Name ?? string.Empty, RegexOptions.IgnoreCase);
result = Regex.Replace(result, @"{{\s*ROOT_PATH(?:\s*\(\s*(\d+)\s*\))?\s*}}", match =>
{
var segments = context.Segments ?? Array.Empty<string>();
if (!match.Groups[1].Success)
return context.Path ?? string.Empty;
if (!int.TryParse(match.Groups[1].Value, out var segmentCount) || segmentCount <= 0)
return string.Empty;
var take = Math.Min(segmentCount, segments.Length);
return take == 0 ? string.Empty : JoinSanitizedPathSegments(segments.Skip(segments.Length - take), context.PathSegmentSeparator);
}, RegexOptions.IgnoreCase);
result = Regex.Replace(result, @"{{\s*ROOT_SEGMENT\s*\(\s*(\d+)\s*\)\s*}}", match =>
{
var segments = context.Segments ?? Array.Empty<string>();
if (!int.TryParse(match.Groups[1].Value, out var segmentIndex) || segmentIndex < 0 || segmentIndex >= segments.Length)
return string.Empty;
return segments[segmentIndex] ?? string.Empty;
}, RegexOptions.IgnoreCase);
return result;
}
private static string NormalizeLoopPlaceholderLength(string templateValue)
@@ -217,10 +350,18 @@ namespace C4IT_IAM_Engine
return NormalizeLoopPlaceholderLength(templateValue).Length;
}
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath)
private static string[] SplitPathSegments(string path)
{
return (path ?? string.Empty)
.Trim()
.Replace('/', '\\')
.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
}
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath, string pathSegmentSeparator)
{
if (sanitizedSegments != null && sanitizedSegments.Length > 0)
return string.Join("_", sanitizedSegments);
return JoinSanitizedPathSegments(sanitizedSegments, pathSegmentSeparator);
return fallbackRelativePath ?? string.Empty;
}

View File

@@ -21,9 +21,11 @@ namespace C4IT_IAM_Engine
public class SecurityGroups
{
public string domainName;
public string effectiveDomainController;
public string username;
public SecureString password;
public bool ForceStrictAdGroupNames;
public bool PreserveAdGroupNameCase;
public List<IAM_SecurityGroup> IAM_SecurityGroups;
public string rootUID;
@@ -31,6 +33,11 @@ namespace C4IT_IAM_Engine
{
IAM_SecurityGroups = new List<IAM_SecurityGroup>();
}
private string GetLdapServer()
{
return string.IsNullOrWhiteSpace(effectiveDomainController) ? domainName : effectiveDomainController;
}
public bool GroupsAllreadyExisting(string ouPath)
{
LogMethodBegin(MethodBase.GetCurrentMethod());
@@ -46,14 +53,14 @@ namespace C4IT_IAM_Engine
{
DirectoryEntry entry = new DirectoryEntry
{
Path = "LDAP://" + domainName,
Path = "LDAP://" + GetLdapServer(),
Username = username,
Password = new NetworkCredential("", password).Password,
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
};
DirectorySearcher dSearch = new DirectorySearcher(entry)
{
Filter = "(&(CN=" + s.Name.ToUpper() + ")(objectClass=group))"
Filter = "(&(CN=" + GetConfiguredGroupName(s.Name) + ")(objectClass=group))"
};
dSearch.PageSize = 100000;
SearchResultCollection sr = dSearch.FindAll();
@@ -85,14 +92,14 @@ namespace C4IT_IAM_Engine
{
DirectoryEntry entry = new DirectoryEntry
{
Path = "LDAP://" + domainName,
Path = "LDAP://" + GetLdapServer(),
Username = username,
Password = new NetworkCredential("", password).Password,
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
};
DirectorySearcher dSearch = new DirectorySearcher(entry)
{
Filter = "(&(CN=" + CN.ToUpper() + ")(objectClass=group))"
Filter = "(&(CN=" + GetConfiguredGroupName(CN) + ")(objectClass=group))"
};
dSearch.PageSize = 100000;
SearchResultCollection sr = dSearch.FindAll();
@@ -129,7 +136,9 @@ namespace C4IT_IAM_Engine
int writeACLPermission,
int ownerACLPermission,
int loop = 0,
int existingADGroupCount = 0)
int existingADGroupCount = 0,
string groupNameSanitizeReplacement = Helper.DefaultGroupNameSanitizeReplacement,
bool preserveAdGroupNameCase = false)
{
LogMethodBegin(MethodBase.GetCurrentMethod());
try
@@ -145,11 +154,12 @@ namespace C4IT_IAM_Engine
var relativePathRaw = DataArea.GetRelativePath(newFolderPath, baseFolder).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
relativePathRaw = relativePathRaw.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
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;
var sanitizedSegments = relativePathSegments.Select(i => Helper.SanitizePathSegment(i, groupNameSanitizeReplacement)).ToArray();
var relativePath = sanitizedSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(sanitizedSegments, groupNameSanitizeReplacement) : string.Empty;
var folderName = sanitizedSegments.Length > 0
? sanitizedSegments[sanitizedSegments.Length - 1]
: Helper.SanitizePathSegment(Path.GetFileName(newFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
: Helper.SanitizePathSegment(Path.GetFileName(newFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)), groupNameSanitizeReplacement);
var rootContext = Helper.GetRootPathTemplateContext(baseFolder, groupNameSanitizeReplacement);
foreach (var template in resolvedTemplates)
{
@@ -206,7 +216,11 @@ namespace C4IT_IAM_Engine
folderName,
replacementTags,
Helper.MaxAdGroupNameLength,
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'");
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
"AD-Gruppenname",
rootContext,
preserveAdGroupNameCase,
groupNameSanitizeReplacement);
var boundedDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
template.DescriptionTemplate,
@@ -217,27 +231,33 @@ namespace C4IT_IAM_Engine
replacementTags,
Helper.MaxAdGroupDescriptionLength,
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
"AD-Gruppenbeschreibung");
"AD-Gruppenbeschreibung",
rootContext,
preserveAdGroupNameCase,
groupNameSanitizeReplacement);
var adjustedNameSegments = boundedNameContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedNameRelativePath = adjustedNameSegments.Length > 0 ? string.Join("_", adjustedNameSegments) : string.Empty;
var adjustedNameRelativePath = adjustedNameSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedNameSegments, groupNameSanitizeReplacement) : string.Empty;
var adjustedNameFolderName = boundedNameContext.FolderName;
var adjustedDescriptionSegments = boundedDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedDescriptionRelativePath = adjustedDescriptionSegments.Length > 0 ? string.Join("_", adjustedDescriptionSegments) : string.Empty;
var adjustedDescriptionRelativePath = adjustedDescriptionSegments.Length > 0 ? Helper.JoinSanitizedPathSegments(adjustedDescriptionSegments, groupNameSanitizeReplacement) : string.Empty;
var adjustedDescriptionFolderName = boundedDescriptionContext.FolderName;
template.NamingTemplate = Helper.ApplyTemplatePlaceholders(template.NamingTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName)
.ReplaceTags(customTags).ReplaceTags(tags)
.ToUpper();
template.NamingTemplate = Helper.ApplyAdGroupNameCasing(
Helper.ApplyTemplatePlaceholders(template.NamingTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext, groupNameSanitizeReplacement)
.ReplaceTags(customTags).ReplaceTags(tags),
preserveAdGroupNameCase);
template.DescriptionTemplate = Helper.ApplyTemplatePlaceholders(template.DescriptionTemplate, template.Type != SecurityGroupType.Traverse, adjustedDescriptionRelativePath, adjustedDescriptionSegments, adjustedDescriptionFolderName)
.ReplaceTags(customTags).ReplaceTags(tags)
.ToUpper();
template.DescriptionTemplate = Helper.ApplyAdGroupNameCasing(
Helper.ApplyTemplatePlaceholders(template.DescriptionTemplate, template.Type != SecurityGroupType.Traverse, adjustedDescriptionRelativePath, adjustedDescriptionSegments, adjustedDescriptionFolderName, rootContext, groupNameSanitizeReplacement)
.ReplaceTags(customTags).ReplaceTags(tags),
preserveAdGroupNameCase);
template.WildcardTemplate = Helper.ApplyTemplatePlaceholders(template.WildcardTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName)
.ReplaceTags(customTags).ReplaceTags(tags)
.ToUpper();
template.WildcardTemplate = Helper.ApplyAdGroupNameCasing(
Helper.ApplyTemplatePlaceholders(template.WildcardTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext, groupNameSanitizeReplacement)
.ReplaceTags(customTags).ReplaceTags(tags),
preserveAdGroupNameCase);
}
@@ -417,7 +437,7 @@ namespace C4IT_IAM_Engine
{
DirectoryEntry entry = new DirectoryEntry
{
Path = "LDAP://" + domainName,
Path = "LDAP://" + GetLdapServer(),
Username = username,
Password = new NetworkCredential("", password).Password,
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
@@ -425,7 +445,7 @@ namespace C4IT_IAM_Engine
DirectorySearcher search = new DirectorySearcher(entry)
{
Filter = "(&(objectClass=group)(sAMAccountName=" + groupName.ToUpper() + "))"
Filter = "(&(objectClass=group)(sAMAccountName=" + GetConfiguredGroupName(groupName) + "))"
};
search.PageSize = 100000;
@@ -459,7 +479,7 @@ namespace C4IT_IAM_Engine
return null;
}
var basePath = "LDAP://" + domainName;
var basePath = "LDAP://" + GetLdapServer();
if (!string.IsNullOrWhiteSpace(ouPath))
basePath += "/" + ouPath;
@@ -514,7 +534,7 @@ namespace C4IT_IAM_Engine
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);
return new DirectoryEntry("LDAP://" + GetLdapServer() + "/" + matchedDistinguishedName, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
}
private DirectoryEntry FindGroupEntryFromFolderAcl(string folderPath, string wildcardPattern)
@@ -541,7 +561,7 @@ namespace C4IT_IAM_Engine
.Cast<FileSystemAccessRule>();
var matchedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
using (var domainContext = new PrincipalContext(ContextType.Domain, domainName, username, new NetworkCredential("", password).Password))
using (var domainContext = new PrincipalContext(ContextType.Domain, GetLdapServer(), username, new NetworkCredential("", password).Password))
{
foreach (var rule in rules)
{
@@ -714,13 +734,17 @@ namespace C4IT_IAM_Engine
try
{
secGroup.CreatedNewEntry = false;
if (!GroupAllreadyExisting(secGroup.Name.ToUpper()))
var groupName = GetConfiguredGroupName(secGroup.Name);
secGroup.Name = groupName;
secGroup.technicalName = "CN=" + groupName + "," + ouPath;
if (!GroupAllreadyExisting(groupName))
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName + "/" + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
DefaultLogger.LogEntry(LogLevels.Debug, $"Creating ad entry with CN / sAmAccountName: {secGroup.Name.ToUpper()}");
DirectoryEntry group = entry.Children.Add("CN=" + secGroup.Name.ToUpper(), "group");
group.Properties["sAmAccountName"].Value = secGroup.Name.ToUpper();
DirectoryEntry entry = new DirectoryEntry("LDAP://" + GetLdapServer() + "/" + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
DefaultLogger.LogEntry(LogLevels.Debug, $"Creating ad entry with CN / sAmAccountName: {groupName}");
DirectoryEntry group = entry.Children.Add("CN=" + groupName, "group");
group.Properties["sAmAccountName"].Value = groupName;
if (users != null && secGroup.Scope == GroupScope.Global)
{
foreach (var user in users)
@@ -745,7 +769,7 @@ namespace C4IT_IAM_Engine
}
group.CommitChanges();
DirectoryEntry ent = new DirectoryEntry("LDAP://" + domainName + "/" + "CN =" + secGroup.Name.ToUpper() + "," + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
DirectoryEntry ent = new DirectoryEntry("LDAP://" + GetLdapServer() + "/" + "CN=" + groupName + "," + ouPath, username, new NetworkCredential("", password).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
var objectid = SecurityGroups.getSID(ent);
DefaultLogger.LogEntry(LogLevels.Debug, $"Security group created in ad: {secGroup.technicalName}");
@@ -774,6 +798,11 @@ namespace C4IT_IAM_Engine
LogMethodEnd(MethodBase.GetCurrentMethod());
}
}
private string GetConfiguredGroupName(string groupName)
{
return Helper.ApplyAdGroupNameCasing(groupName, PreserveAdGroupNameCase);
}
}
public enum GroupScopeValues : int
{

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices.AccountManagement;
using System.IO;
using System.Linq;
@@ -24,6 +25,7 @@ namespace LiamNtfs
private cNtfsLogonInfo privLogonInfo = null;
public PrincipalContext adContext = null;
public DirectoryEntry directoryEntry = null;
public string EffectiveDomainController { get; private set; } = null;
public Exception LastException { get; private set; } = null;
public string LastErrorMessage { get; private set; } = null;
@@ -49,8 +51,12 @@ namespace LiamNtfs
//TODO: remove dummy delay?
await Task.Delay(0);
ResetError();
adContext = new PrincipalContext(ContextType.Domain, LogonInfo.Domain, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
var ldapPath = $"LDAP://{LogonInfo.Domain}/{LogonInfo.TargetGroupPath}";
var adServer = ResolveEffectiveDomainController(LogonInfo);
adContext = new PrincipalContext(ContextType.Domain, adServer, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
EffectiveDomainController = adContext.ConnectedServer ?? adServer;
LogEntry($"NTFS AD domain controller pinned to '{EffectiveDomainController}' for domain '{LogonInfo.Domain}'.", LogLevels.Debug);
var ldapPath = $"LDAP://{EffectiveDomainController}/{LogonInfo.TargetGroupPath}";
directoryEntry = new DirectoryEntry
{
Path = ldapPath,
@@ -69,6 +75,70 @@ namespace LiamNtfs
return false;
}
private string ResolveEffectiveDomainController(cNtfsLogonInfo logonInfo)
{
var configuredDomainControllers = ParseDomainControllers(logonInfo?.DomainControllers);
foreach (var domainController in configuredDomainControllers)
{
if (CanConnectToDomainController(domainController, logonInfo))
return domainController;
LogEntry($"Configured NTFS AD domain controller '{domainController}' is not reachable. Trying next candidate.", LogLevels.Warning);
}
var pdc = TryGetPdcRoleOwner(logonInfo);
if (!string.IsNullOrWhiteSpace(pdc))
return pdc;
LogEntry($"Could not determine PDC emulator for domain '{logonInfo?.Domain}'. Falling back to domain locator.", LogLevels.Warning);
return logonInfo?.Domain;
}
private static IEnumerable<string> ParseDomainControllers(string domainControllers)
{
if (string.IsNullOrWhiteSpace(domainControllers))
return Enumerable.Empty<string>();
return domainControllers
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i));
}
private bool CanConnectToDomainController(string domainController, cNtfsLogonInfo logonInfo)
{
try
{
using (var context = new PrincipalContext(ContextType.Domain, domainController, logonInfo.User, new NetworkCredential("", logonInfo.UserSecret).Password))
return !string.IsNullOrWhiteSpace(context.ConnectedServer);
}
catch (Exception E)
{
LogException(E, LogLevels.Debug);
return false;
}
}
private string TryGetPdcRoleOwner(cNtfsLogonInfo logonInfo)
{
try
{
var credentials = new DirectoryContext(
DirectoryContextType.Domain,
logonInfo.Domain,
logonInfo.User,
new NetworkCredential("", logonInfo.UserSecret).Password);
using (var domain = Domain.GetDomain(credentials))
return domain?.PdcRoleOwner?.Name;
}
catch (Exception E)
{
LogException(E, LogLevels.Debug);
return null;
}
}
private async Task<bool> privRelogon()
{
if (privLogonInfo == null)

View File

@@ -334,6 +334,7 @@ namespace LiamNtfs
public class cNtfsLogonInfo
{
public string Domain;
public string DomainControllers;
public string User;
public string UserSecret;
public string TargetNetworkName;

View File

@@ -447,7 +447,7 @@ namespace LiamWorkflowActivities
null,
null,
allowSharePathEnsure,
false,
ntfsArea is cLiamNtfsFolder,
simulateOnly);
if (ensureResult == null)
{

View File

@@ -4,6 +4,12 @@ setlocal EnableDelayedExpansion
set "ProductName=C4IT Light Identity Access Management"
set "SignTool=..\..\Common Code\Tools\signtool.exe"
set "TimeStamp=http://rfc3161timestamp.globalsign.com/advanced"
set "SignCertificateSubject=Consulting4IT GmbH"
set "SignCertificateEmail=info@consulting4it.de"
if defined LIAM_SIGN_CERT_SUBJECT (
set "SignCertificateSubject=%LIAM_SIGN_CERT_SUBJECT%"
)
REM Alle passenden Dateien in einer Variablen sammeln
set "FileList="
@@ -13,6 +19,11 @@ for %%F in (".\bin\Release\Liam*.dll") do (
REM SignTool mit allen gesammelten Dateien aufrufen
echo Signing all matching files at once...
call "%SignTool%" sign /a /tr %TimeStamp% /td SHA256 /fd SHA256 /d "%ProductName%" !FileList!
echo Expected signer: %SignCertificateSubject% ^<%SignCertificateEmail%^>
if defined LIAM_SIGN_CERT_THUMBPRINT (
call "%SignTool%" sign /sha1 "%LIAM_SIGN_CERT_THUMBPRINT%" /tr %TimeStamp% /td SHA256 /fd SHA256 /d "%ProductName%" !FileList!
) else (
call "%SignTool%" sign /n "%SignCertificateSubject%" /tr %TimeStamp% /td SHA256 /fd SHA256 /d "%ProductName%" !FileList!
)
pause

View File

@@ -4,6 +4,12 @@ setlocal EnableDelayedExpansion
set "ProductName=C4IT Light Identity Access Management"
set "SignTool=..\..\Common Code\Tools\signtool.exe"
set "TimeStamp=http://rfc3161timestamp.globalsign.com/advanced"
set "SignCertificateSubject=Consulting4IT GmbH"
set "SignCertificateEmail=info@consulting4it.de"
if defined LIAM_SIGN_CERT_SUBJECT (
set "SignCertificateSubject=%LIAM_SIGN_CERT_SUBJECT%"
)
set "FileList="
@@ -24,6 +30,11 @@ if not defined FileList (
)
echo Signing all matching files at once...
call "%SignTool%" sign /a /tr %TimeStamp% /td SHA256 /fd SHA256 /d "%ProductName%" !FileList!
echo Expected signer: %SignCertificateSubject% ^<%SignCertificateEmail%^>
if defined LIAM_SIGN_CERT_THUMBPRINT (
call "%SignTool%" sign /sha1 "%LIAM_SIGN_CERT_THUMBPRINT%" /tr %TimeStamp% /td SHA256 /fd SHA256 /d "%ProductName%" !FileList!
) else (
call "%SignTool%" sign /n "%SignCertificateSubject%" /tr %TimeStamp% /td SHA256 /fd SHA256 /d "%ProductName%" !FileList!
)
pause

253
README.md Normal file
View File

@@ -0,0 +1,253 @@
# LIAM
## Naming Conventions fuer NTFS-Gruppen
NTFS-Namenskonventionen bestehen aus `NamingTemplate`, `DescriptionTemplate` und `Wildcard`. Die Templates werden beim Erzeugen oder Sicherstellen von AD-Gruppen materialisiert. Der `Wildcard` ist eine regulaere Expression und wird beim Auslesen der ACLs verwendet, um vorhandene Gruppen wieder einer Rolle zuzuordnen.
Die wichtigsten Eingaben fuer die Ersetzung sind:
| Quelle | Beispiel |
| --- | --- |
| `RootPath` | `\\SRVWSM001.imagoverum.com\file_shares\share2` |
| Aktuelle DataArea | `\\SRVWSM001.imagoverum.com\file_shares\share2\test33` |
| `CustomTags` | `Filesystem_GroupGlobalTag=UG`, `Filesystem_GroupDomainLocalTag=FS`, `Filesystem_GroupOwnerTag=_OW` |
| Rolle / Scope | z. B. `Owner` und `DomainLocal` |
### Standard-Platzhalter
| Platzhalter | Wirkung | Beispielwert bei Root `\\server\file_shares\share2` und DataArea `...\share2\test33` |
| --- | --- | --- |
| `{{NAME}}` | Name des aktuellen Ordners oder Shares. | `test33` |
| `{{RELATIVEPATH}}` | Relativer Pfad der DataArea unterhalb des `RootPath`, mit Sanitizing und konfiguriertem Segmenttrenner. | `test33` |
| `{{RELATIVEPATH(0)}}` | Letztes relatives Pfadsegment. | `test33` |
| `{{RELATIVEPATH(1)}}` | Die letzten zwei relativen Pfadsegmente. Bei weniger Segmenten werden alle vorhandenen verwendet. | z. B. `team1_test33` |
| `{{ROOT_SERVER}}` | Server-/Namespace-Teil des UNC-RootPath. | `server` |
| `{{ROOT_NAME}}` | Letztes Segment des RootPath. | `share2` |
| `{{ROOT_PATH}}` | Alle RootPath-Segmente ohne Server, mit Segmenttrenner verbunden. | `file_shares_share2` |
| `{{ROOT_PATH(1)}}` | Letztes RootPath-Segment. | `share2` |
| `{{ROOT_PATH(2)}}` | Letzte zwei RootPath-Segmente. | `file_shares_share2` |
| `{{ROOT_SEGMENT(0)}}` | RootPath-Segment per 0-basierter Position, ohne Server. | `file_shares` |
| `{{ROOT_SEGMENT(1)}}` | Zweites RootPath-Segment. | `share2` |
`{{RELATIVEPATH(n)}}` zaehlt von hinten: `0` ist das letzte Segment, `1` sind die letzten zwei Segmente, `2` die letzten drei Segmente usw. `{{ROOT_PATH(n)}}` verwendet dagegen die letzten `n` Segmente des RootPath.
Wenn die aktuelle DataArea dem `RootPath` selbst entspricht, ist `{{RELATIVEPATH}}` leer. `{{NAME}}` ist dann der Name des RootPath, also z. B. `share2` oder `LEI.01.test`.
### Rollen- und Scope-Platzhalter
Diese Platzhalter werden aus Rolle, Scope und `CustomTags` aufgebaut:
| Platzhalter | Wirkung | Typische Werte |
| --- | --- | --- |
| `{{PREFIX}}` | Gruppenprefix aus `Filesystem_GroupPrefixTag`, fallback auf `ADGroupPrefix`. | `ACL`, `FS` |
| `{{SCOPETAG}}` | Scope-Tag. Bei `Global` aus `Filesystem_GroupGlobalTag`, bei `DomainLocal` aus `Filesystem_GroupDomainLocalTag`. | `UG`, `FS`, `G`, `DL` |
| `{{GROUPTYPEPOSTFIX}}` | Rollen-Postfix. Owner/Write/Read/Traverse verwenden die jeweiligen `Filesystem_Group*Tag` Werte. | `_OW`, `_RW`, `_R`, `_T` |
| `{{_LOOP}}` | Optionaler Eindeutigkeitszaehler. Beim ersten Versuch leer, danach `_1`, `_2`, usw. | leer, `_1`, `_2` |
| `{{LOOP}}` | Variante ohne Trennzeichen. Beim ersten Versuch leer, danach `1`, `2`, usw. | leer, `1`, `2` |
Der Loop-Platzhalter ist flexibel: Alles innerhalb der geschweiften Klammern, das `LOOP` enthaelt, wird als Loop-Tag behandelt. `{{-LOOP}}` wird beim ersten Versuch leer und danach z. B. `-1`.
### CustomTags
Alle Eintraege aus `CustomTags` koennen ebenfalls direkt verwendet werden. Die Schreibweise muss exakt zum Key passen.
Beispiele:
```text
{{ADGroupPrefix}}_{{RELATIVEPATH}}{{GROUPTYPEPOSTFIX}}
{{Filesystem_GroupGlobalTag}}_{{ROOT_NAME}}_{{NAME}}{{GROUPTYPEPOSTFIX}}
{{Filesystem_GroupDomainLocalTag}}_{{ROOT_PATH(1)}}_{{RELATIVEPATH}}{{GROUPTYPEPOSTFIX}}
```
### Beispiele fuer NamingTemplate
Share-basierte Gruppen nur mit Share-Name:
```text
{{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
```
Bei `RootPath=\\intra.brkr.corp\File_Shares\LEI.01.test`, Scope `DomainLocal`, `Filesystem_GroupDomainLocalTag=FS` und Rolle `Owner` entsteht:
```text
FS_LEI.01.TEST_OW
```
Gruppen fuer Unterordner relativ zum Root:
```text
{{SCOPETAG}}_{{RELATIVEPATH}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
```
Bei `RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2` und DataArea `...\share2\test33` entsteht fuer Owner:
```text
FS_TEST33_OW
```
Root-Share und Unterordner kombinieren:
```text
{{SCOPETAG}}_{{ROOT_NAME}}.{{RELATIVEPATH}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
```
Bei Root `share2` und Ordner `test33` entsteht:
```text
FS_SHARE2.TEST33_OW
```
Nur die letzten zwei relativen Pfadsegmente verwenden:
```text
{{SCOPETAG}}_{{RELATIVEPATH(1)}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
```
Bei `...\share2\team1\test33` entsteht:
```text
FS_TEAM1_TEST33_OW
```
Namespace-/Share-Bestandteile aus dem RootPath verwenden:
```text
{{SCOPETAG}}_{{ROOT_SEGMENT(0)}}_{{ROOT_SEGMENT(1)}}_{{NAME}}{{GROUPTYPEPOSTFIX}}
```
Bei Root `\\SRVWSM001.imagoverum.com\file_shares\share2` und Name `test33` entsteht:
```text
FS_FILE_SHARES_SHARE2_TEST33_OW
```
### Beispiele fuer AGP und AGDLP
Bei AGP liegen die Global-Gruppen direkt auf der ACL. Eine typische Konvention ist:
```text
NamingTemplate: {{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
Scope: Global
```
Bei AGDLP liegen die DomainLocal-Gruppen auf der ACL, die Global-Gruppen werden darin verschachtelt. Typisch ist:
```text
Global NamingTemplate: {{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
DomainLocal NamingTemplate: {{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
```
Mit `Filesystem_GroupGlobalTag=UG` und `Filesystem_GroupDomainLocalTag=FS` entstehen z. B.:
```text
UG_LEI.01.TEST_OW
FS_LEI.01.TEST_OW
```
In diesem Fall gehoert bei AGDLP die `FS_...` DomainLocal-Gruppe auf die NTFS-ACL; `UG_...` wird Mitglied der `FS_...` Gruppe.
### Wildcard-Regeln
`Wildcard` ist eine regulaere Expression. Sie muss nach Platzhalterersetzung zum erzeugten oder vorhandenen `sAMAccountName` passen.
Passendes Beispiel:
```text
^{{SCOPETAG}}_[a-zA-ZoeaeueOeAeUess0-9_\-\.]*{{GROUPTYPEPOSTFIX}}$
```
Mit `SCOPETAG=FS` und `GROUPTYPEPOSTFIX=_OW` matcht das:
```text
FS_LEI.01.TEST_OW
```
Nicht passend ist ein fuehrendes Leerzeichen:
```text
^ {{SCOPETAG}}_[a-zA-ZoeaeueOeAeUess0-9_\-\.]*{{GROUPTYPEPOSTFIX}}$
```
Dieser Regex erwartet nach `^` ein Leerzeichen und matcht deshalb nicht auf `FS_LEI.01.TEST_OW`.
Wenn eine Traverse-Naming-Convention keine Gruppe erzeugen soll, kann das `NamingTemplate` leer bleiben. Fuer Owner/Write/Read sollte der `Wildcard` nicht leer sein. Ein leerer Regex ist keine sinnvolle Matching-Regel, weil er technisch sehr breit matchen kann.
### Sanitizing, Laenge und Grossschreibung
Pfadbasierte Platzhalter wie `{{NAME}}`, `{{RELATIVEPATH}}`, `{{ROOT_PATH}}` und `{{ROOT_SEGMENT(n)}}` werden fuer AD-Gruppennamen bereinigt. Standardmaessig werden ungueltige Zeichen mit `_` ersetzt. Das Ersatzzeichen kann ueber `NtfsGroupNameSanitizeReplacement` geaendert oder entfernt werden.
Generierte AD-Gruppennamen werden standardmaessig in Grossbuchstaben geschrieben. Mit `PreserveNtfsAdGroupNameCase=1` bleibt die Schreibweise erhalten.
AD-Gruppennamen werden auf die maximale Laenge von 64 Zeichen begrenzt. Wenn ein Template mit `{{RELATIVEPATH}}` oder `{{NAME}}` zu lang wird, werden Pfadbestandteile gekuerzt. Fuer Loop-Platzhalter werden bis zu drei Ziffern reserviert.
## AdditionalParameters / AdditionalConfiguration
Provider-spezifische Zusatzparameter werden in Matrix42 am DataArea-Collector ueber das Fragment `C4IT_GCC_DataArea_Collector_AdditionalAttributes` gepflegt. Pro Parameter wird ein Eintrag mit `Name` und `Value` angelegt.
Beispiel:
| Name | Value |
| --- | --- |
| `EnsureNtfsPermissionGroups` | `1` |
| `NtfsAdDomainControllers` | `dc01.contoso.local,dc02.contoso.local` |
Im Diagnose-JSON erscheinen diese Werte unter `AdditionalConfiguration`. Parameternamen werden ohne Beachtung der Gross-/Kleinschreibung gelesen. Boolean-Werte sind in der Regel aktiv, wenn der Wert `true`, `1` oder `yes` ist. Leere oder nicht vorhandene Werte deaktivieren den jeweiligen Schalter, sofern unten nichts anderes beschrieben ist.
### Allgemein
| Parameter | Provider | Werte | Wirkung |
| --- | --- | --- | --- |
| `WhatIf` | Workflow / alle Provider, soweit unterstuetzt | `true`, `1`, `yes` | Aktiviert den Simulationsmodus fuer Workflow-Pfade, die WhatIf unterstuetzen. Aktionen werden dann vorbereitet und protokolliert, aber nicht dauerhaft ausgefuehrt. |
### NTFS
| Parameter | Werte | Wirkung |
| --- | --- | --- |
| `EnsureNtfsPermissionGroups` | `true`, `1`, `yes` | Stellt beim Auslesen von NTFS-Ordnern automatisch fehlende AD-Berechtigungsgruppen und NTFS-ACLs sicher. |
| `EnsureNtfsPermissionGroupsForShares` | `true`, `1`, `yes` | Erweitert das automatische Ensure auf Share-DataAreas. Ohne diesen Parameter wird das automatische Ensure nur fuer Ordner ausgefuehrt. |
| `AllowManualNtfsPermissionEnsureForShares` | `true`, `1`, `yes` | Erlaubt die manuelle Ensure-Aktivitaet auch fuer Share-DataAreas. |
| `NtfsIncludePaths` | Pfadliste, getrennt mit `;`, &#124; oder Zeilenumbruechen | Beschraenkt die NTFS-Verarbeitung auf passende Pfade. Unterstuetzt relative Pfade unterhalb des RootPath, absolute UNC-Pfade und einfache Wildcards mit `*`. Wenn der Parameter leer ist, sind alle Pfade eingeschlossen. |
| `NtfsExcludePaths` | Pfadliste, getrennt mit `;`, &#124; oder Zeilenumbruechen | Schliesst passende Pfade von der NTFS-Verarbeitung aus. Excludes gewinnen gegen Includes. Unterstuetzt relative Pfade, absolute UNC-Pfade und einfache Wildcards mit `*`. |
| `NtfsTraverseBoundaryPath` | Relativer oder absoluter Pfad | Setzt eine Traverse-Grenze fuer die Traverse-Gruppenverarbeitung. Damit koennen Traverse-Gruppen ueber den eigentlichen Einsprung hinaus bis zu einer definierten Ebene sichergestellt werden. |
| `NtfsGroupNameSanitizeReplacement` | Zeichenfolge, z. B. `_`, `.`, leer, `none`, `remove`, `<empty>` | Legt fest, womit ungueltige Zeichen in dynamischen gruppennamenrelevanten Pfadbestandteilen ersetzt werden. Standard ist `_`. Mit leerem Wert oder `none`/`remove`/`<empty>` werden ungueltige Zeichen entfernt und Pfadsegmente ohne Trennzeichen verbunden. |
| `PreserveNtfsAdGroupNameCase` | `true`, `1`, `yes` | Unterbindet das automatische Uppercase fuer generierte NTFS-AD-Gruppennamen. Ohne diesen Parameter werden generierte Gruppennamen wie bisher in Grossbuchstaben erzeugt. |
| `ForceStrictAdGroupNames` | `true`, `1`, `yes` | Erzwingt strikte AD-Gruppennamen. Wildcard-/ACL-basierte Wiederverwendung abweichender bestehender Gruppen wird damit eingeschraenkt; es werden nur exakt passende konfigurierte oder generierte Namen verwendet. |
| `NtfsAdDomainControllers` | Kommagetrennte DC-Liste, z. B. `dc01.contoso.local,dc02.contoso.local` | Pinnt NTFS-AD-Operationen auf einen Domain Controller. Der erste erreichbare DC wird verwendet. Wenn kein Eintrag erreichbar ist oder der Parameter fehlt, wird der PDC Emulator verwendet; danach faellt der Code auf die normale Domain-Locator-Logik zurueck. Der ausgewaehlte DC wird im Debug-Log protokolliert. |
Beispiele:
```text
EnsureNtfsPermissionGroups=1
EnsureNtfsPermissionGroupsForShares=1
NtfsIncludePaths=Finance\*;HR\Reports
NtfsExcludePaths=*\_archive\*
NtfsTraverseBoundaryPath=\\fileserver\file_shares
NtfsGroupNameSanitizeReplacement=.
PreserveNtfsAdGroupNameCase=1
NtfsAdDomainControllers=dc01.contoso.local,dc02.contoso.local
```
### Active Directory
| Parameter | Werte | Wirkung |
| --- | --- | --- |
| `AdDomainControllers` | Kommagetrennte DC-Liste, z. B. `dc01.contoso.local,dc02.contoso.local` | Pinnt Active-Directory-Provider-Operationen auf einen Domain Controller. Der erste erreichbare DC wird verwendet. Wenn kein Eintrag erreichbar ist oder der Parameter fehlt, wird der PDC Emulator verwendet; danach faellt der Code auf die normale Domain-Locator-Logik zurueck. Der ausgewaehlte DC wird im Debug-Log protokolliert. |
| `ActiveDirectoryDomainControllers` | Kommagetrennte DC-Liste | Alias/Fallback fuer `AdDomainControllers`, wenn `AdDomainControllers` nicht gesetzt ist. |
Beispiel:
```text
AdDomainControllers=dc01.contoso.local,dc02.contoso.local
```
### Microsoft Teams
| Parameter | Werte | Wirkung |
| --- | --- | --- |
| `WithoutPrivateChannels` | `true`, `1` | Private Channels werden beim Teams-Provider nicht beruecksichtigt. |
### Hinweise zur Pfad- und Listen-Syntax
`NtfsIncludePaths` und `NtfsExcludePaths` verwenden `;`, &#124; oder Zeilenumbrueche als Trenner. Kommas sind dort Teil des Werts. Die Domain-Controller-Parameter verwenden dagegen eine kommagetrennte Prioritaetsliste.
Pfadfilter koennen relativ zum konfigurierten NTFS-RootPath oder als absolute UNC-Pfade angegeben werden. Einfache Wildcards mit `*` sind moeglich.

View File

@@ -7,5 +7,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2026, Consulting4IT GmbH, Germany")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyInformationalVersion("3.3.0")]
[assembly: AssemblyVersion("3.3.0")]
[assembly: AssemblyInformationalVersion("3.3.2")]
[assembly: AssemblyVersion("3.3.2")]

View File

@@ -107,6 +107,194 @@ Damit kann die Filterung nicht einfach durch direktes Laden einer UID umgangen w
Die Path-Policy ist also klassifizierungsunabhaengig, das Berechtigungs-Handling selbst aber bewusst nicht.
### 7. Automatisches Permission-Ensure und Traverse
`EnsureNtfsPermissionGroups` wird ebenfalls ueber `AdditionalConfiguration` gesteuert. Die Werte kommen aus `C4IT_GCC_DataArea_Collector_AdditionalAttributes` und werden beim Provider-Aufbau in `AdditionalConfiguration` uebernommen.
Wenn `EnsureNtfsPermissionGroups=1` gesetzt ist, wird beim Laden von NTFS-Folder-DataAreas der Soll-Zustand fuer Berechtigungsgruppen sichergestellt:
- Owner-/Write-/Read-Gruppen werden angelegt oder wiederverwendet
- fehlende NTFS-ACLs werden auf dem Zielordner gesetzt
- Traverse-Gruppen werden analog zur Ordner-Neuanlage verarbeitet
Damit ist der nachtraegliche Ensure-Pfad fachlich mit der bestehenden Ordner-Neuanlage gleichgezogen. Share-Pfade bleiben gesondert ueber `EnsureNtfsPermissionGroupsForShares` behandelt; Traverse wird dabei nicht implizit fuer Shares erweitert.
### 8. Optionale Traverse-Boundary
Die neue Einstellung `NtfsTraverseBoundaryPath` ist optional und wird ebenfalls aus `AdditionalConfiguration` gelesen.
Ohne `NtfsTraverseBoundaryPath` bleibt die bestehende Traverse-Reichweite unveraendert. Die Verarbeitung folgt dann der bisherigen `baseFolder`-/`createTraverseGroupLvl`-Logik der Ordner-Neuanlage.
Mit `NtfsTraverseBoundaryPath` kann die sichtbare Parent-Kette explizit erweitert werden. Die Traverse-Verarbeitung laeuft dann vom Parent des Zielordners bis inklusive dieser Boundary.
Beispiel:
```text
RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2
EnsureNtfsPermissionGroups=1
NtfsTraverseBoundaryPath=\\SRVWSM001.imagoverum.com\file_shares
```
Fuer den Zielordner:
```text
\\SRVWSM001.imagoverum.com\file_shares\share2\test33
```
werden Traverse-Gruppen und Parent-ACLs fuer folgende Pfade sichergestellt:
- `\\SRVWSM001.imagoverum.com\file_shares\share2`
- `\\SRVWSM001.imagoverum.com\file_shares`
Nicht verarbeitet wird der Serverroot `\\SRVWSM001.imagoverum.com`.
Die Boundary muss ein Parent-Pfad des Zielordners sein und erreichbar sein. Ist das nicht der Fall, bricht der Ensure-/Create-Vorgang mit einer klaren Fehlermeldung ab, bevor Gruppen oder ACLs veraendert werden.
### 9. Traverse-Naming-Platzhalter
Fuer Traverse-Naming-Conventions gibt es zusaetzliche optionale Platzhalter:
- `{{TRAVERSE_NAME}}`: Name des aktuell verarbeiteten Traverse-Parents, z.B. `share2`
- `{{TRAVERSE_VISIBLEPATH}}`: sichtbarer Parent-Pfad ab dem Parent der Boundary, segmentweise mit `_`, z.B. `file_shares_share2`
Bestehende Platzhalter wie `{{NAME}}` und `{{RELATIVEPATH}}` bleiben unveraendert und behalten ihre bisherige Bedeutung.
Beispiel fuer eine Traverse-Namenskonvention:
```text
{{ADGroupPrefix}}_{{SCOPETAG}}_{{TRAVERSE_VISIBLEPATH}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
```
Bei:
```text
ADGroupPrefix=ACL
Filesystem_GroupGlobalTag=G
Filesystem_GroupTraverseTag=_T
```
entstehen daraus z.B.:
```text
ACL_G_FILE_SHARES_T
ACL_G_FILE_SHARES_SHARE2_T
```
Wenn das Traverse-`NamingTemplate` leer ist, ist das kein Fehler. Es wird dann keine neue Traverse-Gruppe angelegt. Bestehende Gruppen werden aber weiterhin ueber ACLs und, sofern gepflegt, ueber `Wildcard` gesucht und konfiguriert. Sind `NamingTemplate` und `Wildcard` leer, ist die Traverse-Verarbeitung fuer diesen Parent ein No-op.
Der Scope von Traverse-Gruppen wird aus der NTFS-Gruppenstrategie abgeleitet:
- `Ntfs_AGP`: Traverse-Gruppen werden als Global-Gruppen erstellt
- `Ntfs_AGDLP`: Traverse-Gruppen werden als DomainLocal-Gruppen erstellt
Wenn mehrere Traverse-Naming-Conventions vorhanden sind, wird die zur Strategie passende Konvention bevorzugt. Ist keine passende Konvention vorhanden, wird die vorhandene Traverse-Konvention weiterverwendet, der Scope aber trotzdem strategy-driven gesetzt.
### 10. Root-Path-Platzhalter
Naming Conventions koennen zusaetzlich Bestandteile des konfigurierten `RootPath` verwenden. Die Platzhalter funktionieren in `NamingTemplate`, `DescriptionTemplate` und `Wildcard`.
Fuer:
```text
RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2
Zielpfad=\\SRVWSM001.imagoverum.com\file_shares\share2\test33
```
stehen folgende Root-Platzhalter zur Verfuegung:
- `{{ROOT_SERVER}}`: Serveranteil, z.B. `SRVWSM001.imagoverum.com`
- `{{ROOT_NAME}}`: letzter Root-Segmentname, z.B. `share2`
- `{{ROOT_PATH}}`: alle Root-Segmente nach dem Server, z.B. `file_shares_share2`
- `{{ROOT_PATH(1)}}`: die letzten `n` Root-Segmente, z.B. `share2`
- `{{ROOT_PATH(2)}}`: z.B. `file_shares_share2`
- `{{ROOT_SEGMENT(0)}}`: erstes Root-Segment nach dem Server, z.B. `file_shares`
- `{{ROOT_SEGMENT(1)}}`: zweites Root-Segment nach dem Server, z.B. `share2`
Root-Segmente werden wie Ordnersegmente sanitisiert. Leerzeichen und Bindestriche werden standardmaessig zu `_`. Nicht vorhandene `ROOT_SEGMENT(n)`-Werte werden zu einem leeren String. Wenn `ROOT_PATH(n)` mehr Segmente anfordert als vorhanden sind, werden alle vorhandenen Root-Segmente verwendet.
Beispiel:
```text
{{ADGroupPrefix}}_{{ROOT_NAME}}.{{NAME}}{{GROUPTYPEPOSTFIX}}
```
ergibt fuer die Owner-Gruppe des Zielordners:
```text
ACL_SHARE2.TEST33_O
```
Alternativ mit Namespace-/Root-Anteil:
```text
{{ADGroupPrefix}}_{{ROOT_PATH(2)}}.{{NAME}}{{GROUPTYPEPOSTFIX}}
```
ergibt:
```text
ACL_FILE_SHARES_SHARE2.TEST33_O
```
Die bestehenden Platzhalter `{{NAME}}`, `{{RELATIVEPATH}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}` bleiben unveraendert.
### 11. Konfigurierbares Sanitizing und Gross-/Kleinschreibung fuer NTFS-Gruppennamen
Die Normalisierung der dynamischen Pfadbestandteile wird ueber `AdditionalConfiguration` gesteuert. Die Werte kommen wie `EnsureNtfsPermissionGroups` aus `C4IT_GCC_DataArea_Collector_AdditionalAttributes`.
`NtfsGroupNameSanitizeReplacement` steuert das Ersatz-/Trennzeichen fuer dynamische Pfadbestandteile:
- nicht gesetzt: AD-kritische Zeichen werden durch `_` ersetzt und Pfadsegmente werden mit `_` verbunden
- gesetzt auf z.B. `.`: AD-kritische Zeichen werden durch `.` ersetzt und Pfadsegmente werden mit `.` verbunden
- gesetzt auf einen leeren Wert, `<empty>`, `empty`, `none` oder `remove`: AD-kritische Zeichen werden entfernt und Pfadsegmente ohne Trennzeichen verbunden
Als AD-kritisch gelten in dynamischen Pfadbestandteilen derzeit Whitespace, Bindestrich, Steuerzeichen sowie `/ \ [ ] : ; | = , + * ? < > @ ( ) ' "`. Diese Zeichen sind fuer AD-`sAMAccountName`, LDAP-DNs/Search-Filter oder Entra-/Graph-kompatible Gruppennamen problematisch. `.` und `_` bleiben erhalten.
Die Einstellung wirkt auf `{{NAME}}`, `{{RELATIVEPATH}}`, `{{ROOT_*}}`, `{{TRAVERSE_NAME}}` und `{{TRAVERSE_VISIBLEPATH}}`. Sie aendert nicht die statischen Zeichen, die direkt im Naming Template stehen. Soll z.B. zwischen Root und Ordner immer ein Punkt stehen, bleibt der Punkt Bestandteil des Templates.
Beispiel:
```text
RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2
Zielpfad=\\SRVWSM001.imagoverum.com\file_shares\share2\test-33
NamingTemplate={{ADGroupPrefix}}_{{ROOT_NAME}}.{{NAME}}{{GROUPTYPEPOSTFIX}}
NtfsGroupNameSanitizeReplacement=
```
ergibt bei deaktivierter automatischer Grossschreibung:
```text
ACL_share2.test33_O
```
`PreserveNtfsAdGroupNameCase=1` unterbindet die bisher automatische Grossschreibung der erzeugten AD-Gruppennamen. Ohne diesen Schalter bleibt das bisherige Verhalten erhalten und die generierten CN-/sAMAccountName-Werte werden in Grossbuchstaben erzeugt.
### 12. Domain-Controller-Pinning fuer direkte AD-Readbacks
Der NTFS-Provider pinnt seine AD-Zugriffe auf einen konkreten Domain Controller, damit neu angelegte Gruppen unmittelbar im gleichen oder in einem direkt folgenden Workflow-Lauf wieder gefunden werden koennen. Ohne Pinning kann Windows bei getrennten WF-Instanzen unterschiedliche DCs auswaehlen; bei langen AD-Replikationsintervallen waeren frisch angelegte Gruppen dann auf dem zweiten DC noch nicht sichtbar.
Standardverhalten ohne Konfiguration:
- der Provider ermittelt automatisch den PDC Emulator der Domain
- alle NTFS-AD-Zugriffe innerhalb des Provider-Laufs verwenden diesen DC
- der verwendete DC wird einmal beim AD-Logon im Debug-Log ausgegeben
Optional kann ueber `AdditionalConfiguration` eine priorisierte, kommagetrennte DC-Liste gesetzt werden:
```text
NtfsAdDomainControllers=dc01.imagoverum.com,dc02.imagoverum.com
```
Der Provider testet die Eintraege in Reihenfolge. Der erste erreichbare DC wird verwendet. Wenn kein konfigurierter DC erreichbar ist, faellt der Provider auf den automatisch ermittelten PDC Emulator zurueck. Wenn auch dieser nicht ermittelt werden kann, wird wie bisher die Domain selbst verwendet und damit wieder der Windows-DC-Locator genutzt.
Die gleiche Logik gilt fuer den ActiveDirectory-Provider. Dort koennen die DCs ueber `AdDomainControllers` oder alternativ `ActiveDirectoryDomainControllers` gesetzt werden:
```text
AdDomainControllers=dc01.imagoverum.com,dc02.imagoverum.com
```
Auch hier wird ohne Konfiguration automatisch der PDC Emulator verwendet. Der tatsaechlich verwendete DC wird beim AD-Logon im Debug-Log ausgegeben.
## Matching-Regeln
Empfohlene Semantik:

View File

@@ -37,6 +37,9 @@ Das bedeutet:
- jeder Ordner wird isoliert behandelt
- keine gemeinsame Voranalyse
- kein Caching ueber den gesamten Lauf
- Owner-/Write-/Read-Gruppen sowie Traverse-Gruppen werden analog zur Ordner-Neuanlage sichergestellt
- eine optionale Traverse-Grenze kann ueber `NtfsTraverseBoundaryPath` aus `AdditionalConfiguration` gesetzt werden
- das Sanitizing dynamischer Pfadbestandteile kann ueber `NtfsGroupNameSanitizeReplacement` angepasst werden; `PreserveNtfsAdGroupNameCase=1` unterbindet die automatische Grossschreibung neuer AD-Gruppennamen
### 2. Create-/Ensure-Pfad

View File

@@ -0,0 +1,265 @@
<#
.SYNOPSIS
Creates or uses a dedicated LIAM test account and delegates limited AD and NTFS rights for validation.
.DESCRIPTION
Use this script to verify whether the reduced LIAM service-user permissions are sufficient.
Run with -WhatIf first, then without -WhatIf, configure the account in LIAM, and execute the relevant workflows.
Requirements:
- RSAT ActiveDirectory module
- Run as an account allowed to create users and edit ACLs on the target OU and NTFS paths
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $true)]
[string]$SamAccountName,
[Parameter(Mandatory = $true)]
[string]$TargetGroupOuDN,
[string[]]$ReadSearchBaseDNs = @(),
[string[]]$NtfsReadAclPaths = @(),
[string[]]$NtfsManageAclPaths = @(),
[string[]]$NtfsCreateParentPaths = @(),
[switch]$CreateUser,
[switch]$GrantDeleteGroupObjects
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
Import-Module ActiveDirectory -ErrorAction Stop
function Get-SchemaGuid {
param(
[Parameter(Mandatory = $true)]
[string]$LdapDisplayName
)
$schemaNc = (Get-ADRootDSE).schemaNamingContext
$object = Get-ADObject -SearchBase $schemaNc `
-LDAPFilter "(lDAPDisplayName=$LdapDisplayName)" `
-Properties schemaIDGUID
if (-not $object) {
throw "Schema object not found: $LdapDisplayName"
}
return [Guid]::new([byte[]]$object.schemaIDGUID)
}
function Add-LiamAdAccessRule {
param(
[Parameter(Mandatory = $true)]
[string]$TargetDN,
[Parameter(Mandatory = $true)]
[System.Security.Principal.IdentityReference]$Identity,
[Parameter(Mandatory = $true)]
[System.DirectoryServices.ActiveDirectoryRights]$Rights,
[Parameter(Mandatory = $true)]
[System.Security.AccessControl.AccessControlType]$AccessType,
[Guid]$ObjectType = [Guid]::Empty,
[System.DirectoryServices.ActiveDirectorySecurityInheritance]$Inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None,
[Guid]$InheritedObjectType = [Guid]::Empty
)
$entry = [ADSI]"LDAP://$TargetDN"
$acl = $entry.ObjectSecurity
if ($InheritedObjectType -ne [Guid]::Empty) {
$rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
$Identity,
$Rights,
$AccessType,
$ObjectType,
$Inheritance,
$InheritedObjectType
)
}
elseif ($ObjectType -ne [Guid]::Empty) {
$rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
$Identity,
$Rights,
$AccessType,
$ObjectType
)
}
else {
$rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
$Identity,
$Rights,
$AccessType,
$Inheritance
)
}
$acl.AddAccessRule($rule)
if ($PSCmdlet.ShouldProcess($TargetDN, "Add AD ACL: $Rights / $ObjectType / $Inheritance")) {
$entry.ObjectSecurity = $acl
$entry.CommitChanges()
}
}
function Grant-LiamNtfsRights {
param(
[Parameter(Mandatory = $true)]
[string]$Path,
[Parameter(Mandatory = $true)]
[string]$Account,
[Parameter(Mandatory = $true)]
[System.Security.AccessControl.FileSystemRights]$Rights,
[System.Security.AccessControl.InheritanceFlags]$InheritanceFlags = "ContainerInherit,ObjectInherit",
[System.Security.AccessControl.PropagationFlags]$PropagationFlags = "None"
)
if (-not (Test-Path -LiteralPath $Path)) {
throw "Path not found: $Path"
}
$acl = Get-Acl -LiteralPath $Path
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(
$Account,
$Rights,
$InheritanceFlags,
$PropagationFlags,
[System.Security.AccessControl.AccessControlType]::Allow
)
$acl.AddAccessRule($rule)
if ($PSCmdlet.ShouldProcess($Path, "Grant NTFS rights '$Rights' to '$Account'")) {
Set-Acl -LiteralPath $Path -AclObject $acl
}
}
$domain = Get-ADDomain
$netbiosName = $domain.NetBIOSName
$accountName = "$netbiosName\$SamAccountName"
if ($CreateUser) {
$existingUser = Get-ADUser -LDAPFilter "(sAMAccountName=$SamAccountName)" -ErrorAction SilentlyContinue
if (-not $existingUser) {
$password = Read-Host "Password for $SamAccountName" -AsSecureString
if ($PSCmdlet.ShouldProcess($SamAccountName, "Create AD user")) {
New-ADUser `
-SamAccountName $SamAccountName `
-Name $SamAccountName `
-AccountPassword $password `
-Enabled $true `
-PasswordNeverExpires $true `
-ChangePasswordAtLogon $false
}
}
}
$user = Get-ADUser -Identity $SamAccountName
$identity = $user.SID
$groupClassGuid = Get-SchemaGuid "group"
$attributeNames = @(
"cn",
"sAMAccountName",
"displayName",
"groupType",
"description",
"managedBy",
"member"
)
$attributeGuids = @{}
foreach ($name in $attributeNames) {
$attributeGuids[$name] = Get-SchemaGuid $name
}
Add-LiamAdAccessRule `
-TargetDN $TargetGroupOuDN `
-Identity $identity `
-Rights ([System.DirectoryServices.ActiveDirectoryRights]"ListChildren,ReadProperty") `
-AccessType Allow `
-Inheritance All
Add-LiamAdAccessRule `
-TargetDN $TargetGroupOuDN `
-Identity $identity `
-Rights CreateChild `
-AccessType Allow `
-ObjectType $groupClassGuid
if ($GrantDeleteGroupObjects) {
Add-LiamAdAccessRule `
-TargetDN $TargetGroupOuDN `
-Identity $identity `
-Rights DeleteChild `
-AccessType Allow `
-ObjectType $groupClassGuid
}
foreach ($attributeName in $attributeNames) {
Add-LiamAdAccessRule `
-TargetDN $TargetGroupOuDN `
-Identity $identity `
-Rights WriteProperty `
-AccessType Allow `
-ObjectType $attributeGuids[$attributeName] `
-Inheritance Descendents `
-InheritedObjectType $groupClassGuid
}
foreach ($readBase in $ReadSearchBaseDNs) {
Add-LiamAdAccessRule `
-TargetDN $readBase `
-Identity $identity `
-Rights ([System.DirectoryServices.ActiveDirectoryRights]"ListChildren,ReadProperty") `
-AccessType Allow `
-Inheritance All
}
foreach ($path in $NtfsReadAclPaths) {
Grant-LiamNtfsRights `
-Path $path `
-Account $accountName `
-Rights ([System.Security.AccessControl.FileSystemRights]"ReadAndExecute,ReadPermissions")
}
foreach ($path in $NtfsManageAclPaths) {
Grant-LiamNtfsRights `
-Path $path `
-Account $accountName `
-Rights ([System.Security.AccessControl.FileSystemRights]"ReadAndExecute,ReadPermissions,ChangePermissions")
}
foreach ($path in $NtfsCreateParentPaths) {
Grant-LiamNtfsRights `
-Path $path `
-Account $accountName `
-Rights ([System.Security.AccessControl.FileSystemRights]"ReadAndExecute,ReadPermissions,CreateDirectories") `
-InheritanceFlags None `
-PropagationFlags None
}
Write-Host "Delegation finished for $accountName"
Write-Host "Suggested validation:"
Write-Host "1. Configure this account as the LIAM provider credential."
Write-Host "2. Create AD service groups and add members."
Write-Host "3. Read NTFS data areas."
Write-Host "4. Ensure missing NTFS permission groups and ACL entries."
Write-Host "5. Verify that AD deletes and writes outside the target OU fail."