- update multiple LIAM projects and solution/config files - add LiamWorkflowDiagnostics app sources and generated outputs - include current workspace state (dependencies and build outputs)
942 lines
37 KiB
C#
942 lines
37 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Security;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Management.Automation;
|
||
using System.Management.Automation.Runspaces;
|
||
using C4IT.Logging;
|
||
using static C4IT.Logging.cLogManager;
|
||
using C4IT.Matrix42.ServerInfo;
|
||
using System.Text.RegularExpressions;
|
||
using LiamNtfs;
|
||
using System.DirectoryServices;
|
||
using System.Security.Principal;
|
||
|
||
namespace C4IT.LIAM
|
||
{
|
||
public class cLiamProviderExchange : cLiamProviderBase
|
||
{
|
||
public static Guid exchangeModuleId = new Guid("A1E213C3-6517-EA11-4881-000C2980FD95");
|
||
public readonly ExchangeManager exchangeManager;
|
||
internal readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||
|
||
private string exchangeUri;
|
||
private PSCredential credential;
|
||
private string organizationalUnit;
|
||
private string lastErrorCode = string.Empty;
|
||
private string lastErrorMessage;
|
||
private bool isLoggedOn = false;
|
||
|
||
public cLiamProviderExchange(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) :
|
||
base(LiamConfiguration, ProviderData)
|
||
{
|
||
exchangeUri = ProviderData.RootPath;
|
||
|
||
if (!string.IsNullOrEmpty(ProviderData.GroupPath))
|
||
organizationalUnit = ProviderData.GroupPath;
|
||
else
|
||
organizationalUnit = ProviderData.Domain;
|
||
|
||
// Credential erstellen
|
||
var securePassword = new SecureString();
|
||
foreach (char c in ProviderData.Credential.Secret)
|
||
{
|
||
securePassword.AppendChar(c);
|
||
}
|
||
credential = new PSCredential(ProviderData.Credential.Identification, securePassword);
|
||
// ExchangeManager initialisieren
|
||
exchangeManager = new ExchangeManager(this, exchangeUri, credential, ProviderData.Domain, organizationalUnit);
|
||
// AD-Zugriff initialisieren
|
||
var LI = new cNtfsLogonInfo()
|
||
{
|
||
Domain = Domain,
|
||
User = Credential?.Identification,
|
||
UserSecret = Credential?.Secret,
|
||
TargetGroupPath = this.GroupPath
|
||
};
|
||
|
||
// Asynchrone Initialisierung starten
|
||
_ = activeDirectoryBase.LogonAsync(LI).ConfigureAwait(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Extrahiert den GUID-Wert aus den Properties.
|
||
/// Zunächst wird versucht, "objectGUID" zu lesen – ist dieser leer, wird "GUID" verwendet.
|
||
/// </summary>
|
||
internal static string ExtractObjectGuid(dynamic properties)
|
||
{
|
||
// Erstversuch: objectGUID (wie in AD)
|
||
var value = properties["objectGUID"]?.Value;
|
||
if (value == null || string.IsNullOrEmpty(value.ToString()))
|
||
{
|
||
// Alternative: GUID (wie von den Exchange-Cmdlets zurückgegeben)
|
||
value = properties["GUID"]?.Value;
|
||
}
|
||
if (value is byte[] guidBytes)
|
||
return new Guid(guidBytes).ToString();
|
||
if (value is Guid guid)
|
||
return guid.ToString();
|
||
return value?.ToString() ?? string.Empty;
|
||
}
|
||
|
||
public string GetLastErrorCode()
|
||
{
|
||
return lastErrorCode;
|
||
}
|
||
|
||
private void ClearLastError()
|
||
{
|
||
lastErrorCode = string.Empty;
|
||
lastErrorMessage = string.Empty;
|
||
}
|
||
|
||
private void SetLastError(string code, string message)
|
||
{
|
||
lastErrorCode = string.IsNullOrWhiteSpace(code) ? "EXCH_UNKNOWN_ERROR" : code;
|
||
lastErrorMessage = message ?? string.Empty;
|
||
LogEntry($"[{lastErrorCode}] {lastErrorMessage}", LogLevels.Error);
|
||
}
|
||
|
||
public override async Task<bool> LogonAsync()
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
ClearLastError();
|
||
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||
{
|
||
SetLastError("EXCH_LOGON_LICENSE_INVALID", "License not valid or Exchange module not licensed");
|
||
return false;
|
||
}
|
||
|
||
try
|
||
{
|
||
var testMailboxes = exchangeManager.GetSharedMailboxes(
|
||
"Name -like '*'",
|
||
out string errorCode,
|
||
out string errorMessage);
|
||
if (testMailboxes == null)
|
||
{
|
||
SetLastError(errorCode, $"Failed to connect to Exchange: {errorMessage}");
|
||
isLoggedOn = false;
|
||
return false;
|
||
}
|
||
|
||
if (testMailboxes != null)
|
||
{
|
||
LogEntry("Successfully connected to Exchange", LogLevels.Info);
|
||
isLoggedOn = true;
|
||
ClearLastError();
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogException(ex);
|
||
SetLastError("EXCH_LOGON_EXCEPTION", $"Failed to connect to Exchange: {ex.Message}");
|
||
isLoggedOn = false;
|
||
return false;
|
||
}
|
||
|
||
SetLastError("EXCH_LOGON_FAILED", "Unknown error connecting to Exchange");
|
||
return false;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
SetLastError("EXCH_LOGON_EXCEPTION", $"Exception during Exchange logon: {E.Message}");
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override string GetLastErrorMessage()
|
||
{
|
||
return lastErrorMessage;
|
||
}
|
||
|
||
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
ClearLastError();
|
||
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||
{
|
||
SetLastError("EXCH_GET_DATAAREAS_LICENSE_INVALID", "License not valid or Exchange module not licensed");
|
||
return new List<cLiamDataAreaBase>();
|
||
}
|
||
|
||
if (!isLoggedOn && !await LogonAsync())
|
||
return null;
|
||
|
||
var DataAreas = new List<cLiamDataAreaBase>();
|
||
|
||
// Shared Mailboxes
|
||
var sharedMailboxes = exchangeManager.GetSharedMailboxes(
|
||
null,
|
||
out string sharedErrorCode,
|
||
out string sharedErrorMessage);
|
||
if (sharedMailboxes == null)
|
||
{
|
||
SetLastError(sharedErrorCode, $"Failed to read shared mailboxes: {sharedErrorMessage}");
|
||
return null;
|
||
}
|
||
|
||
foreach (var mailbox in sharedMailboxes)
|
||
{
|
||
var displayName = mailbox.Properties["DisplayName"]?.Value?.ToString();
|
||
var alias = mailbox.Properties["Alias"]?.Value?.ToString();
|
||
var primarySmtpAddress = mailbox.Properties["PrimarySmtpAddress"]?.Value?.ToString();
|
||
var objectGuid = ExtractObjectGuid(mailbox.Properties);
|
||
|
||
// Filterung via Regex
|
||
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||
!Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||
continue;
|
||
|
||
var exchangeMailbox = new cLiamExchangeSharedMailbox(this, displayName, primarySmtpAddress, alias, objectGuid);
|
||
DataAreas.Add(exchangeMailbox);
|
||
}
|
||
|
||
// Distribution Groups
|
||
var distributionGroups = exchangeManager.GetDistributionGroups(
|
||
null,
|
||
out string distErrorCode,
|
||
out string distErrorMessage);
|
||
if (distributionGroups == null)
|
||
{
|
||
SetLastError(distErrorCode, $"Failed to read distribution groups: {distErrorMessage}");
|
||
return null;
|
||
}
|
||
|
||
foreach (var group in distributionGroups)
|
||
{
|
||
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||
var alias = group.Properties["Alias"]?.Value?.ToString();
|
||
var primarySmtpAddress = group.Properties["PrimarySmtpAddress"]?.Value?.ToString();
|
||
var objectGuid = ExtractObjectGuid(group.Properties);
|
||
|
||
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||
!Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||
continue;
|
||
|
||
var exchangeGroup = new cLiamExchangeDistributionGroup(this, displayName, primarySmtpAddress, alias, objectGuid);
|
||
DataAreas.Add(exchangeGroup);
|
||
}
|
||
|
||
ClearLastError();
|
||
return DataAreas;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
SetLastError("EXCH_GET_DATAAREAS_EXCEPTION", E.Message);
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var dataType = cLIAMHelper.getUidItem(ref UID);
|
||
if (string.IsNullOrEmpty(dataType))
|
||
return null;
|
||
|
||
if (!int.TryParse(dataType, out int dataTypeInt))
|
||
return null;
|
||
|
||
var primarySmtpAddress = cLIAMHelper.getUidItem(ref UID);
|
||
if (string.IsNullOrEmpty(primarySmtpAddress))
|
||
return null;
|
||
|
||
if (!isLoggedOn && !await LogonAsync())
|
||
return null;
|
||
|
||
switch ((eLiamDataAreaTypes)dataTypeInt)
|
||
{
|
||
case eLiamDataAreaTypes.ExchangeSharedMailbox:
|
||
return await cLiamExchangeSharedMailbox.Load(this, primarySmtpAddress);
|
||
case eLiamDataAreaTypes.ExchangeDistributionGroup:
|
||
return await cLiamExchangeDistributionGroup.Load(this, primarySmtpAddress);
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
ClearLastError();
|
||
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||
{
|
||
SetLastError("EXCH_GET_SECURITYGROUPS_LICENSE_INVALID", "License not valid or Exchange module not licensed");
|
||
return new List<cLiamDataAreaBase>();
|
||
}
|
||
|
||
if (!isLoggedOn && !await LogonAsync())
|
||
return null;
|
||
|
||
var securityGroups = new List<cLiamDataAreaBase>();
|
||
var groups = exchangeManager.GetSecurityGroups(
|
||
groupFilter,
|
||
out string errorCode,
|
||
out string errorMessage);
|
||
if (groups == null)
|
||
{
|
||
SetLastError(errorCode, $"Failed to read security groups: {errorMessage}");
|
||
return null;
|
||
}
|
||
|
||
foreach (var group in groups)
|
||
{
|
||
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||
var sid = group.Properties["Sid"]?.Value?.ToString();
|
||
var dn = group.Properties["DistinguishedName"]?.Value?.ToString();
|
||
var objectGuid = ExtractObjectGuid(group.Properties);
|
||
|
||
if (!string.IsNullOrEmpty(this.GroupRegEx) &&
|
||
!Regex.Match(displayName, this.GroupRegEx).Success)
|
||
continue;
|
||
|
||
var securityGroup = new cLiamExchangeSecurityGroup(this, displayName, sid, dn, objectGuid);
|
||
securityGroups.Add(securityGroup);
|
||
}
|
||
|
||
ClearLastError();
|
||
return securityGroups;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
SetLastError("EXCH_GET_SECURITYGROUPS_EXCEPTION", E.Message);
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// Hilfsmethoden zur Interaktion mit Exchange
|
||
|
||
|
||
|
||
internal async Task<bool> AddMemberToGroup(string groupName, string member, bool isSharedMailbox)
|
||
{
|
||
try
|
||
{
|
||
if (isSharedMailbox)
|
||
exchangeManager.AddMailboxPermission(groupName, member);
|
||
else
|
||
exchangeManager.AddMemberToDistributionGroup(groupName, member);
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogException(ex);
|
||
lastErrorMessage = $"Error adding member to group: {ex.Message}";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
internal async Task<bool> RemoveMemberFromGroup(string groupName, string member, bool isSharedMailbox)
|
||
{
|
||
try
|
||
{
|
||
if (isSharedMailbox)
|
||
exchangeManager.RemoveMailboxPermission(groupName, member);
|
||
else
|
||
exchangeManager.RemoveMemberFromDistributionGroup(groupName, member);
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogException(ex);
|
||
lastErrorMessage = $"Error removing member from group: {ex.Message}";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public async Task<cLiamExchangeSecurityGroup> GetManagedByGroup(string groupDn)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
if (activeDirectoryBase.adContext == null)
|
||
{
|
||
LogEntry("Active Directory context not initialized", LogLevels.Error);
|
||
return null;
|
||
}
|
||
|
||
string ldapPath = $"LDAP://{groupDn}";
|
||
DirectoryEntry groupEntry = null;
|
||
try
|
||
{
|
||
groupEntry = new DirectoryEntry(
|
||
ldapPath,
|
||
this.Credential?.Identification,
|
||
this.Credential?.Secret,
|
||
AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
||
|
||
if (groupEntry.Properties.Contains("managedBy") && groupEntry.Properties["managedBy"].Value != null)
|
||
{
|
||
string managedByDn = groupEntry.Properties["managedBy"].Value.ToString();
|
||
string managedByLdapPath = $"LDAP://{managedByDn}";
|
||
using (DirectoryEntry managedByEntry = new DirectoryEntry(
|
||
managedByLdapPath,
|
||
this.Credential?.Identification,
|
||
this.Credential?.Secret,
|
||
AuthenticationTypes.Secure | AuthenticationTypes.Sealing))
|
||
{
|
||
if (managedByEntry.SchemaClassName == "group")
|
||
{
|
||
byte[] sidBytes = (byte[])managedByEntry.Properties["objectSid"].Value;
|
||
SecurityIdentifier sid = new SecurityIdentifier(sidBytes, 0);
|
||
string displayName = managedByEntry.Properties["displayName"]?.Value?.ToString()
|
||
?? managedByEntry.Properties["name"]?.Value?.ToString();
|
||
return new cLiamExchangeSecurityGroup(this, displayName, sid.Value, managedByDn, sid.Value);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogException(ex);
|
||
}
|
||
finally
|
||
{
|
||
groupEntry?.Dispose();
|
||
}
|
||
return null;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
}
|
||
|
||
public class cLiamExchangeSecurityGroup : cLiamDataAreaBase
|
||
{
|
||
public new readonly cLiamProviderExchange Provider = null;
|
||
public readonly string sid = null;
|
||
public readonly string dn = null;
|
||
|
||
// objectGuid wird nun als TechnicalName genutzt
|
||
public cLiamExchangeSecurityGroup(cLiamProviderExchange Provider, string displayName, string sid, string dn, string objectGuid) : base(Provider)
|
||
{
|
||
this.Provider = Provider;
|
||
this.TechnicalName = displayName;
|
||
this.DisplayName = displayName;
|
||
this.UID = sid;
|
||
this.sid = sid;
|
||
this.dn = dn;
|
||
}
|
||
|
||
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||
{
|
||
return Task.FromResult(new List<cLiamDataAreaBase>());
|
||
}
|
||
}
|
||
|
||
public class cLiamExchangeSharedMailbox : cLiamDataAreaBase
|
||
{
|
||
public new readonly cLiamProviderExchange Provider = null;
|
||
public readonly string PrimarySmtpAddress = null;
|
||
public readonly string Alias = null;
|
||
public string OwnerGroupIdentifier = "S-1-0-0";
|
||
public string FullAccessGroupSid = "S-1-0-0";
|
||
public string SendAsGroupSid = "S-1-0-0";
|
||
|
||
// objectGuid wird für TechnicalName genutzt
|
||
public cLiamExchangeSharedMailbox(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias, string objectGuid) : base(Provider)
|
||
{
|
||
this.Provider = Provider;
|
||
this.TechnicalName = objectGuid;
|
||
this.DisplayName = displayName;
|
||
this.PrimarySmtpAddress = primarySmtpAddress;
|
||
this.Alias = alias;
|
||
this.UID = getUID(primarySmtpAddress);
|
||
this.Level = 0;
|
||
this.DataType = eLiamDataAreaTypes.ExchangeSharedMailbox;
|
||
this.SupportsOwners = true;
|
||
this.SupportsPermissions = true;
|
||
_ = assignPermissionGroups(Provider).ConfigureAwait(false);
|
||
}
|
||
|
||
internal static string getUID(string primarySmtpAddress)
|
||
{
|
||
return $"{(int)eLiamDataAreaTypes.ExchangeSharedMailbox}|{primarySmtpAddress}";
|
||
}
|
||
|
||
public static async Task<cLiamExchangeSharedMailbox> Load(cLiamProviderExchange Provider, string primarySmtpAddress)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var mailbox = Provider.exchangeManager.GetSharedMailboxByAddress(primarySmtpAddress);
|
||
if (mailbox == null)
|
||
return null;
|
||
|
||
var displayName = mailbox.Properties["DisplayName"]?.Value?.ToString();
|
||
var alias = mailbox.Properties["Alias"]?.Value?.ToString();
|
||
var objectGuid = cLiamProviderExchange.ExtractObjectGuid(mailbox.Properties);
|
||
|
||
return new cLiamExchangeSharedMailbox(Provider, displayName, primarySmtpAddress, alias, objectGuid);
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var members = Provider.exchangeManager.GetMailboxPermissionMembers(this.TechnicalName);
|
||
if (members == null)
|
||
return new List<cLiamUserInfo>();
|
||
|
||
var ownersList = new List<cLiamUserInfo>();
|
||
foreach (var member in members)
|
||
{
|
||
var userInfo = new cLiamUserInfo
|
||
{
|
||
DisplayName = member.Properties["DisplayName"]?.Value?.ToString(),
|
||
UserPrincipalName = member.Properties["UserPrincipalName"]?.Value?.ToString(),
|
||
EMail = member.Properties["PrimarySmtpAddress"]?.Value?.ToString(),
|
||
SID = member.Properties["Sid"]?.Value?.ToString()
|
||
};
|
||
ownersList.Add(userInfo);
|
||
}
|
||
return ownersList;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
bool success = false;
|
||
switch (Role)
|
||
{
|
||
case eLiamAccessRoles.Owner:
|
||
success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, true);
|
||
break;
|
||
case eLiamAccessRoles.Write:
|
||
success = await Provider.exchangeManager.AddSendAsPermission(this.DisplayName, User.UserPrincipalName);
|
||
break;
|
||
default:
|
||
LogEntry($"Unsupported permission role for Exchange mailbox: {Role}", LogLevels.Warning);
|
||
return new cLiamPermissionResult { Valid = false };
|
||
}
|
||
return new cLiamPermissionResult
|
||
{
|
||
Valid = success,
|
||
UserReference = User.UserPrincipalName
|
||
};
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return new cLiamPermissionResult { Valid = false };
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
bool success = false;
|
||
switch (Role)
|
||
{
|
||
case eLiamAccessRoles.Owner:
|
||
success = await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, true);
|
||
break;
|
||
case eLiamAccessRoles.Write:
|
||
success = await Provider.exchangeManager.RemoveSendAsPermission(this.DisplayName, User.UserPrincipalName);
|
||
break;
|
||
default:
|
||
LogEntry($"Unsupported permission role for Exchange mailbox: {Role}", LogLevels.Warning);
|
||
return false;
|
||
}
|
||
return success;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||
{
|
||
return new List<cLiamDataAreaBase>();
|
||
}
|
||
|
||
private async Task assignPermissionGroups(cLiamProviderExchange Provider)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var fullAccessNamingConvention = Provider.NamingConventions.FirstOrDefault(i =>
|
||
i.AccessRole == eLiamAccessRoles.ExchangeSMBFullAccess);
|
||
|
||
var sendAsNamingConvention = Provider.NamingConventions.FirstOrDefault(i =>
|
||
i.AccessRole == eLiamAccessRoles.ExchangeSMBSendAs);
|
||
|
||
if (fullAccessNamingConvention == null || sendAsNamingConvention == null)
|
||
{
|
||
LogEntry("Naming conventions for Exchange mailbox permissions not found", LogLevels.Warning);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var fullAccessPermissions = Provider.exchangeManager.GetFullAccessPermissionGroups(this.TechnicalName);
|
||
if (fullAccessPermissions != null)
|
||
{
|
||
foreach (var permission in fullAccessPermissions)
|
||
{
|
||
string samAccountName = permission.Properties["SamAccountName"]?.Value?.ToString();
|
||
string sid = permission.Properties["Sid"]?.Value?.ToString();
|
||
|
||
if (!string.IsNullOrEmpty(samAccountName) && !string.IsNullOrEmpty(sid))
|
||
{
|
||
//if (Regex.IsMatch(samAccountName, fullAccessNamingConvention.Wildcard, RegexOptions.IgnoreCase))
|
||
{
|
||
this.FullAccessGroupSid = sid;
|
||
LogEntry($"Found FullAccess group {samAccountName} (SID: {sid}) for mailbox {this.DisplayName}", LogLevels.Debug);
|
||
string dn = permission.Properties["DistinguishedName"]?.Value?.ToString();
|
||
if (!string.IsNullOrEmpty(dn))
|
||
{
|
||
var managedByGroup = await Provider.GetManagedByGroup(dn);
|
||
if (managedByGroup != null)
|
||
{
|
||
this.OwnerGroupIdentifier = managedByGroup.sid;
|
||
LogEntry($"Found owner group {managedByGroup.TechnicalName} (SID: {managedByGroup.sid}) for mailbox {this.DisplayName}", LogLevels.Debug);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var sendAsPermissions = Provider.exchangeManager.GetSendAsPermissionGroups(this.TechnicalName);
|
||
if (sendAsPermissions != null)
|
||
{
|
||
foreach (var permission in sendAsPermissions)
|
||
{
|
||
string recipientType = permission.Properties["RecipientType"]?.Value?.ToString();
|
||
string samAccountName = permission.Properties["SamAccountName"]?.Value?.ToString();
|
||
string sid = permission.Properties["Sid"]?.Value?.ToString();
|
||
|
||
if (!string.IsNullOrEmpty(samAccountName) && !string.IsNullOrEmpty(sid))
|
||
{
|
||
//if (Regex.IsMatch(samAccountName, sendAsNamingConvention.Wildcard, RegexOptions.IgnoreCase))
|
||
{
|
||
this.SendAsGroupSid = sid;
|
||
LogEntry($"Found SendAs group {samAccountName} (SID: {sid}) for mailbox {this.DisplayName}", LogLevels.Debug);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogException(ex);
|
||
}
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
}
|
||
|
||
public class cLiamExchangeDistributionGroup : cLiamDataAreaBase
|
||
{
|
||
public new readonly cLiamProviderExchange Provider = null;
|
||
public readonly string PrimarySmtpAddress = null;
|
||
public readonly string Alias = null;
|
||
public string OwnerGroupIdentifier = "S-1-0-0";
|
||
public string MemberGroupSid = "S-1-0-0";
|
||
|
||
// objectGuid wird als TechnicalName gesetzt
|
||
public cLiamExchangeDistributionGroup(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias, string objectGuid) : base(Provider)
|
||
{
|
||
this.Provider = Provider;
|
||
this.TechnicalName = objectGuid;
|
||
this.DisplayName = displayName;
|
||
this.PrimarySmtpAddress = primarySmtpAddress;
|
||
this.Alias = alias;
|
||
this.UID = getUID(primarySmtpAddress);
|
||
this.Level = 0;
|
||
this.DataType = eLiamDataAreaTypes.ExchangeDistributionGroup;
|
||
this.SupportsOwners = true;
|
||
this.SupportsPermissions = true;
|
||
_ = assignPermissionGroups(Provider).ConfigureAwait(false);
|
||
}
|
||
|
||
internal static string getUID(string primarySmtpAddress)
|
||
{
|
||
return $"{(int)eLiamDataAreaTypes.ExchangeDistributionGroup}|{primarySmtpAddress}";
|
||
}
|
||
|
||
public static async Task<cLiamExchangeDistributionGroup> Load(cLiamProviderExchange Provider, string primarySmtpAddress)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var group = Provider.exchangeManager.GetDistributionGroupByAddress(primarySmtpAddress);
|
||
if (group == null)
|
||
return null;
|
||
|
||
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||
var alias = group.Properties["Alias"]?.Value?.ToString();
|
||
var objectGuid = cLiamProviderExchange.ExtractObjectGuid(group.Properties);
|
||
|
||
return new cLiamExchangeDistributionGroup(Provider, displayName, primarySmtpAddress, alias, objectGuid);
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var members = Provider.exchangeManager.GetDistributionGroupMembers(this.TechnicalName);
|
||
if (members == null)
|
||
return new List<cLiamUserInfo>();
|
||
|
||
var membersList = new List<cLiamUserInfo>();
|
||
foreach (var member in members)
|
||
{
|
||
var userInfo = new cLiamUserInfo
|
||
{
|
||
DisplayName = member.Properties["DisplayName"]?.Value?.ToString(),
|
||
UserPrincipalName = member.Properties["UserPrincipalName"]?.Value?.ToString(),
|
||
EMail = member.Properties["PrimarySmtpAddress"]?.Value?.ToString(),
|
||
SID = member.Properties["Sid"]?.Value?.ToString()
|
||
};
|
||
membersList.Add(userInfo);
|
||
}
|
||
return membersList;
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
if (Role != eLiamAccessRoles.Owner)
|
||
{
|
||
LogEntry($"Only Owner role is supported for distribution groups, requested: {Role}", LogLevels.Warning);
|
||
return new cLiamPermissionResult { Valid = false };
|
||
}
|
||
|
||
bool success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, false);
|
||
return new cLiamPermissionResult
|
||
{
|
||
Valid = success,
|
||
UserReference = User.UserPrincipalName
|
||
};
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return new cLiamPermissionResult { Valid = false };
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
if (Role != eLiamAccessRoles.Owner)
|
||
{
|
||
LogEntry($"Only Owner role is supported for distribution groups, requested: {Role}", LogLevels.Warning);
|
||
return false;
|
||
}
|
||
|
||
return await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, false);
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
|
||
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||
{
|
||
return new List<cLiamDataAreaBase>();
|
||
}
|
||
|
||
private async Task assignPermissionGroups(cLiamProviderExchange Provider)
|
||
{
|
||
var CM = MethodBase.GetCurrentMethod();
|
||
LogMethodBegin(CM);
|
||
try
|
||
{
|
||
var namingConvention = Provider.NamingConventions
|
||
.FirstOrDefault(nc => nc.AccessRole == eLiamAccessRoles.ExchangeMLMember);
|
||
if (namingConvention == null)
|
||
{
|
||
LogEntry("Naming convention for DL-Member not found", LogLevels.Warning);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// ruft alle Gruppen auf dem DL ab
|
||
var memberGroups = Provider.exchangeManager
|
||
.GetDistributionGroupMembers(this.TechnicalName);
|
||
|
||
foreach (var group in memberGroups)
|
||
{
|
||
var sam = group.Properties["SamAccountName"]?.Value?.ToString();
|
||
var sid = group.Properties["Sid"]?.Value?.ToString();
|
||
if (string.IsNullOrEmpty(sam) || string.IsNullOrEmpty(sid))
|
||
continue;
|
||
|
||
// falls gewünscht: Filter nach Namenskonvention
|
||
// if (!Regex.IsMatch(sam, namingConvention.Wildcard, RegexOptions.IgnoreCase))
|
||
// continue;
|
||
|
||
// hier beispielsweise in eine List<string> MemberGroupSids aufnehmen
|
||
this.MemberGroupSid = sid;
|
||
LogEntry($"Found DL-member group {sam} (SID: {sid}) for distribution list {this.DisplayName}", LogLevels.Debug);
|
||
|
||
// optional: falls die Gruppe ein ManagedBy hat
|
||
var dn = group.Properties["DistinguishedName"]?.Value?.ToString();
|
||
if (!string.IsNullOrEmpty(dn))
|
||
{
|
||
var mgr = await Provider.GetManagedByGroup(dn);
|
||
if (mgr != null)
|
||
{
|
||
this.OwnerGroupIdentifier = mgr.sid;
|
||
LogEntry($"Found owner group {mgr.TechnicalName} (SID: {mgr.sid}) for distribution list {this.DisplayName}", LogLevels.Debug);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogException(ex);
|
||
}
|
||
}
|
||
catch (Exception E)
|
||
{
|
||
LogException(E);
|
||
}
|
||
finally
|
||
{
|
||
LogMethodEnd(CM);
|
||
}
|
||
}
|
||
}
|
||
}
|