initial
This commit is contained in:
516
LIAMActiveDirectory/cActiveDirectoryBase.cs
Normal file
516
LIAMActiveDirectory/cActiveDirectoryBase.cs
Normal file
@@ -0,0 +1,516 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using C4IT.Logging;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace LiamAD
|
||||
{
|
||||
public class cActiveDirectoryBase
|
||||
{
|
||||
private cADLogonInfo privLogonInfo = null;
|
||||
public PrincipalContext adContext = null;
|
||||
public DirectoryEntry directoryEntry = null;
|
||||
public Exception LastException { get; private set; } = null;
|
||||
public string LastErrorMessage { get; private set; } = null;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void ResetError()
|
||||
{
|
||||
LastException = null;
|
||||
LastErrorMessage = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetErrorException(string Action, Exception E, LogLevels lev = LogLevels.Error)
|
||||
{
|
||||
LastException = E;
|
||||
LastErrorMessage = Action + ": " + E.Message;
|
||||
cLogManager.LogEntry(Action, lev);
|
||||
}
|
||||
|
||||
private async Task<bool> privLogonAsync(cADLogonInfo LogonInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
//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}";
|
||||
directoryEntry = new DirectoryEntry
|
||||
{
|
||||
Path = ldapPath,
|
||||
Username = LogonInfo.User,
|
||||
Password = new NetworkCredential(LogonInfo.User, LogonInfo.UserSecret).Password,
|
||||
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
|
||||
};
|
||||
return adContext != null;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
SetErrorException("exception error while ad login", E, LogLevels.Debug);
|
||||
cLogManager.LogException(E, LogLevels.Debug);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> privRelogon()
|
||||
{
|
||||
if (privLogonInfo == null)
|
||||
return false;
|
||||
var RetVal = await privLogonAsync(privLogonInfo);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
public async Task<bool> LogonAsync(cADLogonInfo LogonInfo)
|
||||
{
|
||||
var RetVal = await privLogonAsync(LogonInfo);
|
||||
if (RetVal == true)
|
||||
privLogonInfo = LogonInfo;
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
internal AuthorizationRuleCollection GetAccessControlList(string path)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
DirectoryInfo dADir = new DirectoryInfo(path);
|
||||
var dAACL = dADir.GetAccessControl();
|
||||
return dAACL.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier));
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal string resolveSid(string sid)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
return new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString();
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<cADCollectionBase> RequestSecurityGroupsListAsync(string groupFilter)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
var Result = privRequestSecurityGroupsListAsync(groupFilter);
|
||||
if (Result != null)
|
||||
{
|
||||
var RetVal = new cADCollectionBase(Result.Count);
|
||||
foreach (var Entry in Result)
|
||||
{
|
||||
var res = new cSecurityGroupResult(Entry);
|
||||
RetVal.Add(res);
|
||||
}
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<cSecurityGroupResult> privRequestSecurityGroupsListAsync(string groupFilter = null, string rawLDAPFilter = null)
|
||||
{
|
||||
ResetError();
|
||||
List<cSecurityGroupResult> securityGroups = new List<cSecurityGroupResult>();
|
||||
|
||||
if (String.IsNullOrEmpty(privLogonInfo.TargetGroupPath) ||
|
||||
(string.IsNullOrEmpty(groupFilter) && string.IsNullOrEmpty(rawLDAPFilter)))
|
||||
{
|
||||
return new List<cSecurityGroupResult>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ctx = adContext;
|
||||
var entry = directoryEntry;
|
||||
|
||||
using (DirectorySearcher dSearch = new DirectorySearcher(entry))
|
||||
{
|
||||
dSearch.Filter = string.IsNullOrEmpty(rawLDAPFilter) ? "(&(" + groupFilter + ")(objectClass=group))" : rawLDAPFilter;
|
||||
dSearch.PageSize = 100000;
|
||||
|
||||
SearchResultCollection sr = dSearch.FindAll();
|
||||
if (sr.Count > 0)
|
||||
{
|
||||
foreach (SearchResult k in sr)
|
||||
{
|
||||
var sid = new SecurityIdentifier(k.Properties["objectSid"][0] as byte[], 0).Value;
|
||||
var dn = k.Properties["distinguishedname"][0].ToString();
|
||||
|
||||
// Initialisieren Sie die managedBy-SID als null
|
||||
string managedBySid = null;
|
||||
|
||||
// Prüfen, ob das managedBy-Attribut existiert und nicht null ist
|
||||
if (k.Properties.Contains("managedBy") && k.Properties["managedBy"].Count > 0)
|
||||
{
|
||||
// managedBy-DN erhalten
|
||||
string managedByDn = k.Properties["managedBy"][0].ToString();
|
||||
|
||||
// Erstellen eines DirectoryEntry-Objekts für den managedBy-DN
|
||||
using (DirectoryEntry managedByEntry = new DirectoryEntry($"LDAP://{managedByDn}"))
|
||||
{
|
||||
if (managedByEntry.Properties.Contains("objectSid") && managedByEntry.Properties["objectSid"].Count > 0)
|
||||
{
|
||||
// SID des managedBy-Objekts erhalten
|
||||
managedBySid = new SecurityIdentifier(managedByEntry.Properties["objectSid"][0] as byte[], 0).Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Neues SecurityGroup-Objekt erstellen
|
||||
cSecurityGroupResult group = new cSecurityGroupResult()
|
||||
{
|
||||
ID = sid,
|
||||
Path = dn,
|
||||
DisplayName = k.Properties["Name"][0].ToString(),
|
||||
Description = k.Properties.Contains("Description") ? k.Properties["Description"][0].ToString() : string.Empty,
|
||||
Scope = (GroupScope)GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, sid).GroupScope,
|
||||
ManagedBySID = managedBySid
|
||||
};
|
||||
|
||||
securityGroups.Add(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cLogManager.LogException(e);
|
||||
return new List<cSecurityGroupResult>(securityGroups);
|
||||
}
|
||||
|
||||
return securityGroups;
|
||||
}
|
||||
|
||||
public class cADCollectionBase : SortedList<string, cADResultBase>
|
||||
{
|
||||
public cADCollectionBase() { }
|
||||
public cADCollectionBase(int n) : base(n) { }
|
||||
|
||||
public void Add(cADResultBase adr)
|
||||
{
|
||||
if (!this.ContainsKey(adr.ID))
|
||||
this.Add(adr.ID, adr);
|
||||
}
|
||||
}
|
||||
|
||||
public class cSecurityGroupResult : cADResultBase
|
||||
{
|
||||
public cSecurityGroupResult() { }
|
||||
public cSecurityGroupResult(cADResultBase b) : base(b)
|
||||
{
|
||||
this.ManagedBySID = (b as cSecurityGroupResult)?.ManagedBySID;
|
||||
}
|
||||
public GroupScope Scope { get; internal set; }
|
||||
public string ManagedBySID { get; internal set; }
|
||||
}
|
||||
public class cADUserResult : cADResultBase
|
||||
{
|
||||
public string GivenName { get; internal set; }
|
||||
public string SurName { get; internal set; }
|
||||
public string UserPrincipalName { get; internal set; }
|
||||
public string Email { get; internal set; }
|
||||
public cADUserResult() { }
|
||||
public cADUserResult(cADResultBase b) : base(b)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public cADUserResult(Principal Result) : base(Result)
|
||||
{
|
||||
UserPrincipalName = Result.UserPrincipalName;
|
||||
}
|
||||
|
||||
public GroupScope Scope { get; internal set; }
|
||||
}
|
||||
public class cADResultBase
|
||||
{
|
||||
public string ID { get; set; } = null;
|
||||
public string DisplayName { get; set; } = null;
|
||||
public string Path { get; set; } = null;
|
||||
public DateTime CreatedDate { get; set; } = DateTime.MinValue;
|
||||
public string Description { get; set; } = null;
|
||||
|
||||
public cADResultBase()
|
||||
{ }
|
||||
public cADResultBase(cADResultBase Result)
|
||||
{
|
||||
if (Result == null)
|
||||
return;
|
||||
|
||||
ID = Result.ID;
|
||||
DisplayName = Result.DisplayName;
|
||||
Description = Result.Description;
|
||||
Path = Result.Path;
|
||||
}
|
||||
public cADResultBase(Principal Result)
|
||||
{
|
||||
if (Result == null)
|
||||
return;
|
||||
|
||||
ID = Result.Sid.ToString();
|
||||
DisplayName = Result.DisplayName;
|
||||
Path = Result.DistinguishedName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchrones Abrufen des managedBy-Attributs einer AD-Gruppe anhand ihrer SID.
|
||||
/// Gibt den Distinguished Name (DN) des Managers zurück.
|
||||
/// </summary>
|
||||
/// <param name="groupSid">Die SID der AD-Gruppe.</param>
|
||||
/// <returns>Der DN des Managers oder null, falls nicht gefunden.</returns>
|
||||
public async Task<string> GetManagedByDnAsync(string dn)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Simuliert einen asynchronen Aufruf
|
||||
await Task.Yield();
|
||||
|
||||
using (var group = GroupPrincipal.FindByIdentity(adContext, IdentityType.DistinguishedName, dn))
|
||||
{
|
||||
if (group == null)
|
||||
{
|
||||
cLogManager.LogEntry($"Gruppe mit dn {dn} nicht gefunden.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Zugriff auf das underlying DirectoryEntry, um das managedBy-Attribut zu lesen
|
||||
var directoryEntry = group.GetUnderlyingObject() as DirectoryEntry;
|
||||
if (directoryEntry != null && directoryEntry.Properties.Contains("managedBy"))
|
||||
{
|
||||
var managedByValue = directoryEntry.Properties["managedBy"].Value as string;
|
||||
if (!string.IsNullOrEmpty(managedByValue))
|
||||
{
|
||||
return managedByValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLogManager.LogEntry($"managedBy-Attribut für Gruppe mit dn {dn} ist leer.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cLogManager.LogEntry($"Gruppe mit dn {dn} hat kein managedBy-Attribut.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
cLogManager.LogException(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchrones Abrufen der Mitglieder des Managers einer AD-Gruppe anhand des groupSid.
|
||||
/// Verwendet den DN des Managers.
|
||||
/// </summary>
|
||||
/// <param name="groupSid">Die SID der AD-Gruppe.</param>
|
||||
/// <returns>Eine cADCollectionBase mit den Mitgliedern oder null.</returns>
|
||||
public async Task<cADCollectionBase> GetManagedByMembersAsync(string groupSid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var managedByDn = await GetManagedByDnAsync(groupSid);
|
||||
if (!string.IsNullOrEmpty(managedByDn))
|
||||
{
|
||||
return await GetMembersByDnAsync(managedByDn);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLogManager.LogEntry($"Keine gültige managedBy DN für Gruppe mit SID {groupSid} gefunden.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
cLogManager.LogException(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchrones Abrufen der Mitglieder einer AD-Gruppe anhand des Distinguished Name (DN).
|
||||
/// </summary>
|
||||
/// <param name="dn">Der Distinguished Name der AD-Gruppe.</param>
|
||||
/// <returns>Eine cADCollectionBase mit den Mitgliedern oder null.</returns>
|
||||
public async Task<cADCollectionBase> GetMembersByDnAsync(string dn)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Simuliert einen asynchronen Aufruf
|
||||
await Task.Yield();
|
||||
|
||||
var result = privGetMembersByDnAsync(dn).ToList();
|
||||
if (result != null && result.Any())
|
||||
{
|
||||
var retVal = new cADCollectionBase(result.Count);
|
||||
foreach (var entry in result)
|
||||
{
|
||||
var res = new cADUserResult(entry);
|
||||
if (!string.IsNullOrEmpty(res.Path))
|
||||
retVal.Add(res);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLogManager.LogEntry($"Keine Mitglieder für Gruppe mit DN {dn} gefunden.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cLogManager.LogException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interne Methode zum Abrufen der Mitglieder einer AD-Gruppe anhand des Distinguished Name (DN).
|
||||
/// </summary>
|
||||
/// <param name="dn">Der Distinguished Name der AD-Gruppe.</param>
|
||||
/// <returns>Eine PrincipalSearchResult mit den Mitgliedern oder null.</returns>
|
||||
private PrincipalSearchResult<Principal> privGetMembersByDnAsync(string dn)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var group = GroupPrincipal.FindByIdentity(adContext, IdentityType.DistinguishedName, dn))
|
||||
{
|
||||
if (group == null)
|
||||
{
|
||||
cLogManager.LogEntry($"Gruppe mit DN {dn} nicht gefunden.");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return group.GetMembers(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cLogManager.LogException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchrones Abrufen der Mitglieder einer AD-Gruppe anhand ihrer SID.
|
||||
/// Diese Methode bleibt unverändert und kann weiterhin verwendet werden.
|
||||
/// </summary>
|
||||
/// <param name="sid">Die SID der AD-Gruppe.</param>
|
||||
/// <returns>Eine cADCollectionBase mit den Mitgliedern oder null.</returns>
|
||||
internal async Task<cADCollectionBase> GetMembersAsync(string sid)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Simuliert einen asynchronen Aufruf
|
||||
await Task.Yield();
|
||||
|
||||
var result = privGetMembersAsync(sid).ToList();
|
||||
if (result != null && result.Any())
|
||||
{
|
||||
var retVal = new cADCollectionBase(result.Count);
|
||||
foreach (var entry in result)
|
||||
{
|
||||
var res = new cADUserResult(entry);
|
||||
if (!string.IsNullOrEmpty(res.Path))
|
||||
retVal.Add(res);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLogManager.LogEntry($"Keine Mitglieder für Gruppe mit SID {sid} gefunden.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cLogManager.LogException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interne Methode zum Abrufen der Mitglieder einer AD-Gruppe anhand ihrer SID.
|
||||
/// Diese Methode bleibt unverändert und kann weiterhin verwendet werden.
|
||||
/// </summary>
|
||||
/// <param name="sid">Die SID der AD-Gruppe.</param>
|
||||
/// <returns>Eine PrincipalSearchResult mit den Mitgliedern oder null.</returns>
|
||||
private PrincipalSearchResult<Principal> privGetMembersAsync(string sid)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var group = GroupPrincipal.FindByIdentity(adContext, IdentityType.Sid, sid))
|
||||
{
|
||||
if (group == null)
|
||||
{
|
||||
cLogManager.LogEntry($"Gruppe mit SID {sid} nicht gefunden.");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return group.GetMembers(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
cLogManager.LogException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user