initial
This commit is contained in:
161
LIAM.sln
Normal file
161
LIAM.sln
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33723.286
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamTestTeams", "LiamTestTeams\LiamTestTeams.csproj", "{6197C490-07C6-4313-8E0F-AADC27776473}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{451CEE78-7CF7-4691-AAB6-4D636BF22E04}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
_shared\Matrix42.Common.dll = _shared\Matrix42.Common.dll
|
||||
SharedAssemblyInfo.cs = SharedAssemblyInfo.cs
|
||||
_shared\System.Web.Http.dll = _shared\System.Web.Http.dll
|
||||
_shared\update4u.SPS.DataLayer.dll = _shared\update4u.SPS.DataLayer.dll
|
||||
_shared\update4u.SPS.DataLayer_alt.dll = _shared\update4u.SPS.DataLayer_alt.dll
|
||||
_shared\update4u.SPS.Security.dll = _shared\update4u.SPS.Security.dll
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamBaseClasses", "LiamBaseClasses\LiamBaseClasses.csproj", "{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamMsTeams", "LiamMsTeams\LiamMsTeams.csproj", "{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamHelper", "LiamHelper\LiamHelper.csproj", "{6B0E73A6-F918-42D5-9525-D59D4D16283D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamMsGraph", "LiamMsGraph\LiamMsGraph.csproj", "{452827DB-14FF-469E-AF41-1A24E1875BDA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamM42WebApi", "LiamM42WebApi\LiamM42WebApi.csproj", "{007A69B8-3BEA-44F3-BD61-C5354C707F3A}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA} = {452827DB-14FF-469E-AF41-1A24E1875BDA}
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C} = {DACBD3DC-1866-4B39-964A-D2A8DEA2774C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamNtfs", "LiamNtfs\LiamNtfs.csproj", "{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamWorkflowActivities", "LiamWorkflowActivities\LiamWorkflowActivities.csproj", "{5840BB2D-88BF-4E1C-8FF6-510305894B42}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamWorkflowActivitiesDesign", "LiamWorkflowActivitiesDesign\LiamWorkflowActivitiesDesign.csproj", "{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamActiveDirectory", "LIAMActiveDirectory\LiamActiveDirectory.csproj", "{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamExchange", "LiamExchange\LiamExchange.csproj", "{12586A29-BB1E-49B4-B971-88E520D6A77C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug_and_copy|Any CPU = Debug_and_copy|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6197C490-07C6-4313-8E0F-AADC27776473}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6197C490-07C6-4313-8E0F-AADC27776473}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug_and_copy|Any CPU.ActiveCfg = Debug_and_copy|Any CPU
|
||||
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug_and_copy|Any CPU.Build.0 = Debug_and_copy|Any CPU
|
||||
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0EC9AD55-4DBA-49C3-BEEF-5EC07E361909}
|
||||
EndGlobalSection
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 12
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = https://consulting4it.visualstudio.com/
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = LiamBaseClasses\\LiamBaseClasses.csproj
|
||||
SccProjectName1 = LiamBaseClasses
|
||||
SccLocalPath1 = LiamBaseClasses
|
||||
SccProjectUniqueName2 = LiamHelper\\LiamHelper.csproj
|
||||
SccProjectName2 = LiamHelper
|
||||
SccLocalPath2 = LiamHelper
|
||||
SccProjectUniqueName3 = LiamM42WebApi\\LiamM42WebApi.csproj
|
||||
SccProjectName3 = LiamM42WebApi
|
||||
SccLocalPath3 = LiamM42WebApi
|
||||
SccProjectUniqueName4 = LiamMsGraph\\LiamMsGraph.csproj
|
||||
SccProjectName4 = LiamMsGraph
|
||||
SccLocalPath4 = LiamMsGraph
|
||||
SccProjectUniqueName5 = LiamMsTeams\\LiamMsTeams.csproj
|
||||
SccProjectName5 = LiamMsTeams
|
||||
SccLocalPath5 = LiamMsTeams
|
||||
SccProjectUniqueName6 = LiamTestTeams\\LiamTestTeams.csproj
|
||||
SccProjectName6 = LiamTestTeams
|
||||
SccLocalPath6 = LiamTestTeams
|
||||
SccProjectUniqueName7 = LiamNtfs\\LiamNtfs.csproj
|
||||
SccProjectName7 = LiamNtfs
|
||||
SccLocalPath7 = LiamNtfs
|
||||
SccProjectUniqueName8 = LiamWorkflowActivities\\LiamWorkflowActivities.csproj
|
||||
SccProjectName8 = LiamWorkflowActivities
|
||||
SccLocalPath8 = LiamWorkflowActivities
|
||||
SccProjectUniqueName9 = LiamWorkflowActivitiesDesign\\LiamWorkflowActivitiesDesign.csproj
|
||||
SccProjectName9 = LiamWorkflowActivitiesDesign
|
||||
SccLocalPath9 = LiamWorkflowActivitiesDesign
|
||||
SccProjectUniqueName10 = LIAMActiveDirectory\\LiamActiveDirectory.csproj
|
||||
SccProjectName10 = LIAMActiveDirectory
|
||||
SccLocalPath10 = LIAMActiveDirectory
|
||||
SccProjectUniqueName11 = LiamExchange\\LiamExchange.csproj
|
||||
SccProjectName11 = LiamExchange
|
||||
SccLocalPath11 = LiamExchange
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
371
LIAMActiveDirectory/C4IT.LIAM.AD.cs
Normal file
371
LIAMActiveDirectory/C4IT.LIAM.AD.cs
Normal file
@@ -0,0 +1,371 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.AccessControl;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using C4IT.Logging;
|
||||
using C4IT.Matrix42.ServerInfo;
|
||||
using LiamAD;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using static LiamAD.ADServiceGroupCreator;
|
||||
using static LiamAD.cActiveDirectoryBase;
|
||||
|
||||
namespace C4IT.LIAM
|
||||
{
|
||||
public static class LiamInitializer
|
||||
{
|
||||
static public cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||
{
|
||||
return new cLiamProviderAD(LiamConfiguration, ProviderData);
|
||||
}
|
||||
}
|
||||
|
||||
public class cLiamProviderAD : cLiamProviderBase
|
||||
{
|
||||
public static Guid adModuleId = new Guid("e820a625-0653-ee11-b886-00155d300101");
|
||||
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||
private readonly ADServiceGroupCreator _serviceGroupCreator;
|
||||
|
||||
|
||||
public cLiamProviderAD(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) :
|
||||
base(LiamConfiguration, ProviderData)
|
||||
{
|
||||
_serviceGroupCreator = new ADServiceGroupCreator(this);
|
||||
}
|
||||
|
||||
public List<Tuple<string, string, string, string>> CreateServiceGroups(
|
||||
string serviceName,
|
||||
string description = null,
|
||||
eLiamAccessRoleScopes gruppenbereich = eLiamAccessRoleScopes.Universal,
|
||||
ADGroupType gruppentyp = ADGroupType.Distribution,
|
||||
IEnumerable<string> ownerSidList = null,
|
||||
IEnumerable<string> memberSidList = null)
|
||||
{
|
||||
return _serviceGroupCreator.EnsureServiceGroups(
|
||||
serviceName,
|
||||
description,
|
||||
gruppenbereich,
|
||||
gruppentyp,
|
||||
ownerSidList,
|
||||
memberSidList);
|
||||
}
|
||||
|
||||
public override async Task<bool> LogonAsync()
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||
{
|
||||
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||
return false;
|
||||
}
|
||||
return await LogonAsync(true);
|
||||
}
|
||||
|
||||
public async Task<bool> LogonAsync(bool force = false)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var LI = new cADLogonInfo()
|
||||
{
|
||||
Domain = Domain,
|
||||
User = Credential?.Identification,
|
||||
UserSecret = Credential?.Secret,
|
||||
TargetGroupPath = this.GroupPath
|
||||
};
|
||||
var RetVal = await activeDirectoryBase.LogonAsync(LI);
|
||||
return RetVal;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int Depth = -1)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||
{
|
||||
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
if (!await LogonAsync())
|
||||
return null;
|
||||
if (string.IsNullOrEmpty(this.GroupPath))
|
||||
return null;
|
||||
|
||||
// 1. Alle Roh-Resultate einlesen
|
||||
var rawList = await activeDirectoryBase.RequestSecurityGroupsListAsync(this.GroupFilter);
|
||||
if (rawList == null)
|
||||
return null;
|
||||
|
||||
// 2. Nur die, die dem RegEx entsprechen und deren Wert extrahieren
|
||||
var allResults = rawList
|
||||
.Where(entry =>
|
||||
string.IsNullOrEmpty(this.GroupRegEx)
|
||||
|| Regex.Match(entry.Value.DisplayName, this.GroupRegEx).Success)
|
||||
.Select(entry => (cSecurityGroupResult)entry.Value)
|
||||
.ToList();
|
||||
|
||||
// 3. ManagedBySID-Werte sammeln (ohne Null-/Leereinträge)
|
||||
var managedBySids = new HashSet<string>(
|
||||
allResults
|
||||
.Select(r => r.ManagedBySID)
|
||||
.Where(m => !string.IsNullOrEmpty(m))
|
||||
);
|
||||
|
||||
// 4. Nur die Gruppen, deren ID nicht in managedBySids enthalten ist
|
||||
var filteredResults = allResults
|
||||
.Where(r => !managedBySids.Contains(r.ID))
|
||||
.ToList();
|
||||
|
||||
// 5. In DataArea-Objekte umwandeln
|
||||
var SecurityGroups = new List<cLiamDataAreaBase>();
|
||||
foreach (var secGroup in filteredResults)
|
||||
{
|
||||
SecurityGroups.Add(new cLiamAdGroupAsDataArea(this, secGroup));
|
||||
}
|
||||
|
||||
return SecurityGroups;
|
||||
}
|
||||
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
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||
{
|
||||
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
if (!await LogonAsync())
|
||||
return null;
|
||||
if (string.IsNullOrEmpty(this.GroupPath))
|
||||
return null;
|
||||
|
||||
var SecurityGroups = new List<cLiamDataAreaBase>();
|
||||
|
||||
var SGL = await activeDirectoryBase.RequestSecurityGroupsListAsync(groupFilter);
|
||||
if (SGL == null)
|
||||
return null;
|
||||
|
||||
foreach (var Entry in SGL)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.GroupRegEx) && !Regex.Match(Entry.Value.DisplayName, this.GroupRegEx).Success)
|
||||
continue;
|
||||
|
||||
|
||||
var SecurityGroup = new cLiamAdGroup2(this, (cSecurityGroupResult)Entry.Value);
|
||||
SecurityGroups.Add(SecurityGroup);
|
||||
}
|
||||
return SecurityGroups;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public int getDepth(string path)
|
||||
{
|
||||
return getDepth(this.RootPath, path);
|
||||
}
|
||||
public static int getDepth(DirectoryInfo root, DirectoryInfo folder)
|
||||
{
|
||||
var rootDepth = root.FullName.TrimEnd(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar).Length;
|
||||
var folderDepth = folder.FullName.TrimEnd(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar).Length;
|
||||
return folderDepth - rootDepth;
|
||||
|
||||
}
|
||||
public static int getDepth(string root, string folder)
|
||||
{
|
||||
return getDepth(new DirectoryInfo(root), new DirectoryInfo(folder));
|
||||
|
||||
}
|
||||
|
||||
public override string GetLastErrorMessage()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
||||
{
|
||||
//TODO implement LoadDataArea
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||
{
|
||||
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
var res = new cLiamAdGroupAsDataArea(this, new cSecurityGroupResult()
|
||||
{
|
||||
Path = UID
|
||||
});
|
||||
return res;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class cLiamAdGroupAsDataArea : cLiamDataAreaBase
|
||||
{
|
||||
public new readonly cLiamProviderAD Provider = null;
|
||||
public readonly string dn = null;
|
||||
public readonly string scope = null;
|
||||
public readonly string ManagedBySID;
|
||||
|
||||
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public cLiamAdGroupAsDataArea(cLiamProviderAD Provider, cSecurityGroupResult secGroup) : base(Provider)
|
||||
{
|
||||
this.UID = secGroup.ID;
|
||||
this.TechnicalName = secGroup.Path;
|
||||
this.DisplayName = secGroup.DisplayName;
|
||||
this.Description = secGroup.Description;
|
||||
this.Provider = Provider;
|
||||
this.dn = secGroup.Path;
|
||||
this.scope = secGroup.Scope.ToString();
|
||||
this.ManagedBySID = secGroup.ManagedBySID;
|
||||
}
|
||||
|
||||
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
return await GetMembersAsync(true);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
private async Task<List<cLiamUserInfo>> GetMembersAsync(bool owners)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var AD = this.Provider?.activeDirectoryBase;
|
||||
if (AD == null)
|
||||
{
|
||||
LogEntry($"Could not get ad class from Provider for folder '{this.TechnicalName}'", LogLevels.Warning);
|
||||
return null;
|
||||
}
|
||||
cADCollectionBase lstMembers;
|
||||
if (owners && !string.IsNullOrEmpty(OwnerRef))
|
||||
lstMembers = await AD.GetMembersAsync(OwnerRef);
|
||||
else if (owners && !string.IsNullOrEmpty(dn))
|
||||
lstMembers = await AD.GetManagedByMembersAsync(this.dn);
|
||||
else
|
||||
lstMembers = null;
|
||||
if (lstMembers == null)
|
||||
{
|
||||
LogEntry($"Could not get owner list for folder '{this.TechnicalName}'", LogLevels.Warning);
|
||||
return null;
|
||||
}
|
||||
|
||||
var RetVal = new List<cLiamUserInfo>(lstMembers.Count);
|
||||
LogEntry($"Owners for folder found: {lstMembers.Count}", LogLevels.Debug);
|
||||
foreach (var MemberEntry in lstMembers.Values)
|
||||
{
|
||||
var User = new cLiamUserInfo()
|
||||
{
|
||||
DisplayName = MemberEntry.DisplayName,
|
||||
UserPrincipalName = (MemberEntry as cADUserResult).UserPrincipalName,
|
||||
SID = MemberEntry.ID
|
||||
};
|
||||
RetVal.Add(User);
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class cLiamAdGroup2 : cLiamDataAreaBase
|
||||
{
|
||||
public new readonly cLiamProviderAD Provider = null;
|
||||
public readonly string dn = null;
|
||||
public readonly string scope = null;
|
||||
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public cLiamAdGroup2(cLiamProviderAD Provider, cSecurityGroupResult secGroup) : base(Provider)
|
||||
{
|
||||
this.DisplayName = secGroup.DisplayName;
|
||||
this.UID = secGroup.ID;
|
||||
this.TechnicalName = secGroup.DisplayName;
|
||||
this.Provider = Provider;
|
||||
this.dn = secGroup.Path;
|
||||
this.scope = secGroup.Scope.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
10
LIAMActiveDirectory/LIAMActiveDirectory.csproj.vspscc
Normal file
10
LIAMActiveDirectory/LIAMActiveDirectory.csproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
74
LIAMActiveDirectory/LiamActiveDirectory.csproj
Normal file
74
LIAMActiveDirectory/LiamActiveDirectory.csproj
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>LIAMActiveDirectory</RootNamespace>
|
||||
<AssemblyName>LiamActiveDirectory</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.ValueTuple, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.6.1\lib\net462\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="cActiveDirectoryBase.cs" />
|
||||
<Compile Include="C4IT.LIAM.AD.cs" />
|
||||
<Compile Include="cADBase.cs" />
|
||||
<Compile Include="cADServiceGroupCreator.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LiamBaseClasses\LiamBaseClasses.csproj">
|
||||
<Project>{3531c9e6-cf6e-458e-b604-4a5a8d1c7ab0}</Project>
|
||||
<Name>LiamBaseClasses</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\LiamHelper\LiamHelper.csproj">
|
||||
<Project>{6b0e73a6-f918-42d5-9525-d59d4d16283d}</Project>
|
||||
<Name>LiamHelper</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
36
LIAMActiveDirectory/Properties/AssemblyInfo.cs
Normal file
36
LIAMActiveDirectory/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("LIAMActiveDirectory")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("LIAMActiveDirectory")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("aeca0ad2-8b91-4767-9afa-e160f6662dbe")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/Newtonsoft.Json.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/System.ValueTuple.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/System.ValueTuple.dll
Normal file
Binary file not shown.
1299
LIAMActiveDirectory/bin/Debug/System.ValueTuple.xml
Normal file
1299
LIAMActiveDirectory/bin/Debug/System.ValueTuple.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/Newtonsoft.Json.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/System.ValueTuple.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/System.ValueTuple.dll
Normal file
Binary file not shown.
1299
LIAMActiveDirectory/bin/Release/System.ValueTuple.xml
Normal file
1299
LIAMActiveDirectory/bin/Release/System.ValueTuple.xml
Normal file
File diff suppressed because it is too large
Load Diff
142
LIAMActiveDirectory/cADBase.cs
Normal file
142
LIAMActiveDirectory/cADBase.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using C4IT.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LiamAD
|
||||
{
|
||||
public class cADBase
|
||||
{
|
||||
private cADLogonInfo privLogonInfo = null;
|
||||
private int scanningDepth;
|
||||
public PrincipalContext adContext = 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);
|
||||
}
|
||||
|
||||
|
||||
[DllImport("mpr.dll")]
|
||||
private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);
|
||||
|
||||
[DllImport("mpr.dll")]
|
||||
private static extern int WNetCancelConnection2(string name, int flags,
|
||||
bool force);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class cADLogonInfo
|
||||
{
|
||||
public string Domain;
|
||||
public string User;
|
||||
public string UserSecret;
|
||||
public string TargetGroupPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class NetResource
|
||||
{
|
||||
public ResourceScope Scope;
|
||||
public ResourceType ResourceType;
|
||||
public ResourceDisplaytype DisplayType;
|
||||
public int Usage;
|
||||
public string LocalName;
|
||||
public string RemoteName;
|
||||
public string Comment;
|
||||
public string Provider;
|
||||
}
|
||||
|
||||
public enum ResourceScope : int
|
||||
{
|
||||
Connected = 1,
|
||||
GlobalNetwork,
|
||||
Remembered,
|
||||
Recent,
|
||||
Context
|
||||
};
|
||||
|
||||
public enum ResourceType : int
|
||||
{
|
||||
Any = 0,
|
||||
Disk = 1,
|
||||
Print = 2,
|
||||
Reserved = 8,
|
||||
}
|
||||
|
||||
public enum ResourceDisplaytype : int
|
||||
{
|
||||
Generic = 0x0,
|
||||
Domain = 0x01,
|
||||
Server = 0x02,
|
||||
Share = 0x03,
|
||||
File = 0x04,
|
||||
Group = 0x05,
|
||||
Network = 0x06,
|
||||
Root = 0x07,
|
||||
Shareadmin = 0x08,
|
||||
Directory = 0x09,
|
||||
Tree = 0x0a,
|
||||
Ndscontainer = 0x0b
|
||||
}
|
||||
|
||||
public enum NetError : uint
|
||||
{
|
||||
NERR_Success = 0,
|
||||
NERR_BASE = 2100,
|
||||
NERR_UnknownDevDir = (NERR_BASE + 16),
|
||||
NERR_DuplicateShare = (NERR_BASE + 18),
|
||||
NERR_BufTooSmall = (NERR_BASE + 23),
|
||||
}
|
||||
public enum SHARE_TYPE : uint
|
||||
{
|
||||
STYPE_DISKTREE = 0,
|
||||
STYPE_PRINTQ = 1,
|
||||
STYPE_DEVICE = 2,
|
||||
STYPE_IPC = 3,
|
||||
STYPE_SPECIAL = 0x80000000,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SHARE_INFO_1
|
||||
{
|
||||
public string shi1_netname;
|
||||
public uint shi1_type;
|
||||
public string shi1_remark;
|
||||
public SHARE_INFO_1(string sharename, uint sharetype, string remark)
|
||||
{
|
||||
this.shi1_netname = sharename;
|
||||
this.shi1_type = sharetype;
|
||||
this.shi1_remark = remark;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return shi1_netname;
|
||||
}
|
||||
}
|
||||
}
|
||||
288
LIAMActiveDirectory/cADServiceGroupCreator.cs
Normal file
288
LIAMActiveDirectory/cADServiceGroupCreator.cs
Normal file
@@ -0,0 +1,288 @@
|
||||
using System;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using C4IT.Logging;
|
||||
using C4IT.LIAM;
|
||||
using LiamAD;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
namespace LiamAD
|
||||
{
|
||||
/// <summary>
|
||||
/// Helfer für cLiamProviderAD: Erstellt AD Member- und Owner-Gruppen für Services
|
||||
/// nach konfigurierter Namenskonvention und setzt ManagedBy.
|
||||
/// </summary>
|
||||
public class ADServiceGroupCreator
|
||||
{
|
||||
private readonly cLiamProviderAD _provider;
|
||||
private readonly cActiveDirectoryBase _adBase;
|
||||
private readonly string _ldapRoot;
|
||||
private readonly string _user;
|
||||
private readonly string _password;
|
||||
public enum ADGroupType
|
||||
{
|
||||
Security, // Sicherheit
|
||||
Distribution // Verteiler
|
||||
}
|
||||
public ADServiceGroupCreator(cLiamProviderAD provider)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Erstellt oder findet beide AD-Gruppen (Member & Owner) für einen Service.
|
||||
/// Neu mit: gruppenbereich (Scope) und gruppentyp (für Member-Gruppe).
|
||||
/// Owner-Gruppe ist immer Security.
|
||||
/// </summary>
|
||||
public List<Tuple<string, string, string, string>> EnsureServiceGroups(
|
||||
string serviceName,
|
||||
string description = null,
|
||||
eLiamAccessRoleScopes gruppenbereich = eLiamAccessRoleScopes.Universal,
|
||||
ADGroupType gruppentyp = ADGroupType.Distribution,
|
||||
IEnumerable<string> ownerSidList = null,
|
||||
IEnumerable<string> memberSidList = null)
|
||||
{
|
||||
const int MaxLoop = 50;
|
||||
var result = new List<Tuple<string, string, string, string>>();
|
||||
|
||||
// Konventionen für Member und Owner
|
||||
var ownerConv = _provider.NamingConventions
|
||||
.FirstOrDefault(nc => nc.AccessRole == eLiamAccessRoles.ADOwner);
|
||||
var memberConv = _provider.NamingConventions
|
||||
.FirstOrDefault(nc => nc.AccessRole == eLiamAccessRoles.ADMember);
|
||||
if (ownerConv == null || memberConv == null)
|
||||
throw new InvalidOperationException("Namenskonvention für ADMember oder ADOwner fehlt.");
|
||||
|
||||
// Tags
|
||||
_provider.CustomTags.TryGetValue("ADGroupPrefix", out var prefix);
|
||||
_provider.CustomTags.TryGetValue("ADOwner", out var ownerPostfix);
|
||||
_provider.CustomTags.TryGetValue("ADMember", out var memberPostfix);
|
||||
|
||||
// 1) Owner-Gruppe (immer Security)
|
||||
string ownerName = null;
|
||||
for (int loop = 0; loop <= MaxLoop; loop++)
|
||||
{
|
||||
string loopPart = loop > 0 ? "_" + loop : string.Empty;
|
||||
ownerName = ownerConv.NamingTemplate
|
||||
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||
.Replace("{{NAME}}", serviceName)
|
||||
.Replace("{{_LOOP}}", loopPart)
|
||||
.Replace("{{GROUPTYPEPOSTFIX}}", ownerPostfix);
|
||||
if (!GroupExists(ownerName)) break;
|
||||
if (loop == MaxLoop) throw new InvalidOperationException($"Kein eindeutiger Owner-Name für '{serviceName}' nach {MaxLoop} Versuchen.");
|
||||
}
|
||||
EnsureGroup(ownerName, ownerConv, description, managedByDn: null, gruppenbereich, ADGroupType.Security);
|
||||
AddMembersBySid(ownerName, ownerSidList); // NEU: SIDs als Owner hinzufügen
|
||||
var ownerDn = GetDistinguishedName(ownerName);
|
||||
var ownerSid = GetSid(ownerName);
|
||||
result.Add(Tuple.Create(eLiamAccessRoles.ADOwner.ToString(), ownerSid, ownerName, ownerDn));
|
||||
|
||||
|
||||
// 2) Member-Gruppe (Gruppentyp nach Parameter)
|
||||
string memberName = null;
|
||||
for (int loop = 0; loop <= MaxLoop; loop++)
|
||||
{
|
||||
string loopPart = loop > 0 ? "_" + loop : string.Empty;
|
||||
memberName = memberConv.NamingTemplate
|
||||
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||
.Replace("{{NAME}}", serviceName)
|
||||
.Replace("{{_LOOP}}", loopPart)
|
||||
.Replace("{{GROUPTYPEPOSTFIX}}", memberPostfix);
|
||||
if (!GroupExists(memberName)) break;
|
||||
if (loop == MaxLoop) throw new InvalidOperationException($"Kein eindeutiger Member-Name für '{serviceName}' nach {MaxLoop} Versuchen.");
|
||||
}
|
||||
EnsureGroup(memberName, memberConv, description, managedByDn: ownerDn, gruppenbereich, gruppentyp);
|
||||
AddMembersBySid(memberName, memberSidList); // NEU: SIDs als Member hinzufügen
|
||||
var memberDn = GetDistinguishedName(memberName);
|
||||
var memberSid = GetSid(memberName);
|
||||
result.Add(Tuple.Create(eLiamAccessRoles.ADMember.ToString(), memberSid, memberName, memberDn));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fügt einer bestehenden Gruppe per SID die entsprechenden AD-Objekte hinzu.
|
||||
/// </summary>
|
||||
private void AddMembersBySid(string groupName, IEnumerable<string> sidList)
|
||||
{
|
||||
if (sidList == null) return;
|
||||
|
||||
// Basis für die Suche: komplette Domäne, nicht nur der OU-Pfad
|
||||
string domainRoot = $"LDAP://{_provider.Domain}";
|
||||
using (var root = new DirectoryEntry(domainRoot, _user, _password, AuthenticationTypes.Secure))
|
||||
using (var grpSearch = new DirectorySearcher(root))
|
||||
{
|
||||
grpSearch.Filter = $"(&(objectCategory=group)(sAMAccountName={groupName}))";
|
||||
var grpRes = grpSearch.FindOne();
|
||||
if (grpRes == null) return;
|
||||
|
||||
var grpEntry = grpRes.GetDirectoryEntry();
|
||||
foreach (var sidStr in sidList)
|
||||
{
|
||||
// Leere oder null überspringen
|
||||
if (string.IsNullOrWhiteSpace(sidStr))
|
||||
continue;
|
||||
|
||||
SecurityIdentifier sid;
|
||||
try
|
||||
{
|
||||
sid = new SecurityIdentifier(sidStr);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ungültige SID-String-Darstellung überspringen
|
||||
continue;
|
||||
}
|
||||
|
||||
// In LDAP-Filter-Notation umwandeln
|
||||
var bytes = new byte[sid.BinaryLength];
|
||||
sid.GetBinaryForm(bytes, 0);
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in bytes)
|
||||
sb.AppendFormat("\\{0:X2}", b);
|
||||
string octetSid = sb.ToString();
|
||||
|
||||
// Suche nach dem Objekt in der Domäne
|
||||
using (var usrSearch = new DirectorySearcher(root))
|
||||
{
|
||||
usrSearch.Filter = $"(objectSid={octetSid})";
|
||||
var usrRes = usrSearch.FindOne();
|
||||
if (usrRes == null)
|
||||
continue;
|
||||
|
||||
var userDn = usrRes.Properties["distinguishedName"][0].ToString();
|
||||
// Doppelteinträge vermeiden
|
||||
if (!grpEntry.Properties["member"].Contains(userDn))
|
||||
grpEntry.Properties["member"].Add(userDn);
|
||||
}
|
||||
}
|
||||
|
||||
grpEntry.CommitChanges();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wandelt eine SID (String-Form) in das für LDAP nötige Oktet-String-Format um.
|
||||
/// </summary>
|
||||
private string SidStringToLdapFilter(string sidString)
|
||||
{
|
||||
var sid = new SecurityIdentifier(sidString);
|
||||
var bytes = new byte[sid.BinaryLength];
|
||||
sid.GetBinaryForm(bytes, 0);
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in bytes)
|
||||
sb.AppendFormat("\\{0:X2}", b);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
private string GetSid(string name)
|
||||
{
|
||||
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
|
||||
using (var ds = new DirectorySearcher(root))
|
||||
{
|
||||
ds.Filter = $"(&(objectCategory=group)(sAMAccountName={name}))";
|
||||
var r = ds.FindOne();
|
||||
if (r == null) return null;
|
||||
var de = r.GetDirectoryEntry();
|
||||
var sidBytes = (byte[])de.Properties["objectSid"][0];
|
||||
return new SecurityIdentifier(sidBytes, 0).Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string FormatName(cLiamNamingConvention conv, string serviceName, System.Collections.Generic.IDictionary<string, string> tags)
|
||||
{
|
||||
string tmpl = conv.NamingTemplate.Replace("{{NAME}}", serviceName);
|
||||
foreach (var kv in tags)
|
||||
tmpl = tmpl.Replace("{{" + kv.Key + "}}", kv.Value);
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stellt sicher, dass die Gruppe existiert – neu mit Scope & Type.
|
||||
/// </summary>
|
||||
private void EnsureGroup(
|
||||
string groupName,
|
||||
cLiamNamingConvention conv,
|
||||
string description,
|
||||
string managedByDn,
|
||||
eLiamAccessRoleScopes groupScope,
|
||||
ADGroupType groupType)
|
||||
{
|
||||
if (!GroupExists(groupName))
|
||||
{
|
||||
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
|
||||
{
|
||||
var grp = root.Children.Add("CN=" + groupName, "group");
|
||||
grp.Properties["sAMAccountName"].Value = groupName;
|
||||
grp.Properties["displayName"].Value = groupName;
|
||||
// Hier: Security-Bit (0x80000000) nur, wenn Security, sonst 0
|
||||
int typeBit = (groupType == ADGroupType.Security)
|
||||
? unchecked((int)0x80000000)
|
||||
: 0;
|
||||
// Scope-Bit aus Param
|
||||
grp.Properties["groupType"].Value = unchecked(typeBit | GetScopeBit(groupScope));
|
||||
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
grp.Properties["description"].Value = description;
|
||||
if (managedByDn != null)
|
||||
grp.Properties["managedBy"].Value = managedByDn;
|
||||
grp.CommitChanges();
|
||||
}
|
||||
WaitReplication(groupName, TimeSpan.FromMinutes(2));
|
||||
}
|
||||
}
|
||||
|
||||
private bool GroupExists(string name)
|
||||
{
|
||||
return _adBase.directoryEntry.Children.Cast<DirectoryEntry>()
|
||||
.Any(c => string.Equals(
|
||||
c.Properties["sAMAccountName"]?.Value?.ToString(), name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private void WaitReplication(string groupName, TimeSpan timeout)
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
while (sw.Elapsed < timeout)
|
||||
{
|
||||
if (GroupExists(groupName))
|
||||
return;
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetDistinguishedName(string name)
|
||||
{
|
||||
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
|
||||
using (var ds = new DirectorySearcher(root))
|
||||
{
|
||||
ds.Filter = "(&(objectClass=group)(sAMAccountName=" + name + "))";
|
||||
var res = ds.FindOne();
|
||||
return res?.Properties["distinguishedName"]?[0]?.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetScopeBit(eLiamAccessRoleScopes scope)
|
||||
{
|
||||
switch (scope)
|
||||
{
|
||||
case eLiamAccessRoleScopes.Universal:
|
||||
return 0x8;
|
||||
case eLiamAccessRoleScopes.Global:
|
||||
return 0x2;
|
||||
case eLiamAccessRoleScopes.DomainLocal:
|
||||
return 0x4;
|
||||
default:
|
||||
return 0x8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamActiveDirectory.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamActiveDirectory.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamBaseClasses.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamHelper.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\Newtonsoft.Json.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamBaseClasses.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamHelper.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.csproj.AssemblyReference.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.csproj.CoreCompileInputs.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActi.8091FDFC.Up2Date
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\System.ValueTuple.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\System.ValueTuple.xml
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
88ca960765b758a5c4edcddedf6dc811f2a49d840cd7ade015d7644911a99c77
|
||||
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LIAMActiveDirectory.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LIAMActiveDirectory.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamBaseClasses.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamHelper.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\Newtonsoft.Json.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamBaseClasses.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamHelper.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.csproj.AssemblyReference.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.csproj.CoreCompileInputs.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LiamActi.8091FDFC.Up2Date
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\System.ValueTuple.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\System.ValueTuple.xml
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
ab9bb136583040c5ab0b8fc2b80edba3f154caa1532f30973b39973f0def47e6
|
||||
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
4
LIAMActiveDirectory/packages.config
Normal file
4
LIAMActiveDirectory/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="System.ValueTuple" version="4.6.1" targetFramework="net462" />
|
||||
</packages>
|
||||
399
LiamBaseClasses/C4IT.LIAM.Base.cs
Normal file
399
LiamBaseClasses/C4IT.LIAM.Base.cs
Normal file
@@ -0,0 +1,399 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
using C4IT.Logging;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
|
||||
namespace C4IT.LIAM
|
||||
{
|
||||
public enum eLiamAccessRoles
|
||||
{
|
||||
Owner = 1, Write = 2, Read = 3, Traverse = 4,
|
||||
ADOwner = 110, // "AD Owner Group"
|
||||
ADMember = 100, // "AD Member Group"
|
||||
ExchangeMLMember = 200, // "Mailing List Member"
|
||||
ExchangeMLOwner = 210, // "Mailing List Owner"
|
||||
ExchangeSMBFullAccess = 250, // "Shared Mailbox Full Access"
|
||||
ExchangeSMBSendAs = 260, // "Shared Mailbox Send as"
|
||||
ExchangeSMBOwner = 270 // "Shared Mailbox Owner"
|
||||
};
|
||||
public enum eLiamAccessRoleScopes { Unknown = 0, Universal = 1, Global = 2, DomainLocal = 3 };
|
||||
|
||||
public enum eLiamProviderTypes { Unknown = 0, Ntfs = 1, Sharepoint = 2, Matrix42 = 3, MsTeams = 4, ActiveDirectory = 5, Exchange = 6 };
|
||||
|
||||
public enum eLiamDataAreaTypes
|
||||
{
|
||||
Unknown = 0,
|
||||
NtfsShare = 101,
|
||||
NtfsFolder = 102,
|
||||
MsTeamsTeam = 401,
|
||||
MsTeamsChannel = 402,
|
||||
MsTeamsFolder = 403,
|
||||
ActiveDirectoryGroup = 501,
|
||||
ExchangeSharedMailbox = 601,
|
||||
ExchangeDistributionGroup = 602
|
||||
};
|
||||
|
||||
public enum eLiamGroupStrategies { None = 0, Ntfs_AGP = 0, Ntfs_AGDLP = 1 };
|
||||
|
||||
public class cLiamConfiguration
|
||||
{
|
||||
}
|
||||
|
||||
public class cLiamProviderData : ICloneable
|
||||
{
|
||||
|
||||
public eLiamProviderTypes ProviderType { get; set; } = eLiamProviderTypes.Unknown;
|
||||
|
||||
public string Domain { get; set; } = "";
|
||||
|
||||
public string RootPath { get; set; } = "";
|
||||
|
||||
public cLiamCredential Credential { get; set; } = null;
|
||||
|
||||
public int MaxDepth { get; set; } = 1;
|
||||
|
||||
public eLiamGroupStrategies GroupStrategy { get; set; } = eLiamGroupStrategies.None;
|
||||
|
||||
public string DataAreaFilter { get; set; } = "";
|
||||
|
||||
public string DataAreaRegEx { get; set; } = "";
|
||||
|
||||
public string GroupFilter { get; set; } = "";
|
||||
|
||||
public string GroupRegEx { get; set; } = "";
|
||||
|
||||
public string GroupPath { get; set; } = "";
|
||||
|
||||
public string OwnerGroupGlobal { get; set; } = "";
|
||||
public string OwnerGroupLocal { get; set; } = "";
|
||||
public string WriteGroupGlobal { get; set; } = "";
|
||||
public string WriteGroupLocal { get; set; } = "";
|
||||
public string ReadGroupGlobal { get; set; } = "";
|
||||
public string ReadGroupLocal { get; set; } = "";
|
||||
public string TraverseGroup { get; set; } = "";
|
||||
|
||||
public List<cLiamNamingConvention> NamingConventions { get; set; } = new List<cLiamNamingConvention>();
|
||||
public Dictionary<string, string> CustomTags { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
public Dictionary<string, string> AdditionalConfiguration { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static void Copy(cLiamProviderData From, cLiamProviderData To)
|
||||
{
|
||||
To.ProviderType = From.ProviderType;
|
||||
To.Domain = From.Domain;
|
||||
To.RootPath = From.RootPath;
|
||||
To.Credential = From.Credential;
|
||||
To.MaxDepth = From.MaxDepth;
|
||||
To.GroupStrategy = From.GroupStrategy;
|
||||
To.DataAreaFilter = From.DataAreaFilter;
|
||||
To.DataAreaRegEx = From.DataAreaRegEx;
|
||||
To.GroupFilter = From.GroupFilter;
|
||||
To.GroupRegEx = From.GroupRegEx;
|
||||
To.GroupPath = From.GroupPath;
|
||||
To.CustomTags = From.CustomTags;
|
||||
To.AdditionalConfiguration = From.AdditionalConfiguration;
|
||||
To.CustomTags = From.CustomTags;
|
||||
To.NamingConventions = From.NamingConventions;
|
||||
}
|
||||
|
||||
public cLiamProviderData()
|
||||
{
|
||||
}
|
||||
|
||||
public cLiamProviderData(cLiamProviderData PD)
|
||||
{
|
||||
Copy(PD, this);
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new cLiamProviderData(this);
|
||||
}
|
||||
public void ReplaceCustomTags()
|
||||
{
|
||||
foreach (var customTag in this.CustomTags)
|
||||
{
|
||||
var Key = customTag.Key;
|
||||
|
||||
foreach (var namingConvention in NamingConventions)
|
||||
{
|
||||
if (customTag.Key == "Filesystem_GroupDomainLocalTag" && namingConvention.Scope == eLiamAccessRoleScopes.DomainLocal || customTag.Key == "Filesystem_GroupGlobalTag" && namingConvention.Scope == eLiamAccessRoleScopes.Global)
|
||||
Key = "SCOPETAG";
|
||||
else
|
||||
Key = customTag.Key;
|
||||
namingConvention.DescriptionTemplate = namingConvention.DescriptionTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
namingConvention.NamingTemplate = namingConvention.NamingTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
namingConvention.Wildcard = namingConvention.Wildcard.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
}
|
||||
GroupFilter = GroupFilter.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class cLiamProviderBase : cLiamProviderData
|
||||
{
|
||||
public cLiamConfiguration LiamConfiguration { get; private set; }
|
||||
|
||||
public cLiamProviderBase(cLiamConfiguration Configuration, cLiamProviderData ProviderData) :
|
||||
base(ProviderData)
|
||||
{
|
||||
LiamConfiguration = Configuration;
|
||||
}
|
||||
|
||||
public abstract Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1);
|
||||
|
||||
public abstract Task<bool> LogonAsync();
|
||||
public abstract string GetLastErrorMessage();
|
||||
|
||||
public abstract Task<cLiamDataAreaBase> LoadDataArea(string UID);
|
||||
|
||||
public static cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||
{
|
||||
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var MyPath = Assembly.GetExecutingAssembly()?.Location;
|
||||
if (MyPath == null)
|
||||
return null;
|
||||
|
||||
MyPath = Path.GetDirectoryName(MyPath);
|
||||
var DllPath = Path.Combine(MyPath, $"Liam{ProviderData.ProviderType}.dll");
|
||||
if (!File.Exists(DllPath))
|
||||
{
|
||||
LogEntry($"Couldn not found Data Provider library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var assLocal = Assembly.LoadFrom(DllPath);
|
||||
if (assLocal == null)
|
||||
{
|
||||
LogEntry($"Could not load Data Provider library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
var TP = assLocal.GetTypes();
|
||||
var type = assLocal.GetType("C4IT.LIAM.LiamInitializer");
|
||||
if (type == null)
|
||||
{
|
||||
LogEntry($"Could not found class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var MI = type.GetMethod("CreateInstance");
|
||||
if (MI == null)
|
||||
{
|
||||
LogEntry($"Could not found method 'CreateInstance' in class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
var objDll = MI.Invoke(null, new object[] { LiamConfiguration, ProviderData });
|
||||
var RetVal = objDll as cLiamProviderBase;
|
||||
ProviderData.ReplaceCustomTags();
|
||||
return RetVal;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter);
|
||||
}
|
||||
|
||||
public class cLiamCredential
|
||||
{
|
||||
public string Domain { get; set; } = "";
|
||||
public string Identification { get; set; } = "";
|
||||
public string Secret { get; set; } = "";
|
||||
}
|
||||
|
||||
public class cLiamNamingConvention
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string NamingTemplate { get; set; } = "";
|
||||
public string DescriptionTemplate { get; set; } = "";
|
||||
public string Wildcard { get; set; } = "";
|
||||
public eLiamAccessRoles AccessRole { get; set; } = eLiamAccessRoles.Read;
|
||||
public eLiamAccessRoleScopes Scope { get; set; } = eLiamAccessRoleScopes.Unknown;
|
||||
public eLiamProviderTypes? ProviderType { get; set; } = null;
|
||||
}
|
||||
|
||||
public class cLiamDataAreaInfo
|
||||
{
|
||||
public string DisplayName { get; protected set; } = null;
|
||||
public string Description { get; protected set; } = null;
|
||||
public string OwnerRef { get; set; } = null;
|
||||
public string UID { get; protected set; } = null;
|
||||
public string CreatedDate { get; protected set; } = null;
|
||||
|
||||
public string TechnicalName { get; protected set; } = "";
|
||||
|
||||
public int Level { get; set; } = -1;
|
||||
|
||||
public string ParentUID { get; protected set; } = null;
|
||||
|
||||
public eLiamDataAreaTypes DataType { get; protected set; } = eLiamDataAreaTypes.Unknown;
|
||||
|
||||
public bool SupportsPermissions { get; protected set; } = false;
|
||||
|
||||
public bool SupportsOwners { get; protected set; } = false;
|
||||
}
|
||||
|
||||
public abstract class cLiamDataAreaBase : cLiamDataAreaInfo
|
||||
{
|
||||
|
||||
public readonly cLiamProviderBase Provider = null;
|
||||
|
||||
public cLiamDataAreaBase(cLiamProviderBase Provider)
|
||||
{
|
||||
this.Provider = Provider;
|
||||
}
|
||||
|
||||
public abstract Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1);
|
||||
|
||||
public static async Task<List<cLiamDataAreaBase>> getChildrenFromListAsync(List<cLiamDataAreaBase> Items, int Depth = -1)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
var RetVal = new List<cLiamDataAreaBase>();
|
||||
try
|
||||
{
|
||||
if (Items == null)
|
||||
return RetVal;
|
||||
|
||||
if (Depth <= 0)
|
||||
return RetVal;
|
||||
|
||||
foreach (var Entry in Items)
|
||||
{
|
||||
var Childs = await Entry.getChildrenAsync(Depth + 1);
|
||||
if (Childs != null)
|
||||
RetVal.AddRange(Childs);
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
public virtual async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<List<cLiamPermissionInfo>> GetPermissionsAsync(bool force)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class cLiamUserInfo
|
||||
{
|
||||
public string DisplayName { get; set; } = null;
|
||||
public string GivenName { get; set; } = null;
|
||||
public string SurName { get; set; } = null;
|
||||
public string UserPrincipalName { get; set; } = null;
|
||||
public string EMail { get; set; } = null;
|
||||
public string SID { get; set; } = null;
|
||||
}
|
||||
|
||||
public class cLiamPermissionResult
|
||||
{
|
||||
public bool Valid { get; set; } = false;
|
||||
public string UserReference { get; set; } = null;
|
||||
}
|
||||
|
||||
public class cLiamPermissionInfo
|
||||
{
|
||||
public cLiamUserInfo User;
|
||||
public eLiamAccessRoles AccessRole = eLiamAccessRoles.Read;
|
||||
public bool OnlyEffective = false;
|
||||
}
|
||||
|
||||
|
||||
public class DataAreaEntryBase
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string TechnicalName { get; set; }
|
||||
public string UID { get; set; }
|
||||
public string TargetType { get; set; }
|
||||
}
|
||||
|
||||
public class SecurityGroupEntry : DataAreaEntryBase
|
||||
{
|
||||
public string Scope { get; set; }
|
||||
}
|
||||
public class DataAreaEntry : DataAreaEntryBase
|
||||
{
|
||||
public string Parent { get; set; }
|
||||
public string ParentUID { get; set; }
|
||||
public string Owner { get; set; }
|
||||
public string Write { get; set; }
|
||||
public string Read { get; set; }
|
||||
public string Traverse { get; set; }
|
||||
public string CreatedDate { get; set; }
|
||||
public string Level { get; set; }
|
||||
public string ConfigurationId { get; set; }
|
||||
public string BaseFolder { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string UniqueId { get; set; }
|
||||
public string DataAreaType { get; set; }
|
||||
}
|
||||
public class LiamApiVersionInfo
|
||||
{
|
||||
public string ProductName { get; set; } = "- unknown -";
|
||||
public string ProductVersion { get; set; } = "";
|
||||
public string AssemblyName { get; set; } = "- unknown -";
|
||||
public string AssemblyVersion { get; set; } = "";
|
||||
}
|
||||
|
||||
public class ProviderCacheEntry
|
||||
{
|
||||
public Guid ID;
|
||||
public Guid ObjectID;
|
||||
public DateTime ValidUntil;
|
||||
public cLiamProviderBase Provider;
|
||||
}
|
||||
|
||||
public class LiamDataAreaEntry
|
||||
{
|
||||
public string DisplayName { get; set; } = "";
|
||||
|
||||
public string UID { get; set; } = "";
|
||||
|
||||
public bool SupportsPermissions { get; set; } = false;
|
||||
}
|
||||
}
|
||||
399
LiamBaseClasses/C4IT.LIAM.Base.cs.txt
Normal file
399
LiamBaseClasses/C4IT.LIAM.Base.cs.txt
Normal file
@@ -0,0 +1,399 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
using C4IT.Logging;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
|
||||
namespace C4IT.LIAM
|
||||
{
|
||||
public enum eLiamAccessRoles
|
||||
{
|
||||
Owner = 1, Write = 2, Read = 3, Traverse = 4,
|
||||
ADOwner = 100, // "AD Owner Group"
|
||||
ADMember = 110, // "AD Member Group"
|
||||
ExchangeMLMember = 200, // "Mailing List Member"
|
||||
ExchangeMLOwner = 210, // "Mailing List Owner"
|
||||
ExchangeSMBFullAccess = 250, // "Shared Mailbox Full Access"
|
||||
ExchangeSMBSendAs = 260, // "Shared Mailbox Send as"
|
||||
ExchangeSMBOwner = 270 // "Shared Mailbox Owner"
|
||||
};
|
||||
public enum eLiamAccessRoleScopes { Unknown = 0, Universal = 1, Global = 2, DomainLocal = 3 };
|
||||
|
||||
public enum eLiamProviderTypes { Unknown = 0, Ntfs = 1, Sharepoint = 2, Matrix42 = 3, MsTeams = 4, ActiveDirectory = 5, Exchange = 6 };
|
||||
|
||||
public enum eLiamDataAreaTypes
|
||||
{
|
||||
Unknown = 0,
|
||||
NtfsShare = 101,
|
||||
NtfsFolder = 102,
|
||||
MsTeamsTeam = 401,
|
||||
MsTeamsChannel = 402,
|
||||
MsTeamsFolder = 403,
|
||||
ActiveDirectoryGroup = 501,
|
||||
ExchangeSharedMailbox = 601,
|
||||
ExchangeDistributionGroup = 602
|
||||
};
|
||||
|
||||
public enum eLiamGroupStrategies { None = 0, Ntfs_AGP = 0, Ntfs_AGDLP = 1 };
|
||||
|
||||
public class cLiamConfiguration
|
||||
{
|
||||
}
|
||||
|
||||
public class cLiamProviderData : ICloneable
|
||||
{
|
||||
|
||||
public eLiamProviderTypes ProviderType { get; set; } = eLiamProviderTypes.Unknown;
|
||||
|
||||
public string Domain { get; set; } = "";
|
||||
|
||||
public string RootPath { get; set; } = "";
|
||||
|
||||
public cLiamCredential Credential { get; set; } = null;
|
||||
|
||||
public int MaxDepth { get; set; } = 1;
|
||||
|
||||
public eLiamGroupStrategies GroupStrategy { get; set; } = eLiamGroupStrategies.None;
|
||||
|
||||
public string DataAreaFilter { get; set; } = "";
|
||||
|
||||
public string DataAreaRegEx { get; set; } = "";
|
||||
|
||||
public string GroupFilter { get; set; } = "";
|
||||
|
||||
public string GroupRegEx { get; set; } = "";
|
||||
|
||||
public string GroupPath { get; set; } = "";
|
||||
|
||||
public string OwnerGroupGlobal { get; set; } = "";
|
||||
public string OwnerGroupLocal { get; set; } = "";
|
||||
public string WriteGroupGlobal { get; set; } = "";
|
||||
public string WriteGroupLocal { get; set; } = "";
|
||||
public string ReadGroupGlobal { get; set; } = "";
|
||||
public string ReadGroupLocal { get; set; } = "";
|
||||
public string TraverseGroup { get; set; } = "";
|
||||
|
||||
public List<cLiamNamingConvention> NamingConventions { get; set; } = new List<cLiamNamingConvention>();
|
||||
public Dictionary<string, string> CustomTags { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
public Dictionary<string, string> AdditionalConfiguration { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static void Copy(cLiamProviderData From, cLiamProviderData To)
|
||||
{
|
||||
To.ProviderType = From.ProviderType;
|
||||
To.Domain = From.Domain;
|
||||
To.RootPath = From.RootPath;
|
||||
To.Credential = From.Credential;
|
||||
To.MaxDepth = From.MaxDepth;
|
||||
To.GroupStrategy = From.GroupStrategy;
|
||||
To.DataAreaFilter = From.DataAreaFilter;
|
||||
To.DataAreaRegEx = From.DataAreaRegEx;
|
||||
To.GroupFilter = From.GroupFilter;
|
||||
To.GroupRegEx = From.GroupRegEx;
|
||||
To.GroupPath = From.GroupPath;
|
||||
To.CustomTags = From.CustomTags;
|
||||
To.AdditionalConfiguration = From.AdditionalConfiguration;
|
||||
To.CustomTags = From.CustomTags;
|
||||
To.NamingConventions = From.NamingConventions;
|
||||
}
|
||||
|
||||
public cLiamProviderData()
|
||||
{
|
||||
}
|
||||
|
||||
public cLiamProviderData(cLiamProviderData PD)
|
||||
{
|
||||
Copy(PD, this);
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new cLiamProviderData(this);
|
||||
}
|
||||
public void ReplaceCustomTags()
|
||||
{
|
||||
foreach (var customTag in this.CustomTags)
|
||||
{
|
||||
var Key = customTag.Key;
|
||||
|
||||
foreach (var namingConvention in NamingConventions)
|
||||
{
|
||||
if (customTag.Key == "Filesystem_GroupDomainLocalTag" && namingConvention.Scope == eLiamAccessRoleScopes.DomainLocal || customTag.Key == "Filesystem_GroupGlobalTag" && namingConvention.Scope == eLiamAccessRoleScopes.Global)
|
||||
Key = "SCOPETAG";
|
||||
else
|
||||
Key = customTag.Key;
|
||||
namingConvention.DescriptionTemplate = namingConvention.DescriptionTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
namingConvention.NamingTemplate = namingConvention.NamingTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
namingConvention.Wildcard = namingConvention.Wildcard.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
}
|
||||
GroupFilter = GroupFilter.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class cLiamProviderBase : cLiamProviderData
|
||||
{
|
||||
public cLiamConfiguration LiamConfiguration { get; private set; }
|
||||
|
||||
public cLiamProviderBase(cLiamConfiguration Configuration, cLiamProviderData ProviderData) :
|
||||
base(ProviderData)
|
||||
{
|
||||
LiamConfiguration = Configuration;
|
||||
}
|
||||
|
||||
public abstract Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1);
|
||||
|
||||
public abstract Task<bool> LogonAsync();
|
||||
public abstract string GetLastErrorMessage();
|
||||
|
||||
public abstract Task<cLiamDataAreaBase> LoadDataArea(string UID);
|
||||
|
||||
public static cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||
{
|
||||
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
var MyPath = Assembly.GetExecutingAssembly()?.Location;
|
||||
if (MyPath == null)
|
||||
return null;
|
||||
|
||||
MyPath = Path.GetDirectoryName(MyPath);
|
||||
var DllPath = Path.Combine(MyPath, $"Liam{ProviderData.ProviderType}.dll");
|
||||
if (!File.Exists(DllPath))
|
||||
{
|
||||
LogEntry($"Couldn not found Data Provider library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var assLocal = Assembly.LoadFrom(DllPath);
|
||||
if (assLocal == null)
|
||||
{
|
||||
LogEntry($"Could not load Data Provider library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
var TP = assLocal.GetTypes();
|
||||
var type = assLocal.GetType("C4IT.LIAM.LiamInitializer");
|
||||
if (type == null)
|
||||
{
|
||||
LogEntry($"Could not found class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var MI = type.GetMethod("CreateInstance");
|
||||
if (MI == null)
|
||||
{
|
||||
LogEntry($"Could not found method 'CreateInstance' in class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||
return null;
|
||||
}
|
||||
var objDll = MI.Invoke(null, new object[] { LiamConfiguration, ProviderData });
|
||||
var RetVal = objDll as cLiamProviderBase;
|
||||
ProviderData.ReplaceCustomTags();
|
||||
return RetVal;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter);
|
||||
}
|
||||
|
||||
public class cLiamCredential
|
||||
{
|
||||
public string Domain { get; set; } = "";
|
||||
public string Identification { get; set; } = "";
|
||||
public string Secret { get; set; } = "";
|
||||
}
|
||||
|
||||
public class cLiamNamingConvention
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string NamingTemplate { get; set; } = "";
|
||||
public string DescriptionTemplate { get; set; } = "";
|
||||
public string Wildcard { get; set; } = "";
|
||||
public eLiamAccessRoles AccessRole { get; set; } = eLiamAccessRoles.Read;
|
||||
public eLiamAccessRoleScopes Scope { get; set; } = eLiamAccessRoleScopes.Unknown;
|
||||
public eLiamProviderTypes? ProviderType { get; set; } = null;
|
||||
}
|
||||
|
||||
public class cLiamDataAreaInfo
|
||||
{
|
||||
public string DisplayName { get; protected set; } = null;
|
||||
public string Description { get; protected set; } = null;
|
||||
public string OwnerRef { get; set; } = null;
|
||||
public string UID { get; protected set; } = null;
|
||||
public string CreatedDate { get; protected set; } = null;
|
||||
|
||||
public string TechnicalName { get; protected set; } = "";
|
||||
|
||||
public int Level { get; set; } = -1;
|
||||
|
||||
public string ParentUID { get; protected set; } = null;
|
||||
|
||||
public eLiamDataAreaTypes DataType { get; protected set; } = eLiamDataAreaTypes.Unknown;
|
||||
|
||||
public bool SupportsPermissions { get; protected set; } = false;
|
||||
|
||||
public bool SupportsOwners { get; protected set; } = false;
|
||||
}
|
||||
|
||||
public abstract class cLiamDataAreaBase : cLiamDataAreaInfo
|
||||
{
|
||||
|
||||
public readonly cLiamProviderBase Provider = null;
|
||||
|
||||
public cLiamDataAreaBase(cLiamProviderBase Provider)
|
||||
{
|
||||
this.Provider = Provider;
|
||||
}
|
||||
|
||||
public abstract Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1);
|
||||
|
||||
public static async Task<List<cLiamDataAreaBase>> getChildrenFromListAsync(List<cLiamDataAreaBase> Items, int Depth = -1)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
var RetVal = new List<cLiamDataAreaBase>();
|
||||
try
|
||||
{
|
||||
if (Items == null)
|
||||
return RetVal;
|
||||
|
||||
if (Depth <= 0)
|
||||
return RetVal;
|
||||
|
||||
foreach (var Entry in Items)
|
||||
{
|
||||
var Childs = await Entry.getChildrenAsync(Depth + 1);
|
||||
if (Childs != null)
|
||||
RetVal.AddRange(Childs);
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
public virtual async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<List<cLiamPermissionInfo>> GetPermissionsAsync(bool force)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class cLiamUserInfo
|
||||
{
|
||||
public string DisplayName { get; set; } = null;
|
||||
public string GivenName { get; set; } = null;
|
||||
public string SurName { get; set; } = null;
|
||||
public string UserPrincipalName { get; set; } = null;
|
||||
public string EMail { get; set; } = null;
|
||||
public string SID { get; set; } = null;
|
||||
}
|
||||
|
||||
public class cLiamPermissionResult
|
||||
{
|
||||
public bool Valid { get; set; } = false;
|
||||
public string UserReference { get; set; } = null;
|
||||
}
|
||||
|
||||
public class cLiamPermissionInfo
|
||||
{
|
||||
public cLiamUserInfo User;
|
||||
public eLiamAccessRoles AccessRole = eLiamAccessRoles.Read;
|
||||
public bool OnlyEffective = false;
|
||||
}
|
||||
|
||||
|
||||
public class DataAreaEntryBase
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string TechnicalName { get; set; }
|
||||
public string UID { get; set; }
|
||||
public string TargetType { get; set; }
|
||||
}
|
||||
|
||||
public class SecurityGroupEntry : DataAreaEntryBase
|
||||
{
|
||||
public string Scope { get; set; }
|
||||
}
|
||||
public class DataAreaEntry : DataAreaEntryBase
|
||||
{
|
||||
public string Parent { get; set; }
|
||||
public string ParentUID { get; set; }
|
||||
public string Owner { get; set; }
|
||||
public string Write { get; set; }
|
||||
public string Read { get; set; }
|
||||
public string Traverse { get; set; }
|
||||
public string CreatedDate { get; set; }
|
||||
public string Level { get; set; }
|
||||
public string ConfigurationId { get; set; }
|
||||
public string BaseFolder { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string UniqueId { get; set; }
|
||||
public string DataAreaType { get; set; }
|
||||
}
|
||||
public class LiamApiVersionInfo
|
||||
{
|
||||
public string ProductName { get; set; } = "- unknown -";
|
||||
public string ProductVersion { get; set; } = "";
|
||||
public string AssemblyName { get; set; } = "- unknown -";
|
||||
public string AssemblyVersion { get; set; } = "";
|
||||
}
|
||||
|
||||
public class ProviderCacheEntry
|
||||
{
|
||||
public Guid ID;
|
||||
public Guid ObjectID;
|
||||
public DateTime ValidUntil;
|
||||
public cLiamProviderBase Provider;
|
||||
}
|
||||
|
||||
public class LiamDataAreaEntry
|
||||
{
|
||||
public string DisplayName { get; set; } = "";
|
||||
|
||||
public string UID { get; set; } = "";
|
||||
|
||||
public bool SupportsPermissions { get; set; } = false;
|
||||
}
|
||||
}
|
||||
61
LiamBaseClasses/LiamBaseClasses.csproj
Normal file
61
LiamBaseClasses/LiamBaseClasses.csproj
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>LiamBaseClasses</RootNamespace>
|
||||
<AssemblyName>LiamBaseClasses</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>false</Deterministic>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="C4IT.LIAM.Base.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LiamHelper\LiamHelper.csproj">
|
||||
<Project>{6b0e73a6-f918-42d5-9525-d59d4d16283d}</Project>
|
||||
<Name>LiamHelper</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
10
LiamBaseClasses/LiamBaseClasses.csproj.vspscc
Normal file
10
LiamBaseClasses/LiamBaseClasses.csproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
11
LiamBaseClasses/Properties/AssemblyInfo.cs
Normal file
11
LiamBaseClasses/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("LIAM support library for basic classes & interfaces")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: Guid("3531c9e6-cf6e-458e-b604-4a5a8d1c7ab0")]
|
||||
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/LiamHelper.dll
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/LiamHelper.pdb
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/Newtonsoft.Json.dll
Normal file
BIN
LiamBaseClasses/bin/Debug/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamHelper.dll
Normal file
BIN
LiamBaseClasses/bin/Release/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamHelper.pdb
Normal file
BIN
LiamBaseClasses/bin/Release/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/Newtonsoft.Json.dll
Normal file
BIN
LiamBaseClasses/bin/Release/Newtonsoft.Json.dll
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||
Binary file not shown.
0
LiamBaseClasses/obj/Debug/LiamBase.24B0A51E.Up2Date
Normal file
0
LiamBaseClasses/obj/Debug/LiamBase.24B0A51E.Up2Date
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
3908855f9633bf09d020c2efbd1fa153a9ad8a91b6e76b39255ee0403b9907f8
|
||||
@@ -0,0 +1,10 @@
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamBaseClasses.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamBaseClasses.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamHelper.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\Newtonsoft.Json.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamHelper.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.csproj.AssemblyReference.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.csproj.CoreCompileInputs.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBase.24B0A51E.Up2Date
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.pdb
|
||||
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
77f86ea35cc63f1fe117fbff3ddf1a527617a8ddb75413eb5ef7f6b4cf6c8399
|
||||
@@ -0,0 +1,10 @@
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamBaseClasses.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamBaseClasses.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamHelper.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\Newtonsoft.Json.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamHelper.pdb
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.csproj.AssemblyReference.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.csproj.CoreCompileInputs.cache
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBase.24B0A51E.Up2Date
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.dll
|
||||
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.pdb
|
||||
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.pdb
Normal file
Binary file not shown.
898
LiamExchange/C4IT.LIAM.Exchange.cs
Normal file
898
LiamExchange/C4IT.LIAM.Exchange.cs
Normal file
@@ -0,0 +1,898 @@
|
||||
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 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 override async Task<bool> LogonAsync()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||||
{
|
||||
LogEntry("Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||
lastErrorMessage = "License not valid or Exchange module not licensed";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var testMailboxes = exchangeManager.GetSharedMailboxes("Name -like '*'");
|
||||
if (testMailboxes != null)
|
||||
{
|
||||
LogEntry("Successfully connected to Exchange", LogLevels.Info);
|
||||
isLoggedOn = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
lastErrorMessage = $"Failed to connect to Exchange: {ex.Message}";
|
||||
isLoggedOn = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
lastErrorMessage = "Unknown error connecting to Exchange";
|
||||
return false;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
lastErrorMessage = $"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
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||||
{
|
||||
LogEntry("Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
|
||||
if (!isLoggedOn && !await LogonAsync())
|
||||
return null;
|
||||
|
||||
var DataAreas = new List<cLiamDataAreaBase>();
|
||||
|
||||
// Shared Mailboxes
|
||||
try
|
||||
{
|
||||
var sharedMailboxes = exchangeManager.GetSharedMailboxes();
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
// Distribution Groups
|
||||
try
|
||||
{
|
||||
var distributionGroups = exchangeManager.GetDistributionGroups();
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
return DataAreas;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
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
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||||
{
|
||||
LogEntry("Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
|
||||
if (!isLoggedOn && !await LogonAsync())
|
||||
return null;
|
||||
|
||||
var securityGroups = new List<cLiamDataAreaBase>();
|
||||
try
|
||||
{
|
||||
var groups = exchangeManager.GetSecurityGroups(groupFilter);
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
return securityGroups;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
726
LiamExchange/C4IT.LIAM.Exchange.cs.txt
Normal file
726
LiamExchange/C4IT.LIAM.Exchange.cs.txt
Normal file
@@ -0,0 +1,726 @@
|
||||
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;
|
||||
|
||||
namespace C4IT.LIAM
|
||||
{
|
||||
public static class LiamInitializer
|
||||
{
|
||||
static public cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||
{
|
||||
return new cLiamProviderExchange(LiamConfiguration, ProviderData);
|
||||
}
|
||||
}
|
||||
|
||||
public class cLiamProviderExchange : cLiamProviderBase
|
||||
{
|
||||
public static Guid exchangeModuleId = new Guid("A1E213C3-6517-EA11-4881-000C2980FD95");
|
||||
internal readonly ExchangeManager exchangeManager;
|
||||
private string exchangeUri;
|
||||
private PSCredential credential;
|
||||
private string organizationalUnit;
|
||||
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;
|
||||
|
||||
// Use the credential from the provider data
|
||||
var securePassword = new SecureString();
|
||||
foreach (char c in ProviderData.Credential.Secret)
|
||||
{
|
||||
securePassword.AppendChar(c);
|
||||
}
|
||||
credential = new PSCredential(ProviderData.Credential.Identification, securePassword);
|
||||
|
||||
// Create the Exchange manager
|
||||
exchangeManager = new ExchangeManager(exchangeUri, credential, organizationalUnit);
|
||||
}
|
||||
|
||||
public override async Task<bool> LogonAsync()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid /*|| !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(exchangeModuleId)*/)
|
||||
{
|
||||
LogEntry($"Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||
lastErrorMessage = "License not valid or Exchange module not licensed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test connection by getting a simple list
|
||||
try
|
||||
{
|
||||
var testMailboxes = exchangeManager.GetSharedMailboxes("Name -like '*'");
|
||||
if (testMailboxes != null)
|
||||
{
|
||||
LogEntry($"Successfully connected to Exchange", LogLevels.Info);
|
||||
isLoggedOn = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
lastErrorMessage = $"Failed to connect to Exchange: {ex.Message}";
|
||||
isLoggedOn = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
lastErrorMessage = "Unknown error connecting to Exchange";
|
||||
return false;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
lastErrorMessage = $"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
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid /*|| !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(exchangeModuleId)*/)
|
||||
{
|
||||
LogEntry($"Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
|
||||
if (!isLoggedOn && !await LogonAsync())
|
||||
return null;
|
||||
|
||||
var DataAreas = new List<cLiamDataAreaBase>();
|
||||
|
||||
// Get Shared Mailboxes
|
||||
try
|
||||
{
|
||||
var sharedMailboxes = exchangeManager.GetSharedMailboxes();
|
||||
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();
|
||||
|
||||
// Skip if it doesn't match the regex filter (if provided)
|
||||
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||||
!System.Text.RegularExpressions.Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||||
continue;
|
||||
|
||||
var exchangeMailbox = new cLiamExchangeSharedMailbox(this, displayName, primarySmtpAddress, alias);
|
||||
DataAreas.Add(exchangeMailbox);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
// Get Distribution Groups
|
||||
try
|
||||
{
|
||||
var distributionGroups = exchangeManager.GetDistributionGroups();
|
||||
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();
|
||||
|
||||
// Skip if it doesn't match the regex filter (if provided)
|
||||
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||||
!System.Text.RegularExpressions.Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||||
continue;
|
||||
|
||||
var exchangeGroup = new cLiamExchangeDistributionGroup(this, displayName, primarySmtpAddress, alias);
|
||||
DataAreas.Add(exchangeGroup);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
return DataAreas;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
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;
|
||||
|
||||
int dataTypeInt;
|
||||
if (!int.TryParse(dataType, out 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
|
||||
{
|
||||
if (!cC4ITLicenseM42ESM.Instance.IsValid /*|| !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(exchangeModuleId)*/)
|
||||
{
|
||||
LogEntry($"Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
|
||||
if (!isLoggedOn && !await LogonAsync())
|
||||
return null;
|
||||
|
||||
// For Exchange, we need to use the same AD security groups as from the AD provider
|
||||
// This is just a placeholder implementation to return some groups from the exchange environment
|
||||
var securityGroups = new List<cLiamDataAreaBase>();
|
||||
|
||||
try
|
||||
{
|
||||
// Use the Exchange PowerShell to get AD groups
|
||||
var groups = exchangeManager.GetSecurityGroups(groupFilter);
|
||||
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();
|
||||
|
||||
// Skip if it doesn't match the regex filter (if provided)
|
||||
if (!string.IsNullOrEmpty(this.GroupRegEx) &&
|
||||
!System.Text.RegularExpressions.Regex.Match(displayName, this.GroupRegEx).Success)
|
||||
continue;
|
||||
|
||||
var securityGroup = new cLiamExchangeSecurityGroup(this, displayName, sid, dn);
|
||||
securityGroups.Add(securityGroup);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
}
|
||||
|
||||
return securityGroups;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper methods to interact with Exchange
|
||||
internal async Task<bool> CreateSharedMailbox(string displayName, string alias, string ownerGroupName, string writeGroupName)
|
||||
{
|
||||
try
|
||||
{
|
||||
exchangeManager.CreateSharedMailbox(displayName, alias, null);
|
||||
|
||||
// Create the owner (FullAccess) and write (SendAs) groups if they don't exist already
|
||||
exchangeManager.CreateSecurityGroup(ownerGroupName, $"{displayName} Full Access");
|
||||
exchangeManager.CreateSecurityGroup(writeGroupName, $"{displayName} Send As");
|
||||
|
||||
// Grant permissions to the groups
|
||||
exchangeManager.AddMailboxPermission(displayName, ownerGroupName, "FullAccess");
|
||||
exchangeManager.AddSendAsPermission(displayName, writeGroupName);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
lastErrorMessage = $"Error creating shared mailbox: {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<bool> CreateDistributionGroup(string displayName, string alias, List<string> initialMembers = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
exchangeManager.CreateDistributionGroup(displayName, alias, initialMembers);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
lastErrorMessage = $"Error creating distribution group: {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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 class cLiamExchangeSecurityGroup : cLiamDataAreaBase
|
||||
{
|
||||
public new readonly cLiamProviderExchange Provider = null;
|
||||
public readonly string sid = null;
|
||||
public readonly string dn = null;
|
||||
|
||||
public cLiamExchangeSecurityGroup(cLiamProviderExchange Provider, string displayName, string sid, string dn) : base(Provider)
|
||||
{
|
||||
this.Provider = Provider;
|
||||
this.TechnicalName = displayName;
|
||||
this.UID = sid;
|
||||
this.sid = sid;
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||
{
|
||||
// Security groups don't have children in this context
|
||||
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 = null; // Full Access group
|
||||
public string WriteGroupIdentifier = null; // Send As group
|
||||
|
||||
public cLiamExchangeSharedMailbox(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias) : base(Provider)
|
||||
{
|
||||
this.Provider = Provider;
|
||||
this.TechnicalName = displayName;
|
||||
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;
|
||||
|
||||
// Set standard naming convention for access groups
|
||||
// These will be resolved to actual groups later as needed
|
||||
this.OwnerGroupIdentifier = $"EXCH_FA_{alias}"; // Full Access group
|
||||
this.WriteGroupIdentifier = $"EXCH_SA_{alias}"; // Send As group
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// Get the mailbox details from Exchange
|
||||
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();
|
||||
|
||||
return new cLiamExchangeSharedMailbox(Provider, displayName, primarySmtpAddress, alias);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
// Get members of the Full Access group
|
||||
var members = Provider.exchangeManager.GetMailboxPermissionMembers(this.DisplayName);
|
||||
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:
|
||||
// Add to Full Access group
|
||||
success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, true);
|
||||
break;
|
||||
case eLiamAccessRoles.Write:
|
||||
// Add Send As permission
|
||||
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:
|
||||
// Remove from Full Access group
|
||||
success = await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, true);
|
||||
break;
|
||||
case eLiamAccessRoles.Write:
|
||||
// Remove Send As permission
|
||||
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)
|
||||
{
|
||||
// Shared mailboxes don't have children in this context
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
}
|
||||
|
||||
public class cLiamExchangeDistributionGroup : cLiamDataAreaBase
|
||||
{
|
||||
public new readonly cLiamProviderExchange Provider = null;
|
||||
public readonly string PrimarySmtpAddress = null;
|
||||
public readonly string Alias = null;
|
||||
|
||||
public cLiamExchangeDistributionGroup(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias) : base(Provider)
|
||||
{
|
||||
this.Provider = Provider;
|
||||
this.TechnicalName = displayName;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// Get the group details from Exchange
|
||||
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();
|
||||
|
||||
return new cLiamExchangeDistributionGroup(Provider, displayName, primarySmtpAddress, alias);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(CM);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
LogMethodBegin(CM);
|
||||
try
|
||||
{
|
||||
// Get members of the distribution group
|
||||
var members = Provider.exchangeManager.GetDistributionGroupMembers(this.DisplayName);
|
||||
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
|
||||
{
|
||||
// For distribution groups, we only support adding members (which is essentially Owner role)
|
||||
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
|
||||
{
|
||||
// For distribution groups, we only support removing members (which is essentially Owner role)
|
||||
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)
|
||||
{
|
||||
// Distribution groups don't have children in this context
|
||||
return new List<cLiamDataAreaBase>();
|
||||
}
|
||||
}
|
||||
}
|
||||
1026
LiamExchange/C4IT.LIAM.ExchangeManager.cs
Normal file
1026
LiamExchange/C4IT.LIAM.ExchangeManager.cs
Normal file
File diff suppressed because it is too large
Load Diff
671
LiamExchange/C4IT.LIAM.ExchangeManager.cs.txt
Normal file
671
LiamExchange/C4IT.LIAM.ExchangeManager.cs.txt
Normal file
@@ -0,0 +1,671 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using C4IT.Logging;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace C4IT.LIAM
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages Exchange operations using PowerShell remoting
|
||||
/// </summary>
|
||||
public class ExchangeManager
|
||||
{
|
||||
private readonly string _exchangeUri;
|
||||
private readonly PSCredential _credential;
|
||||
private readonly string _organizationalUnit;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with explicit credentials, Exchange URI and OU path
|
||||
/// </summary>
|
||||
/// <param name="exchangeUri">URL of the Exchange PowerShell endpoint (e.g. "http://exchangeserver/PowerShell")</param>
|
||||
/// <param name="credential">Explicit credentials</param>
|
||||
/// <param name="organizationalUnit">OU path where objects should be created</param>
|
||||
public ExchangeManager(string exchangeUri, PSCredential credential, string organizationalUnit)
|
||||
{
|
||||
_exchangeUri = exchangeUri;
|
||||
_credential = credential;
|
||||
_organizationalUnit = organizationalUnit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a runspace connected to the Exchange PowerShell endpoint
|
||||
/// </summary>
|
||||
private Runspace CreateRunspace()
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
var connectionInfo = new WSManConnectionInfo(
|
||||
new Uri(_exchangeUri),
|
||||
"http://schemas.microsoft.com/powershell/Microsoft.Exchange",
|
||||
_credential);
|
||||
|
||||
// Set authentication mechanism to Kerberos by default
|
||||
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
|
||||
|
||||
var runspace = RunspaceFactory.CreateRunspace(connectionInfo);
|
||||
runspace.Open();
|
||||
return runspace;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a distribution group (mailing list). Optionally members can be added initially.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the group</param>
|
||||
/// <param name="alias">Alias of the group</param>
|
||||
/// <param name="initialMembers">List of members to be added to the group (optional)</param>
|
||||
public void CreateDistributionGroup(string name, string alias, List<string> initialMembers = null)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
|
||||
// Create the distribution group
|
||||
ps.AddCommand("New-DistributionGroup")
|
||||
.AddParameter("Name", name)
|
||||
.AddParameter("Alias", alias)
|
||||
.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||
ps.Invoke();
|
||||
|
||||
// Add initial members if specified
|
||||
if (initialMembers != null)
|
||||
{
|
||||
foreach (var member in initialMembers)
|
||||
{
|
||||
ps.Commands.Clear();
|
||||
ps.AddCommand("Add-DistributionGroupMember")
|
||||
.AddParameter("Identity", name)
|
||||
.AddParameter("Member", member);
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a security group in Active Directory that can be used for Exchange permissions
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the security group</param>
|
||||
/// <param name="description">Description of the security group</param>
|
||||
/// <returns>True if successful</returns>
|
||||
public bool CreateSecurityGroup(string name, string description)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
|
||||
// Create the security group using New-ADGroup cmdlet
|
||||
ps.AddCommand("New-ADGroup")
|
||||
.AddParameter("Name", name)
|
||||
.AddParameter("GroupScope", "Universal")
|
||||
.AddParameter("GroupCategory", "Security")
|
||||
.AddParameter("DisplayName", name)
|
||||
.AddParameter("Path", _organizationalUnit)
|
||||
.AddParameter("Description", description);
|
||||
|
||||
var result = ps.Invoke();
|
||||
return result.Count > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all shared mailboxes matching an optional filter
|
||||
/// </summary>
|
||||
/// <param name="filter">Optional filter string</param>
|
||||
/// <returns>Collection of shared mailboxes as PSObjects</returns>
|
||||
public IEnumerable<PSObject> GetSharedMailboxes(string filter = null)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-Mailbox")
|
||||
.AddParameter("RecipientTypeDetails", "SharedMailbox");
|
||||
|
||||
if (!string.IsNullOrEmpty(filter))
|
||||
{
|
||||
ps.AddParameter("Filter", filter);
|
||||
}
|
||||
|
||||
return ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return Enumerable.Empty<PSObject>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a shared mailbox by primary SMTP address
|
||||
/// </summary>
|
||||
/// <param name="primarySmtpAddress">The primary SMTP address of the mailbox</param>
|
||||
/// <returns>The mailbox as a PSObject, or null if not found</returns>
|
||||
public PSObject GetSharedMailboxByAddress(string primarySmtpAddress)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-Mailbox")
|
||||
.AddParameter("RecipientTypeDetails", "SharedMailbox")
|
||||
.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||
|
||||
var results = ps.Invoke();
|
||||
return results.Count > 0 ? results[0] : null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all distribution groups matching an optional filter
|
||||
/// </summary>
|
||||
/// <param name="filter">Optional filter string</param>
|
||||
/// <returns>Collection of distribution groups as PSObjects</returns>
|
||||
public IEnumerable<PSObject> GetDistributionGroups(string filter = null)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-DistributionGroup");
|
||||
|
||||
if (!string.IsNullOrEmpty(filter))
|
||||
{
|
||||
ps.AddParameter("Filter", filter);
|
||||
}
|
||||
|
||||
return ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return Enumerable.Empty<PSObject>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a distribution group by primary SMTP address
|
||||
/// </summary>
|
||||
/// <param name="primarySmtpAddress">The primary SMTP address of the group</param>
|
||||
/// <returns>The distribution group as a PSObject, or null if not found</returns>
|
||||
public PSObject GetDistributionGroupByAddress(string primarySmtpAddress)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-DistributionGroup")
|
||||
.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||
|
||||
var results = ps.Invoke();
|
||||
return results.Count > 0 ? results[0] : null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets members of a distribution group
|
||||
/// </summary>
|
||||
/// <param name="groupName">The name of the distribution group</param>
|
||||
/// <returns>Collection of members as PSObjects</returns>
|
||||
public IEnumerable<PSObject> GetDistributionGroupMembers(string groupName)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-DistributionGroupMember")
|
||||
.AddParameter("Identity", groupName);
|
||||
|
||||
return ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return Enumerable.Empty<PSObject>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets users who have permissions on a mailbox
|
||||
/// </summary>
|
||||
/// <param name="mailboxName">The name of the mailbox</param>
|
||||
/// <returns>Collection of users as PSObjects</returns>
|
||||
public IEnumerable<PSObject> GetMailboxPermissionMembers(string mailboxName)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-MailboxPermission")
|
||||
.AddParameter("Identity", mailboxName)
|
||||
.AddParameter("AccessRights", "FullAccess");
|
||||
|
||||
// Filter out default permissions like NT AUTHORITY\SELF
|
||||
var results = ps.Invoke().Where(p =>
|
||||
!p.Properties["User"].Value.ToString().Contains("NT AUTHORITY") &&
|
||||
!p.Properties["User"].Value.ToString().Contains("Administrator"));
|
||||
|
||||
// Now, get the full user objects for each permission
|
||||
var userList = new List<PSObject>();
|
||||
using (var ps2 = PowerShell.Create())
|
||||
{
|
||||
ps2.Runspace = runspace;
|
||||
foreach (var perm in results)
|
||||
{
|
||||
ps2.Commands.Clear();
|
||||
ps2.AddCommand("Get-User")
|
||||
.AddParameter("Identity", perm.Properties["User"].Value.ToString());
|
||||
|
||||
var users = ps2.Invoke();
|
||||
if (users.Count > 0)
|
||||
{
|
||||
userList.Add(users[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return userList;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return Enumerable.Empty<PSObject>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets security groups matching a filter
|
||||
/// </summary>
|
||||
/// <param name="filter">LDAP filter to match groups</param>
|
||||
/// <returns>Collection of security groups as PSObjects</returns>
|
||||
public IEnumerable<PSObject> GetSecurityGroups(string filter)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Get-ADGroup")
|
||||
.AddParameter("Filter", filter)
|
||||
.AddParameter("Properties", new string[] { "DisplayName", "DistinguishedName", "Sid" });
|
||||
|
||||
return ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return Enumerable.Empty<PSObject>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a member to a distribution group
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the distribution group</param>
|
||||
/// <param name="member">User to be added as a member</param>
|
||||
public void AddMemberToDistributionGroup(string groupName, string member)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Add-DistributionGroupMember")
|
||||
.AddParameter("Identity", groupName)
|
||||
.AddParameter("Member", member);
|
||||
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a member from a distribution group
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the distribution group</param>
|
||||
/// <param name="member">User to be removed</param>
|
||||
public void RemoveMemberFromDistributionGroup(string groupName, string member)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Remove-DistributionGroupMember")
|
||||
.AddParameter("Identity", groupName)
|
||||
.AddParameter("Member", member)
|
||||
.AddParameter("Confirm", false);
|
||||
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds mailbox permission for a user
|
||||
/// </summary>
|
||||
/// <param name="mailboxName">Name of the mailbox</param>
|
||||
/// <param name="user">User or group to be granted permission</param>
|
||||
/// <param name="accessRight">Access right (default: FullAccess)</param>
|
||||
public void AddMailboxPermission(string mailboxName, string user, string accessRight = "FullAccess")
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Add-MailboxPermission")
|
||||
.AddParameter("Identity", mailboxName)
|
||||
.AddParameter("User", user)
|
||||
.AddParameter("AccessRights", accessRight)
|
||||
.AddParameter("InheritanceType", "All");
|
||||
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes mailbox permission for a user
|
||||
/// </summary>
|
||||
/// <param name="mailboxName">Name of the mailbox</param>
|
||||
/// <param name="user">User or group to have permission removed</param>
|
||||
/// <param name="accessRight">Access right (default: FullAccess)</param>
|
||||
public void RemoveMailboxPermission(string mailboxName, string user, string accessRight = "FullAccess")
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Remove-MailboxPermission")
|
||||
.AddParameter("Identity", mailboxName)
|
||||
.AddParameter("User", user)
|
||||
.AddParameter("AccessRights", accessRight)
|
||||
.AddParameter("InheritanceType", "All")
|
||||
.AddParameter("Confirm", false);
|
||||
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Send As permission for a mailbox
|
||||
/// </summary>
|
||||
/// <param name="mailboxName">Name of the mailbox</param>
|
||||
/// <param name="user">User or group to be granted permission</param>
|
||||
/// <returns>True if successful</returns>
|
||||
public async Task<bool> AddSendAsPermission(string mailboxName, string user)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Add-ADPermission")
|
||||
.AddParameter("Identity", mailboxName)
|
||||
.AddParameter("User", user)
|
||||
.AddParameter("ExtendedRights", "Send-As")
|
||||
.AddParameter("AccessRights", "ExtendedRight");
|
||||
|
||||
var results = ps.Invoke();
|
||||
return results.Count > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes Send As permission for a mailbox
|
||||
/// </summary>
|
||||
/// <param name="mailboxName">Name of the mailbox</param>
|
||||
/// <param name="user">User or group to have permission removed</param>
|
||||
/// <returns>True if successful</returns>
|
||||
public async Task<bool> RemoveSendAsPermission(string mailboxName, string user)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Remove-ADPermission")
|
||||
.AddParameter("Identity", mailboxName)
|
||||
.AddParameter("User", user)
|
||||
.AddParameter("ExtendedRights", "Send-As")
|
||||
.AddParameter("AccessRights", "ExtendedRight")
|
||||
.AddParameter("Confirm", false);
|
||||
|
||||
var results = ps.Invoke();
|
||||
return results.Count > 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a shared mailbox. Optionally initial permissions (e.g. FullAccess) can be set for members.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the mailbox</param>
|
||||
/// <param name="alias">Alias of the mailbox</param>
|
||||
/// <param name="initialMembers">List of users to be added as access rights (optional)</param>
|
||||
public void CreateSharedMailbox(string name, string alias, List<string> initialMembers = null)
|
||||
{
|
||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||
try
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
|
||||
// Create new shared mailbox
|
||||
ps.AddCommand("New-Mailbox")
|
||||
.AddParameter("Name", name)
|
||||
.AddParameter("Alias", alias)
|
||||
.AddParameter("Shared", true)
|
||||
.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||
ps.Invoke();
|
||||
|
||||
// Add initial members if specified
|
||||
if (initialMembers != null)
|
||||
{
|
||||
foreach (var member in initialMembers)
|
||||
{
|
||||
ps.Commands.Clear();
|
||||
ps.AddCommand("Add-MailboxPermission")
|
||||
.AddParameter("Identity", name)
|
||||
.AddParameter("User", member)
|
||||
.AddParameter("AccessRights", "FullAccess")
|
||||
.AddParameter("InheritanceType", "All");
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
380
LiamExchange/ExchangeManager.Extensions.cs
Normal file
380
LiamExchange/ExchangeManager.Extensions.cs
Normal file
@@ -0,0 +1,380 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.DirectoryServices;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace C4IT.LIAM
|
||||
{
|
||||
public partial class ExchangeManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Stellt sicher, dass eine AD-Sicherheitsgruppe für den angegebenen AccessRole existiert (erstellt sie falls nicht)
|
||||
/// und wartet optional, bis die Replikation abgeschlossen ist.
|
||||
/// Liefert den tatsächlichen Gruppennamen zurück.
|
||||
/// </summary>
|
||||
private string EnsureSecurityGroup(eLiamAccessRoles accessRole, string baseName)
|
||||
{
|
||||
const int MaxLoop = 50; // Abbruchbedingung: nach 50 Versuchen abbrechen
|
||||
|
||||
// 1. Namenskonvention für diese Rolle finden
|
||||
var namingConvention = _provider.NamingConventions
|
||||
.FirstOrDefault(nc => nc.AccessRole == accessRole);
|
||||
if (namingConvention == null)
|
||||
throw new InvalidOperationException($"Keine Namenskonvention für Rolle '{accessRole}' gefunden.");
|
||||
|
||||
// 2. Benötigte CustomTags aus dem Provider ziehen
|
||||
// - Prefix (z.B. "ACL")
|
||||
// - GROUPTYPEPOSTFIX (z.B. "ExchangeMLMember")
|
||||
_provider.CustomTags.TryGetValue("ADGroupPrefix", out var prefix);
|
||||
_provider.CustomTags.TryGetValue(accessRole.ToString(), out var typePostfix);
|
||||
|
||||
// 3. Schleife für _LOOP hochzählen, bis ein einzigartiger Name gefunden ist
|
||||
string groupName = null;
|
||||
string description = null;
|
||||
|
||||
for (int loop = 0; loop <= MaxLoop; loop++)
|
||||
{
|
||||
// nur einfügen, wenn loop > 0
|
||||
var loopPart = loop > 0 ? $"_{loop}" : string.Empty;
|
||||
|
||||
// Platzhalter im Template ersetzen
|
||||
groupName = namingConvention.NamingTemplate
|
||||
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||
.Replace("{{NAME}}", baseName)
|
||||
.Replace("{{_LOOP}}", loopPart)
|
||||
.Replace("{{GROUPTYPEPOSTFIX}}", typePostfix ?? string.Empty);
|
||||
|
||||
description = namingConvention.DescriptionTemplate
|
||||
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||
.Replace("{{NAME}}", baseName)
|
||||
.Replace("{{_LOOP}}", loopPart)
|
||||
.Replace("{{GROUPTYPEPOSTFIX}}", typePostfix ?? string.Empty);
|
||||
|
||||
// Existenz prüfen
|
||||
bool exists = GetSecurityGroups(groupName)
|
||||
.Any(g => string.Equals(
|
||||
g.Properties["sAMAccountName"]?.Value?.ToString(),
|
||||
groupName,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!exists)
|
||||
break; // Name ist frei – raus aus der Schleife
|
||||
|
||||
if (loop == MaxLoop)
|
||||
throw new InvalidOperationException(
|
||||
$"Konnte nach {MaxLoop} Versuchen keinen eindeutigen Gruppennamen für '{baseName}' erzeugen.");
|
||||
}
|
||||
// 4. Gruppen-Scope-Bit setzen
|
||||
int scopeBit;
|
||||
switch (namingConvention.Scope)
|
||||
{
|
||||
case eLiamAccessRoleScopes.Global:
|
||||
scopeBit = 0x2;
|
||||
break;
|
||||
case eLiamAccessRoleScopes.DomainLocal:
|
||||
scopeBit = 0x4;
|
||||
break;
|
||||
case eLiamAccessRoleScopes.Universal:
|
||||
scopeBit = 0x8;
|
||||
break;
|
||||
default:
|
||||
scopeBit = 0x8;
|
||||
break;
|
||||
}
|
||||
int groupType = unchecked((int)(0x80000000 | scopeBit));
|
||||
|
||||
// 5. Gruppe im AD anlegen
|
||||
string ldapPath = $"LDAP://{_organizationalUnit}";
|
||||
string password = new System.Net.NetworkCredential(string.Empty, _credential.Password).Password;
|
||||
using (var root = new DirectoryEntry(
|
||||
ldapPath,
|
||||
_credential.UserName,
|
||||
password,
|
||||
AuthenticationTypes.Secure))
|
||||
{
|
||||
var newGroup = root.Children.Add($"CN={groupName}", "group");
|
||||
newGroup.Properties["sAMAccountName"].Value = groupName;
|
||||
newGroup.Properties["displayName"].Value = groupName;
|
||||
newGroup.Properties["groupType"].Value = groupType;
|
||||
if(!string.IsNullOrEmpty(description))
|
||||
{
|
||||
newGroup.Properties["description"].Value = description;
|
||||
}
|
||||
|
||||
newGroup.CommitChanges();
|
||||
}
|
||||
|
||||
// 6. Auf Replikation warten (optional)
|
||||
const int replicationTimeoutMinutes = 2;
|
||||
if (!WaitForGroupReplication(groupName, TimeSpan.FromMinutes(replicationTimeoutMinutes)))
|
||||
{
|
||||
throw new TimeoutException(
|
||||
$"Die AD-Gruppe '{groupName}' konnte innerhalb von {replicationTimeoutMinutes} Minuten nicht repliziert werden.");
|
||||
}
|
||||
|
||||
return groupName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wartet darauf, dass die Gruppe nach der Erstellung im AD repliziert ist.
|
||||
/// </summary>
|
||||
private bool WaitForGroupReplication(string groupName, TimeSpan timeout)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var pollInterval = TimeSpan.FromSeconds(5);
|
||||
|
||||
while (sw.Elapsed < timeout)
|
||||
{
|
||||
var found = GetSecurityGroups(groupName)
|
||||
.Any(g => string.Equals(
|
||||
g.Properties["sAMAccountName"]?.Value?.ToString(),
|
||||
groupName,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (found) return true;
|
||||
Thread.Sleep(pollInterval);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setzt das ManagedBy-Attribut einer AD-Gruppe auf eine andere Gruppe
|
||||
/// – mit den im Konstruktor übergebenen Credentials und Domain.
|
||||
/// </summary>
|
||||
private void SetManagedBy(string groupName, string managerGroup)
|
||||
{
|
||||
string ldapPath = $"LDAP://{_organizationalUnit}";
|
||||
|
||||
// SecureString -> Klartext
|
||||
string password = SecureStringToString(_credential.Password);
|
||||
|
||||
using (var root = new DirectoryEntry(ldapPath,
|
||||
_credential.UserName,
|
||||
password,
|
||||
AuthenticationTypes.Secure))
|
||||
using (var ds = new DirectorySearcher(root))
|
||||
{
|
||||
// Gruppe holen
|
||||
ds.Filter = $"(&(objectClass=group)(sAMAccountName={groupName}))";
|
||||
var result = ds.FindOne();
|
||||
if (result == null)
|
||||
throw new InvalidOperationException($"Gruppe '{groupName}' nicht gefunden in {ldapPath}");
|
||||
|
||||
var groupEntry = result.GetDirectoryEntry();
|
||||
|
||||
// DistinguishedName der Manager-Gruppe ermitteln
|
||||
using (var mgrSearch = new DirectorySearcher(root))
|
||||
{
|
||||
mgrSearch.Filter = $"(&(objectClass=group)(sAMAccountName={managerGroup}))";
|
||||
var mgrResult = mgrSearch.FindOne();
|
||||
if (mgrResult == null)
|
||||
throw new InvalidOperationException($"Manager-Gruppe '{managerGroup}' nicht gefunden in {ldapPath}");
|
||||
|
||||
string managerDn = mgrResult.GetDirectoryEntry()
|
||||
.Properties["distinguishedName"]
|
||||
.Value
|
||||
.ToString();
|
||||
|
||||
// Attribut setzen und speichern
|
||||
groupEntry.Properties["managedBy"].Value = managerDn;
|
||||
groupEntry.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Erstellt eine Shared Mailbox samt zugehöriger AD-Gruppen (FullAccess, SendAs, Owner) und setzt die nötigen Berechtigungen.
|
||||
/// </summary>
|
||||
public Tuple<Guid, List<Tuple<string, string, string, string>>> CreateSharedMailboxWithOwnershipGroups(
|
||||
string name,
|
||||
string alias,
|
||||
string displayName = null,
|
||||
string primarySmtpAddress = null)
|
||||
{
|
||||
CreationResult result = new CreationResult();
|
||||
|
||||
// Ensure AD groups
|
||||
string fullAccessGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeSMBFullAccess, name);
|
||||
string sendAsGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeSMBSendAs, name);
|
||||
string ownerGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeSMBOwner, name);
|
||||
|
||||
SetManagedBy(fullAccessGroup, ownerGroup);
|
||||
SetManagedBy(sendAsGroup, ownerGroup);
|
||||
|
||||
// Create mailbox
|
||||
using (Runspace rs = CreateRunspace())
|
||||
{
|
||||
using (PowerShell ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = rs;
|
||||
ps.AddCommand("New-Mailbox");
|
||||
ps.AddParameter("Name", name);
|
||||
ps.AddParameter("Alias", alias);
|
||||
ps.AddParameter("Shared", true);
|
||||
ps.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||
if (!string.IsNullOrEmpty(displayName))
|
||||
ps.AddParameter("DisplayName", displayName);
|
||||
if (!string.IsNullOrEmpty(primarySmtpAddress))
|
||||
ps.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||
ps.Invoke();
|
||||
AddMailboxPermission(name, fullAccessGroup, "FullAccess");
|
||||
AddSendAsPermission(name, sendAsGroup).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve mailbox GUID
|
||||
DirectoryEntry mbEntry = FindAdObject("(&(objectClass=user)(mailNickname=" + alias + "))");
|
||||
if (mbEntry != null && mbEntry.Properties.Contains("objectGUID") && mbEntry.Properties["objectGUID"].Count > 0)
|
||||
{
|
||||
byte[] bytes = (byte[])mbEntry.Properties["objectGUID"][0];
|
||||
result.ObjectGuid = new Guid(bytes);
|
||||
}
|
||||
|
||||
// Collect group details
|
||||
string[] roles = new string[] {
|
||||
eLiamAccessRoles.ExchangeSMBFullAccess.ToString(),
|
||||
eLiamAccessRoles.ExchangeSMBSendAs.ToString(),
|
||||
eLiamAccessRoles.ExchangeSMBOwner.ToString()
|
||||
};
|
||||
string[] names = new string[] {
|
||||
fullAccessGroup,
|
||||
sendAsGroup,
|
||||
ownerGroup
|
||||
};
|
||||
|
||||
for (int i = 0; i < roles.Length; i++)
|
||||
{
|
||||
DirectoryEntry grpEntry = FindAdObject("(&(objectCategory=group)(sAMAccountName=" + names[i] + "))");
|
||||
if (grpEntry != null && grpEntry.Properties.Contains("objectSid") && grpEntry.Properties["objectSid"].Count > 0)
|
||||
{
|
||||
byte[] sidBytes = (byte[])grpEntry.Properties["objectSid"][0];
|
||||
string sid = new SecurityIdentifier(sidBytes, 0).Value;
|
||||
string distinguishedName = grpEntry.Properties["distinguishedName"][0].ToString();
|
||||
result.Groups.Add(Tuple.Create(roles[i], sid, names[i], distinguishedName));
|
||||
}
|
||||
}
|
||||
|
||||
return Tuple.Create(result.ObjectGuid, result.Groups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Erstellt eine Distribution Group samt zugehöriger AD-Gruppen (Member, Owner) und setzt die nötigen Berechtigungen.
|
||||
/// </summary>
|
||||
public Tuple<Guid, List<Tuple<string, string, string, string>>> CreateDistributionGroupWithOwnershipGroups(
|
||||
string name,
|
||||
string alias,
|
||||
string displayName = null,
|
||||
string primarySmtpAddress = null)
|
||||
{
|
||||
CreationResult result = new CreationResult();
|
||||
|
||||
// Ensure AD groups
|
||||
string memberGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeMLMember, name);
|
||||
string ownerGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeMLOwner, name);
|
||||
|
||||
SetManagedBy(memberGroup, ownerGroup);
|
||||
|
||||
// Create distribution group
|
||||
using (Runspace rs = CreateRunspace())
|
||||
{
|
||||
using (PowerShell ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = rs;
|
||||
ps.AddCommand("New-DistributionGroup");
|
||||
ps.AddParameter("Name", name);
|
||||
ps.AddParameter("Alias", alias);
|
||||
ps.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||
if (!string.IsNullOrEmpty(displayName))
|
||||
ps.AddParameter("DisplayName", displayName);
|
||||
if (!string.IsNullOrEmpty(primarySmtpAddress))
|
||||
ps.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||
ps.Invoke();
|
||||
|
||||
// b) GUID holen
|
||||
ps.Commands.Clear();
|
||||
ps.AddCommand("Get-DistributionGroup")
|
||||
.AddParameter("Identity", name);
|
||||
var dg = ps.Invoke().FirstOrDefault();
|
||||
if (dg != null && dg.Properties["Guid"] != null)
|
||||
{
|
||||
var guidVal = dg.Properties["Guid"].Value;
|
||||
if (guidVal is Guid g) result.ObjectGuid = g;
|
||||
else if (guidVal is string s && Guid.TryParse(s, out Guid parsed)) result.ObjectGuid = parsed;
|
||||
}
|
||||
|
||||
AddMemberToDistributionGroup(name, memberGroup);
|
||||
SetDistributionGroupManagedBy(name, ownerGroup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Collect group details
|
||||
string[] dRoles = new string[] {
|
||||
eLiamAccessRoles.ExchangeMLMember.ToString(),
|
||||
eLiamAccessRoles.ExchangeMLOwner.ToString()
|
||||
};
|
||||
string[] dNames = new string[] {
|
||||
memberGroup,
|
||||
ownerGroup
|
||||
};
|
||||
|
||||
for (int i = 0; i < dRoles.Length; i++)
|
||||
{
|
||||
DirectoryEntry grpEntry = FindAdObject("(&(objectCategory=group)(sAMAccountName=" + dNames[i] + "))");
|
||||
if (grpEntry != null && grpEntry.Properties.Contains("objectSid") && grpEntry.Properties["objectSid"].Count > 0)
|
||||
{
|
||||
byte[] sidBytes = (byte[])grpEntry.Properties["objectSid"][0];
|
||||
string sid = new SecurityIdentifier(sidBytes, 0).Value;
|
||||
string distinguishedName = grpEntry.Properties["distinguishedName"][0].ToString();
|
||||
result.Groups.Add(Tuple.Create(dRoles[i], sid, dNames[i], distinguishedName));
|
||||
}
|
||||
}
|
||||
|
||||
return Tuple.Create(result.ObjectGuid, result.Groups);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setzt das ManagedBy-Attribut einer Distribution Group.
|
||||
/// </summary>
|
||||
private void SetDistributionGroupManagedBy(string groupName, string managerGroup)
|
||||
{
|
||||
using (var runspace = CreateRunspace())
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.Runspace = runspace;
|
||||
ps.AddCommand("Set-DistributionGroup")
|
||||
.AddParameter("Identity", groupName)
|
||||
.AddParameter("ManagedBy", managerGroup)
|
||||
.AddParameter("ErrorAction", "SilentlyContinue");
|
||||
ps.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hilfsmethode: SecureString in Klartext wandeln.
|
||||
/// </summary>
|
||||
private static string SecureStringToString(SecureString ss)
|
||||
{
|
||||
if (ss == null) return string.Empty;
|
||||
IntPtr ptr = Marshal.SecureStringToBSTR(ss);
|
||||
try
|
||||
{
|
||||
return Marshal.PtrToStringBSTR(ptr) ?? string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeBSTR(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
LiamExchange/LiamExchange.csproj
Normal file
102
LiamExchange/LiamExchange.csproj
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{12586A29-BB1E-49B4-B971-88E520D6A77C}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>LiamExchange</RootNamespace>
|
||||
<AssemblyName>LiamExchange</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Bcl.Cryptography, Version=9.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Cryptography.9.0.4\lib\net462\Microsoft.Bcl.Cryptography.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Formats.Asn1, Version=9.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Formats.Asn1.9.0.4\lib\net462\System.Formats.Asn1.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="C4IT.LIAM.Exchange.cs" />
|
||||
<Compile Include="ExchangeManager.Extensions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LiamBaseClasses\LiamBaseClasses.csproj">
|
||||
<Project>{3531c9e6-cf6e-458e-b604-4a5a8d1c7ab0}</Project>
|
||||
<Name>LiamBaseClasses</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\LiamHelper\LiamHelper.csproj">
|
||||
<Project>{6b0e73a6-f918-42d5-9525-d59d4d16283d}</Project>
|
||||
<Name>LiamHelper</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\LiamNtfs\LiamNtfs.csproj">
|
||||
<Project>{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}</Project>
|
||||
<Name>LiamNtfs</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="C4IT.LIAM.ExchangeManager.cs" />
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
10
LiamExchange/LiamExchange.csproj.vspscc
Normal file
10
LiamExchange/LiamExchange.csproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
33
LiamExchange/Properties/AssemblyInfo.cs
Normal file
33
LiamExchange/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("LiamExchange")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("LiamExchange")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2025")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("12586a29-bb1e-49b4-b971-88e520d6a77c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
11
LiamExchange/app.config
Normal file
11
LiamExchange/app.config
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
BIN
LiamExchange/bin/Debug/LiamBaseClasses.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamBaseClasses.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamExchange.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamExchange.dll
Normal file
Binary file not shown.
11
LiamExchange/bin/Debug/LiamExchange.dll.config
Normal file
11
LiamExchange/bin/Debug/LiamExchange.dll.config
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
BIN
LiamExchange/bin/Debug/LiamExchange.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamExchange.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamHelper.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamHelper.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamNtfs.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamNtfs.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamNtfs.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamNtfs.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.dll
Normal file
BIN
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.dll
Normal file
Binary file not shown.
1576
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.xml
Normal file
1576
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
LiamExchange/bin/Debug/Microsoft.Management.Infrastructure.dll
Normal file
BIN
LiamExchange/bin/Debug/Microsoft.Management.Infrastructure.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/Newtonsoft.Json.dll
Normal file
BIN
LiamExchange/bin/Debug/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/System.Buffers.dll
Normal file
BIN
LiamExchange/bin/Debug/System.Buffers.dll
Normal file
Binary file not shown.
38
LiamExchange/bin/Debug/System.Buffers.xml
Normal file
38
LiamExchange/bin/Debug/System.Buffers.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><doc>
|
||||
<assembly>
|
||||
<name>System.Buffers</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:System.Buffers.ArrayPool`1">
|
||||
<summary>Provides a resource pool that enables reusing instances of type <see cref="T[]"></see>.</summary>
|
||||
<typeparam name="T">The type of the objects that are in the resource pool.</typeparam>
|
||||
</member>
|
||||
<member name="M:System.Buffers.ArrayPool`1.#ctor">
|
||||
<summary>Initializes a new instance of the <see cref="T:System.Buffers.ArrayPool`1"></see> class.</summary>
|
||||
</member>
|
||||
<member name="M:System.Buffers.ArrayPool`1.Create">
|
||||
<summary>Creates a new instance of the <see cref="T:System.Buffers.ArrayPool`1"></see> class.</summary>
|
||||
<returns>A new instance of the <see cref="System.Buffers.ArrayPool`1"></see> class.</returns>
|
||||
</member>
|
||||
<member name="M:System.Buffers.ArrayPool`1.Create(System.Int32,System.Int32)">
|
||||
<summary>Creates a new instance of the <see cref="T:System.Buffers.ArrayPool`1"></see> class using the specifed configuration.</summary>
|
||||
<param name="maxArrayLength">The maximum length of an array instance that may be stored in the pool.</param>
|
||||
<param name="maxArraysPerBucket">The maximum number of array instances that may be stored in each bucket in the pool. The pool groups arrays of similar lengths into buckets for faster access.</param>
|
||||
<returns>A new instance of the <see cref="System.Buffers.ArrayPool`1"></see> class with the specified configuration.</returns>
|
||||
</member>
|
||||
<member name="M:System.Buffers.ArrayPool`1.Rent(System.Int32)">
|
||||
<summary>Retrieves a buffer that is at least the requested length.</summary>
|
||||
<param name="minimumLength">The minimum length of the array.</param>
|
||||
<returns>An array of type <see cref="T[]"></see> that is at least <paramref name="minimumLength">minimumLength</paramref> in length.</returns>
|
||||
</member>
|
||||
<member name="M:System.Buffers.ArrayPool`1.Return(`0[],System.Boolean)">
|
||||
<summary>Returns an array to the pool that was previously obtained using the <see cref="M:System.Buffers.ArrayPool`1.Rent(System.Int32)"></see> method on the same <see cref="T:System.Buffers.ArrayPool`1"></see> instance.</summary>
|
||||
<param name="array">A buffer to return to the pool that was previously obtained using the <see cref="M:System.Buffers.ArrayPool`1.Rent(System.Int32)"></see> method.</param>
|
||||
<param name="clearArray">Indicates whether the contents of the buffer should be cleared before reuse. If <paramref name="clearArray">clearArray</paramref> is set to true, and if the pool will store the buffer to enable subsequent reuse, the <see cref="M:System.Buffers.ArrayPool`1.Return(`0[],System.Boolean)"></see> method will clear the <paramref name="array">array</paramref> of its contents so that a subsequent caller using the <see cref="M:System.Buffers.ArrayPool`1.Rent(System.Int32)"></see> method will not see the content of the previous caller. If <paramref name="clearArray">clearArray</paramref> is set to false or if the pool will release the buffer, the array&#39;s contents are left unchanged.</param>
|
||||
</member>
|
||||
<member name="P:System.Buffers.ArrayPool`1.Shared">
|
||||
<summary>Gets a shared <see cref="T:System.Buffers.ArrayPool`1"></see> instance.</summary>
|
||||
<returns>A shared <see cref="System.Buffers.ArrayPool`1"></see> instance.</returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user