using System; using System.Reflection; using System.Threading.Tasks; using System.Web.Http; using System.Data; using System.Collections.Generic; using System.Xml; using System.IO; using Newtonsoft.Json; using Matrix42.Common; using update4u.SPS.DataLayer; using update4u.SPS.Security; using C4IT.Logging; using static C4IT.Logging.cLogManager; using System.Web.Http.Controllers; using C4IT.Matrix42.ServerInfo; using System.Dynamic; using C4IT.Licensing; using System.ComponentModel; using System.Linq; using System.Globalization; using System.Data.SqlClient; using System.Net.Sockets; using update4u.SPS.DataLayer.Command; using update4u.SPS.DataLayer.Transaction; using System.Net.Http; using System.Net; using System.Text; using System.Net.Http.Headers; using Matrix42.Pandora.Contracts.Action; namespace C4IT.LIAM { public static class cLiamM42Helper { public static dynamic ToDynamic(this object value) { IDictionary expando = new ExpandoObject(); foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) expando.Add(property.Name, property.GetValue(value)); return expando as ExpandoObject; } } [RoutePrefix("api/C4ITLiamWebApi")] public class LiamM42WebApiController : ApiController { public const string LiamProductGuid = "28757DE2-690F-4D3B-9AB7-4AB7FB630901"; public const string constFragmentNameDataAreaTargetPickupType = "C4IT_DataAreaTargetPickupType"; public const string constFragmentNameDataAreaMain = "C4IT_DataAreaClassBase"; public const string constFragmentNameConfigProviderMain = "C4IT_GCC_DataArea_Collector"; public const string constFragmentNameAddonConfigClassBase = "C4IT_AddonConfigClassBase"; public const string constFragmentNameConfigProviderBase = "SPSGenericConnectorConfigurationClassBase"; public const string constFragmentNameConfigProviderAdditionalAttributes = "C4IT_GCC_DataArea_Collector_AdditionalAttributes"; public const string constFragmentNameCustomTagBase = "C4IT_DataAreaCustomTagClassBase"; public const string constFragmentNameNamingConvention = "C4IT_LIAMNamingConvention"; public const string constFragmentNameConfigNamingConvention = "C4IT_LIAMConfigNamingConvention"; public const string constTypeNameConfigProvider = "C4IT_GCC_DataAreaCollectorType"; public const string constFragmentNameAccountAd = "SPSAccountClassAD"; public const string constFragmentNameAccountBase = "SPSAccountClassBase"; public const string constFragmentNameUserBase = "SPSUserClassBase"; public const string constFragmentNameCommon = "SPSCommonClassBase"; public const string constFragmentNameSVCServiceBookingClassBase = "SVCServiceBookingClassBase"; public const string sqlCSVBookingData = @" select da.technicalName as TechnicalName, -- TechnicalName s.Name as ServiceName, -- ServiceName u.LastName + ', ' + u.FirstName as ConsumerName, -- ConsumerName a.NBAccountName as AccountName, s.ArticleID, -- ArticleID o.TicketNumber as OrderNumber, -- OrderNumber b.BookingID, -- BookingID b.ProvisionedDate, -- ProvisionedDate da.ID as ID_noexport, -- Technisch notwendig, wird aber nicht exportiert b.Uninstalled as Deprovisioned, bu.ProvisionedDate as DeProvisioningDate from SVCServiceBookingClassBase b WITH (NOLOCK) left join SPSSelfServiceOrderItemClassBase o WITH (NOLOCK) on o.ID = b.[Order] left join SVCServiceBookingClassBase bu on bu.InstallationBooking = b.ID left join SPSArticleClassBase s WITH (NOLOCK) on b.[Service] = s.ID left join SPSCommonClassBase sf WITH (NOLOCK) on s.ServiceForm = sf.ID left join C4IT_DataAreaServiceConfigurationClassBase sc WITH (NOLOCK) on sc.[Expression-ObjectID] = sf.[Expression-ObjectID] left join C4IT_DataAreaSecurityGroupClassBase sg WITH (NOLOCK) on sc.SecurityGroup = sg.ID left join C4IT_DataAreaClassBase da WITH (NOLOCK) on (da.[Read] = sg.ID OR da.Write = sg.ID OR da.[Owner] = sg.ID) left join SPSUserClassBase u WITH (NOLOCK) on b.Consumer = u.ID left join SPSTargetingClassTarget t on b.[Target] = t.ID left join SPSAccountClassAD a on a.[Expression-ObjectID] = t.[Expression-ObjectID] where "; private static readonly Dictionary ProviderCacheByID = new Dictionary(); private static readonly Dictionary ProviderCacheByObjectID = new Dictionary(); public static bool IsInitialized { get; private set; } = false; private static readonly object initLock = new object(); protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); try { if (IsInitialized) return; lock (initLock) { if (IsInitialized) return; var Ass = Assembly.GetExecutingAssembly(); var LM = cLogManagerFile.CreateInstance(LocalMachine: true, A: Ass); var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); cLogManager.DefaultLogger.LogAssemblyInfo(Ass); IsInitialized = true; LogMethodEnd(CM); } } catch { } } [HttpGet] [Route("loadLicense")] public bool LoadLicensingInformation(bool force = false) { if (force) cC4ITLicenseM42ESM.Instance = null; if (cC4ITLicenseM42ESM.Instance == null) { new cC4ITLicenseM42ESM(new Guid(LiamProductGuid)); var strLicense = getLicenseString(); if (!string.IsNullOrEmpty(strLicense)) cC4ITLicenseM42ESM.Instance.LoadFromString(strLicense); } return cC4ITLicenseM42ESM.Instance.IsValid; } private string getLicenseString() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var ClassID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameAddonConfigClassBase); LogEntry($"Addon Config class ID: {ClassID}", LogLevels.Debug); var dataTable = FragmentRequest.SimpleLoad(ClassID, "license", "UsedInTypeC4IT_LIAMConfigurationType is not null"); if (dataTable?.Rows == null || dataTable.Rows.Count <= 0) { LogEntry($"Addon Config fragment not found: ClassID={ClassID}", LogLevels.Debug); return null; } var license = cLIAMHelper.getStringFromObject(dataTable.Rows[0]["license"]); LogEntry($"Addon Config license: {license}", LogLevels.Debug); return license; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } // Neue Methode [HttpPost] [Route("getCSVBookingData")] public HttpResponseMessage getCSVBookingData(ActionExecuteData actionExecuteData) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); var csvBuilder = new StringBuilder(); string serviceNameForFile = string.Empty; var distinctDataAreaIds = new HashSet(); try { if (actionExecuteData?.Objects == null || actionExecuteData.Objects.Length == 0) { return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("Keine ObjectIds übergeben.") }; } List dataAreaIds = new List(); foreach (ActionExecuteDataEntry entry in actionExecuteData.Objects) { if (entry.ObjectIds != null) { dataAreaIds.AddRange(entry.ObjectIds); } } if (dataAreaIds.Count == 0) { return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("Keine gültigen ObjectIds gefunden.") }; } var parameterNames = new List(); for (int i = 0; i < dataAreaIds.Count; i++) { parameterNames.Add($"@dataareaid{i}"); } string whereClause = "da.[Expression-ObjectId] IN (" + string.Join(", ", parameterNames) + ")"; string sqlQuery = sqlCSVBookingData + whereClause; using (var sqlCommand = new SqlCommand(sqlQuery)) { for (int i = 0; i < dataAreaIds.Count; i++) { sqlCommand.Parameters.AddWithValue($"@dataareaid{i}", dataAreaIds[i]); } using (var sPSTransactionScope = new SPSTransactionScope()) using (IDataReader dataReader = DirectDbCommand.ExecuteReader(sqlCommand)) { // Spaltennamen ermitteln, Spalten mit '_noexport' ausschließen var columnNames = new List(); for (int i = 0; i < dataReader.FieldCount; i++) { string columnName = dataReader.GetName(i); if (!columnName.EndsWith("_noexport")) { columnNames.Add(columnName); } } // CSV-Header erstellen csvBuilder.AppendLine("sep=;"); csvBuilder.AppendLine(string.Join(";", columnNames)); bool isFirstRow = true; while (dataReader.Read()) { // Zugriff auf 'ID_noexport' für interne Logik, ohne Export if (dataReader["ID_noexport"] != DBNull.Value) { distinctDataAreaIds.Add((Guid)dataReader["ID_noexport"]); } if (isFirstRow) { if (dataReader["ServiceName"] != DBNull.Value) { serviceNameForFile = dataReader["ServiceName"].ToString(); } isFirstRow = false; } // Werte nur der exportierten Spalten sammeln var rowValues = new List(); foreach (var columnName in columnNames) { var value = dataReader[columnName]; var stringValue = value == DBNull.Value ? string.Empty : value.ToString(); rowValues.Add(EscapeForCsv(stringValue)); } csvBuilder.AppendLine(string.Join(";", rowValues)); } sPSTransactionScope.Complete(); } } } catch (Exception ex) { LogException(ex); return new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent("Fehler bei der Verarbeitung der Anfrage.") }; } finally { LogMethodEnd(CM); } // Dateinamen erstellen string fileName; if (distinctDataAreaIds.Count == 1) { int index = serviceNameForFile.IndexOf('['); if (index > 0) { serviceNameForFile = serviceNameForFile.Substring(0, index).TrimEnd(' ', '-'); } var safeServiceName = CleanFileName(serviceNameForFile); fileName = $"Servicebuchungen_{safeServiceName}_{DateTime.Now:yyyyMMdd}.csv"; } else { fileName = $"Servicebuchungen_{DateTime.Now:yyyyMMdd}.csv"; } var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(csvBuilder.ToString(), Encoding.UTF8, "text/csv") }; response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName }; return response; } /* Neue Methode [HttpPost] [Route("getCSVBookingData")] public HttpResponseMessage getCSVBookingData(ActionExecuteData actionExecuteData) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); var csvBuilder = new StringBuilder(); string serviceNameForFile = string.Empty; var distinctDataAreaIds = new HashSet(); try { if (actionExecuteData?.Objects == null || actionExecuteData.Objects.Length == 0) { return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("Keine ObjectIds übergeben.") }; } List dataAreaIds = new List(); foreach (ActionExecuteDataEntry entry in actionExecuteData.Objects) { if (entry.ObjectIds != null) { dataAreaIds.AddRange(entry.ObjectIds); } } if (dataAreaIds.Count == 0) { return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("Keine gültigen ObjectIds gefunden.") }; } var parameterNames = new List(); for (int i = 0; i < dataAreaIds.Count; i++) { parameterNames.Add($"@dataareaid{i}"); } string whereClause = "da.[Expression-ObjectID] IN (" + string.Join(", ", parameterNames) + ")"; string sqlQuery = sqlCSVBookingData + whereClause; // CSV-Aufbau var columnNames = new List(); bool headerWritten = false; bool firstRow = true; DirectDbCommand.ExecuteReader( dbCmd => { dbCmd.CommandText = sqlQuery; for (int i = 0; i < dataAreaIds.Count; i++) { var p = dbCmd.CreateParameter(); p.ParameterName = $"@dataareaid{i}"; p.DbType = DbType.Guid; p.Value = dataAreaIds[i]; dbCmd.Parameters.Add(p); } }, reader => { // Header einmalig aus dem ersten gelesenen Datensatz ableiten if (!headerWritten) { for (int i = 0; i < reader.FieldCount; i++) { var name = reader.GetName(i); if (!name.EndsWith("_noexport", StringComparison.OrdinalIgnoreCase)) columnNames.Add(name); } csvBuilder.AppendLine("sep=;"); csvBuilder.AppendLine(string.Join(";", columnNames)); headerWritten = true; } // interne Logik mit ID_noexport (wird nicht exportiert) int idxNoExport = reader.GetOrdinal("ID_noexport"); if (!reader.IsDBNull(idxNoExport)) distinctDataAreaIds.Add(reader.GetGuid(idxNoExport)); // Dateiname: ServiceName aus erster Zeile merken if (firstRow) { int idxServiceName = reader.GetOrdinal("ServiceName"); if (!reader.IsDBNull(idxServiceName)) serviceNameForFile = reader.GetString(idxServiceName); firstRow = false; } // Werte der exportierten Spalten schreiben var rowValues = new List(columnNames.Count); foreach (var col in columnNames) { var val = reader[col]; rowValues.Add(EscapeForCsv(val == DBNull.Value ? string.Empty : Convert.ToString(val))); } csvBuilder.AppendLine(string.Join(";", rowValues)); } ); } catch (Exception ex) { LogException(ex); return new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent("Fehler bei der Verarbeitung der Anfrage.") }; } finally { LogMethodEnd(CM); } // Dateinamen erstellen string fileName; if (distinctDataAreaIds.Count == 1) { int index = serviceNameForFile.IndexOf('['); if (index > 0) { serviceNameForFile = serviceNameForFile.Substring(0, index).TrimEnd(' ', '-'); } var safeServiceName = CleanFileName(serviceNameForFile); fileName = $"Servicebuchungen_{safeServiceName}_{DateTime.Now:yyyyMMdd}.csv"; } else { fileName = $"Servicebuchungen_{DateTime.Now:yyyyMMdd}.csv"; } var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(csvBuilder.ToString(), Encoding.UTF8, "text/csv") }; response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName }; return response; } */ // Hilfsmethoden private string EscapeForCsv(string field) { if (field.Contains(";") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r")) { field = field.Replace("\"", "\"\""); field = $"\"{field}\""; } return field; } private string CleanFileName(string fileName) { foreach (char c in Path.GetInvalidFileNameChars()) { fileName = fileName.Replace(c.ToString(), string.Empty); } return fileName; } private cLiamProviderBase CreateProviderInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) { LoadLicensingInformation(); ProviderData.ReplaceCustomTags(); switch (ProviderData.ProviderType) { case eLiamProviderTypes.MsTeams: return new cLiamProviderMsTeams(LiamConfiguration, ProviderData); case eLiamProviderTypes.Ntfs: return new cLiamProviderNtfs(LiamConfiguration, ProviderData); case eLiamProviderTypes.ActiveDirectory: return new cLiamProviderAD(LiamConfiguration, ProviderData); } return null; } private static ProviderCacheEntry AddCache(Guid ID, Guid ObjectID, cLiamProviderBase Provider) { var Entry = new ProviderCacheEntry() { ID = ID, ObjectID = ObjectID, ValidUntil = DateTime.UtcNow + TimeSpan.FromMinutes(15), Provider = Provider }; ProviderCacheByID[ID] = Entry; ProviderCacheByObjectID[ObjectID] = Entry; return Entry; } private static ProviderCacheEntry GetCacheByID(Guid ID) { if (!ProviderCacheByID.TryGetValue(ID, out var Entry)) return null; if (Entry.ValidUntil < DateTime.UtcNow) { ProviderCacheByID.Remove(ID); ProviderCacheByObjectID.Remove(Entry.ObjectID); return null; } return Entry; } private static ProviderCacheEntry GetCacheByObjectID(Guid ObjectID) { if (!ProviderCacheByObjectID.TryGetValue(ObjectID, out var Entry)) return null; if (Entry.ValidUntil < DateTime.UtcNow) { ProviderCacheByID.Remove(Entry.ID); ProviderCacheByObjectID.Remove(ObjectID); return null; } return Entry; } [Route("getVersionInfo"), HttpGet] public LiamApiVersionInfo getVersionInfo() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); var RetVal = new LiamApiVersionInfo(); try { var A = Assembly.GetExecutingAssembly(); RetVal.ProductVersion = A.GetCustomAttribute()?.InformationalVersion; RetVal.AssemblyVersion = A.GetName().Version.ToString(); RetVal.ProductName = A.GetCustomAttribute()?.Product; RetVal.AssemblyName = A.ManifestModule.ToString(); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return RetVal; } private bool TryLoadProviderFragments(Guid providerConfigClassID, out Guid objectId, out DataTable tblMain, out DataTable tblBase, out DataTable tblAdditionalAttr, out DataTable tblNamingConvention, out DataTable tblCustomTags) { objectId = Guid.Empty; tblMain = null; tblBase = null; tblAdditionalAttr = null; tblNamingConvention = null; tblCustomTags = null; try { var classID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameConfigProviderMain); LogEntry($"Config provider class ID: {classID}", LogLevels.Debug); var fragment = FragmentRequest.GetSPSFragment(classID, providerConfigClassID); if (fragment == null) { LogEntry($"Provider config fragment not found: ClassID={classID}, FragmentId={providerConfigClassID}", LogLevels.Debug); return false; } objectId = fragment.ObjectID; if (objectId == Guid.Empty) { LogEntry($"Provider config fragment not found: ClassID={classID}, FragmentId={providerConfigClassID}", LogLevels.Debug); return false; } tblMain = fragment.FragmentTable; LogEntry($"Config provider object ID: {objectId}", LogLevels.Debug); classID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameConfigProviderBase); LogEntry($"Config provider base class ID: {classID}", LogLevels.Debug); Guid[] ids = { objectId }; tblBase = FragmentRequestBase.SimpleLoad(classID, "Account, Password", AsqlHelper.BuildInCondition("[Expression-ObjectID]", ids)); if (tblBase?.Rows == null || tblBase.Rows.Count <= 0) { LogEntry($"Provider config base fragment not found: ClassId={classID}, ObjectId={objectId}", LogLevels.Debug); return false; } classID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameConfigProviderAdditionalAttributes); LogEntry($"Config provider additional config class ID: {classID}", LogLevels.Debug); tblAdditionalAttr = FragmentRequestBase.SimpleLoad(classID, "Name, Value", AsqlHelper.BuildInCondition("[Expression-ObjectID]", ids)); if (tblAdditionalAttr == null) { LogEntry($"Provider additional config class fragment not found: ClassId={classID}, ObjectId={objectId}", LogLevels.Debug); return false; } classID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameCustomTagBase); LogEntry($"Custom Tag class ID: {classID}", LogLevels.Debug); tblCustomTags = FragmentRequestBase.SimpleLoad(classID, "Key, Name", $"[Expression-ObjectID]='{objectId}'") ?? new DataTable(); classID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameConfigNamingConvention); LogEntry($"Naming convention config class ID: {classID}", LogLevels.Debug); tblNamingConvention = FragmentRequestBase.SimpleLoad(classID, "ID, Usage, NamingConvention.Description as Description, NamingConvention.DescriptionTemplate as DescriptionTemplate, " + "NamingConvention.Name as Name, NamingConvention.NamingTemplate as NamingTemplate, NamingConvention.Wildcard as Wildcard", $"[Expression-ObjectID]='{objectId}'") ?? new DataTable(); return true; } catch (Exception e) { LogException(e); return false; } } private cLiamProviderData buildProviderData(DataTable dtMain, DataTable dtBase, DataTable dtAdditional, DataTable dtNamingConvention, DataTable dtCustomTag, bool includeSecret, out string sanitizedJson) { sanitizedJson = null; if (dtMain?.Rows == null || dtMain.Rows.Count <= 0) return null; if (dtBase?.Rows == null || dtBase.Rows.Count <= 0) return null; if (dtAdditional == null) return null; var dataMain = dtMain.Rows[0]; var dataBase = dtBase.Rows[0]; var encPW = cLIAMHelper.getStringFromObject(dataBase["Password"]); if (!CryptoManager.Instance.TryDecryptDBText(encPW, out string password)) password = encPW; var providerData = new cLiamProviderData() { Domain = cLIAMHelper.getStringFromObject(dataMain["GCCDomain"]), Credential = new cLiamCredential() { Domain = cLIAMHelper.getStringFromObject(dataMain["GCCDomain"]), Identification = cLIAMHelper.getStringFromObject(dataBase["Account"]), Secret = "***" }, RootPath = cLIAMHelper.getStringFromObject(dataMain["GCCTarget"]), MaxDepth = cLIAMHelper.getIntFromObject(dataMain["GCCMaxDepth"]), GroupFilter = cLIAMHelper.getStringFromObject(dataMain["GCCgroupLDAPFilter"]), GroupPath = cLIAMHelper.getStringFromObject(dataMain["GCCgroupOUPath"]), GroupStrategy = (eLiamGroupStrategies)cLIAMHelper.getIntFromObject(dataMain["GCCPermissionGroupStrategy"]), ProviderType = (eLiamProviderTypes)cLIAMHelper.getIntFromObject(dataMain["GCCtargetType"]) }; if (dtAdditional?.Rows != null) { foreach (DataRow row in dtAdditional.Rows) { var name = cLIAMHelper.getStringFromObject(row["Name"]); var value = cLIAMHelper.getStringFromObject(row["Value"]); if (!string.IsNullOrEmpty(name)) providerData.AdditionalConfiguration[name] = value; } } if (dtCustomTag?.Rows != null) { foreach (DataRow row in dtCustomTag.Rows) { var name = cLIAMHelper.getStringFromObject(row["Key"]); var value = cLIAMHelper.getStringFromObject(row["Name"]); if (!string.IsNullOrEmpty(name)) providerData.CustomTags[name] = value; } } if (dtNamingConvention?.Rows != null) { foreach (DataRow row in dtNamingConvention.Rows) { var usage = cLIAMHelper.getIntFromObject(row["Usage"]); var accessRole = eLiamAccessRoles.Read; var scope = eLiamAccessRoleScopes.Unknown; switch (usage) { case -10: accessRole = eLiamAccessRoles.Traverse; scope = eLiamAccessRoleScopes.Global; break; case 10: accessRole = eLiamAccessRoles.Read; scope = eLiamAccessRoleScopes.Global; break; case 20: accessRole = eLiamAccessRoles.Write; scope = eLiamAccessRoleScopes.Global; break; case 30: accessRole = eLiamAccessRoles.Owner; scope = eLiamAccessRoleScopes.Global; break; case 40: accessRole = eLiamAccessRoles.Read; scope = eLiamAccessRoleScopes.DomainLocal; break; case 50: accessRole = eLiamAccessRoles.Write; scope = eLiamAccessRoleScopes.DomainLocal; break; case 60: accessRole = eLiamAccessRoles.Owner; scope = eLiamAccessRoleScopes.DomainLocal; break; case 100: accessRole = eLiamAccessRoles.ADOwner; scope = eLiamAccessRoleScopes.Global; break; case 110: accessRole = eLiamAccessRoles.ADMember; scope = eLiamAccessRoleScopes.Global; break; case 200: accessRole = eLiamAccessRoles.ExchangeMLMember; scope = eLiamAccessRoleScopes.Universal; break; case 210: accessRole = eLiamAccessRoles.ExchangeMLOwner; scope = eLiamAccessRoleScopes.Universal; break; case 250: accessRole = eLiamAccessRoles.ExchangeSMBFullAccess; scope = eLiamAccessRoleScopes.Universal; break; case 260: accessRole = eLiamAccessRoles.ExchangeSMBSendAs; scope = eLiamAccessRoleScopes.Universal; break; case 270: accessRole = eLiamAccessRoles.ExchangeSMBOwner; scope = eLiamAccessRoleScopes.Universal; break; } providerData.NamingConventions.Add(new cLiamNamingConvention() { AccessRole = accessRole, Scope = scope, Description = cLIAMHelper.getStringFromObject(row["Description"]), DescriptionTemplate = cLIAMHelper.getStringFromObject(row["DescriptionTemplate"]), Name = cLIAMHelper.getStringFromObject(row["Name"]), NamingTemplate = cLIAMHelper.getStringFromObject(row["NamingTemplate"]), Wildcard = cLIAMHelper.getStringFromObject(row["Wildcard"]) }); } } sanitizedJson = JsonConvert.SerializeObject(providerData, Newtonsoft.Json.Formatting.Indented); if (includeSecret && providerData.Credential != null) providerData.Credential.Secret = password; return providerData; } private cLiamProviderBase createProvider(DataTable dtMain, DataTable dtBase, DataTable dtAdditional, DataTable dtNamingConvention = null, DataTable dtCustomTag = null) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var DataProviderData = buildProviderData(dtMain, dtBase, dtAdditional, dtNamingConvention, dtCustomTag, includeSecret: true, out var sanitizedJson); if (DataProviderData == null) return null; LogEntry("Provider configuration (sanitized JSON, copy for diagnostics tool):", LogLevels.Info); LogEntry(sanitizedJson, LogLevels.Info); var DataProvider = CreateProviderInstance(new cLiamConfiguration(), DataProviderData); return DataProvider; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("initializeDataProvider"), HttpGet] public async Task initializeDataProvider(Guid ProviderConfigClassID, bool force = false) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (cC4ITLicenseM42ESM.Instance == null) LoadLicensingInformation(); if (!cC4ITLicenseM42ESM.Instance.IsValid) { LogEntry($"Error: License not valid", LogLevels.Error); return false; } var DataProvider = await getDataProvider(ProviderConfigClassID, force); return DataProvider != null; } catch (Exception E) { LogException(E); return false; } finally { LogMethodEnd(CM); } } [Route("exportProviderConfiguration"), HttpGet] public IHttpActionResult exportProviderConfiguration(Guid ProviderConfigClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (cC4ITLicenseM42ESM.Instance == null) LoadLicensingInformation(); if (!cC4ITLicenseM42ESM.Instance.IsValid) { LogEntry($"Error: License not valid", LogLevels.Error); return Content(HttpStatusCode.Forbidden, "License not valid"); } if (!TryLoadProviderFragments(ProviderConfigClassID, out var objectId, out var tblMain, out var tblBase, out var tblAdditionalAttr, out var tblNamingConvention, out var tblCustomTags)) { return Content(HttpStatusCode.NotFound, $"Provider configuration '{ProviderConfigClassID}' not found."); } var providerData = buildProviderData(tblMain, tblBase, tblAdditionalAttr, tblNamingConvention, tblCustomTags, includeSecret: false, out var sanitizedJson); if (providerData == null) return Content(HttpStatusCode.InternalServerError, "Provider configuration could not be loaded."); var export = new ProviderConfigurationExport { ProviderConfigClassID = ProviderConfigClassID, ProviderConfigObjectID = objectId, SanitizedJson = sanitizedJson, Configuration = providerData, GeneratedAtUtc = DateTime.UtcNow }; return Ok(export); } catch (Exception E) { LogException(E); return InternalServerError(E); } finally { LogMethodEnd(CM); } } private async Task getDataProvider(Guid ProviderConfigClassID, bool force = false) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!force) { var Provider = GetCacheByID(ProviderConfigClassID); if (Provider != null) { LogEntry($"provider already cached", LogLevels.Debug); return Provider; } } if (!TryLoadProviderFragments(ProviderConfigClassID, out var ObjectID, out var tblMain, out var tblBase, out var tblAdditionalAttr, out var tblNamingConvention, out var tblCustomTags)) return null; var DataProvider = createProvider(tblMain, tblBase, tblAdditionalAttr, tblNamingConvention, tblCustomTags); if (DataProvider == null) { LogEntry($"Provider configuration '{ProviderConfigClassID}' could not be materialized.", LogLevels.Warning); return null; } var validLogon = await DataProvider.LogonAsync(); if (!validLogon) return null; var RetVal = AddCache(ProviderConfigClassID, ObjectID, DataProvider); return RetVal; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("initializeDataProviderByObjectID"), HttpGet] public async Task initializeDataProviderByObjectID(Guid ObjectID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (cC4ITLicenseM42ESM.Instance == null) LoadLicensingInformation(); if (!cC4ITLicenseM42ESM.Instance.IsValid) { LogEntry($"Error: License not valid", LogLevels.Error); return Guid.Empty; } var Provider = GetCacheByObjectID(ObjectID); if (Provider != null) { LogEntry($"provider already cached", LogLevels.Debug); return Provider.ID; } var TypeID = SPSDataEngineSchemaReader.TypeGetIDFromName(constTypeNameConfigProvider); LogEntry($"Config provider class ID: {TypeID}", LogLevels.Debug); SPSObject spsObject = ObjectRequest.GetSPSObject(TypeID, ObjectID); if (spsObject == null) { LogEntry($"Provider config type not found: TypeID={TypeID}, ObjectID={ObjectID}", LogLevels.Debug); return Guid.Empty; } var tblMain = spsObject.ClassTable[constFragmentNameConfigProviderMain]; if (tblMain == null) { LogEntry($"Provider config class not found: Type={constFragmentNameConfigProviderMain}, ObjectID={ObjectID}", LogLevels.Debug); return Guid.Empty; } var tblBase = spsObject.ClassTable[constFragmentNameConfigProviderBase]; if (tblBase == null) { LogEntry($"Provider config class not found: Type={constFragmentNameConfigProviderBase}, ObjectID={ObjectID}", LogLevels.Debug); return Guid.Empty; } var tblAdditionalAttributes = spsObject.ClassTable[constFragmentNameConfigProviderAdditionalAttributes]; if (tblAdditionalAttributes == null) { LogEntry($"Provider additional config class not found: Type={constFragmentNameConfigProviderAdditionalAttributes}, ObjectID={ObjectID}", LogLevels.Debug); return Guid.Empty; } var DataProvider = createProvider(tblMain, tblBase, tblAdditionalAttributes); var RetVal = await DataProvider.LogonAsync(); if (!RetVal) return Guid.Empty; var ID = cLIAMHelper.getGuidFromObject(tblMain.Rows[0]["ID"]); AddCache(ID, ObjectID, DataProvider); return ID; } catch (Exception E) { LogException(E); return Guid.Empty; } finally { LogMethodEnd(CM); } } [Route("getDataAreasOwner"), HttpGet] public async Task getDataAreasOwner(Guid ProviderConfigClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return ""; } var ProviderEntry = await getDataProvider(ProviderConfigClassID); if (ProviderEntry == null) { LogEntry($"Could not initialize Provider config class with ID {ProviderConfigClassID}", LogLevels.Warning); return null; } var lstDataAreas = await ProviderEntry.Provider.getDataAreasAsync(ProviderEntry.Provider.MaxDepth); if (lstDataAreas == null || lstDataAreas.Count == 0) { LogEntry($"No data areas found for Provider config class with ID {ProviderConfigClassID}", LogLevels.Warning); return null; } var xDoc = new XmlDocument(); xDoc.LoadXml(""); var xNode = xDoc.SelectSingleNode("DataAreaOwners/Owners"); foreach (var DA in lstDataAreas) { var Users = await DA.GetOwnersAsync(); if (Users == null) continue; var Persons = getPersonsFromUsers(Users); foreach (var Person in Persons) { var xItem = xDoc.CreateElement("Owner"); xNode.AppendChild(xItem); cLIAMHelper.AddXmlElement(xItem, "DataAreaTechnicalName", DA.UID); cLIAMHelper.AddXmlElement(xItem, "PersonID", Person.ToString()); } } using (var sw = new StringWriter()) { using (var xw = new XmlTextWriter(sw)) { xDoc.WriteTo(xw); return sw.ToString(); } } } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("getSecurityGroupsFromProvider"), HttpGet] public async Task> getSecurityGroupsFromProvider(Guid ProviderConfigClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new List(); } var ProviderEntry = await getDataProvider(ProviderConfigClassID); if (ProviderEntry == null) { LogEntry($"Could not initialize Provider config class with ID {ProviderConfigClassID}", LogLevels.Warning); return new List(); } var lstSecurityGroups = await ProviderEntry.Provider.getSecurityGroupsAsync(ProviderEntry.Provider.GroupFilter); if (lstSecurityGroups == null || lstSecurityGroups.Count == 0) { LogEntry($"No security groups found for Provider config class with ID {ProviderConfigClassID}", LogLevels.Warning); return new List(); } var SGs = new List(); foreach (var SecurityGroup in lstSecurityGroups) { string uid = null; string scope = null; if (SecurityGroup is cLiamAdGroup adGroup) { uid = adGroup.dn; scope = adGroup.scope; } else if (SecurityGroup is cLiamAdGroup2 adGroup2) { uid = adGroup2.dn; scope = adGroup2.scope; } SGs.Add(new SecurityGroupEntry() { DisplayName = SecurityGroup.TechnicalName, TechnicalName = SecurityGroup.UID, TargetType = ((int)SecurityGroup.Provider.ProviderType).ToString(), UID = uid, Scope = scope }); } return SGs; } catch (Exception E) { LogException(E); return new List(); } finally { LogMethodEnd(CM); } } [Route("getDataAreasFromProvider"), HttpGet] public async Task> getDataAreasFromProvider(Guid ProviderConfigClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return Enumerable.Empty(); } var ProviderEntry = await getDataProvider(ProviderConfigClassID); if (ProviderEntry == null) { LogEntry($"Could not initialize Provider config class with ID {ProviderConfigClassID}", LogLevels.Warning); return Enumerable.Empty(); } var lstDataAreas = await ProviderEntry.Provider.getDataAreasAsync(ProviderEntry.Provider.MaxDepth); if (lstDataAreas == null || lstDataAreas.Count == 0) { LogEntry($"No data areas found for Provider config class with ID {ProviderConfigClassID}", LogLevels.Warning); return Enumerable.Empty(); } return lstDataAreas.Select(DataArea => { var DataAreaNtfsFolder = DataArea as cLiamNtfsFolder; var DataAreaADGroup = DataArea as cLiamAdGroupAsDataArea; string owner = DataAreaADGroup?.ManagedBySID ?? DataAreaNtfsFolder?.OwnerGroupIdentifier ?? string.Empty; string write = DataAreaADGroup?.UID ?? DataAreaNtfsFolder?.WriteGroupIdentifier ?? string.Empty; return new DataAreaEntry { DisplayName = DataArea.DisplayName ?? string.Empty, UID = DataArea.UID, TechnicalName = DataArea.TechnicalName, Description = DataAreaADGroup?.Description ?? string.Empty, TargetType = ((int)DataArea.Provider.ProviderType).ToString(), ParentUID = DataArea.ParentUID ?? string.Empty, Level = DataArea.Level.ToString(), ConfigurationId = ProviderEntry.ObjectID.ToString(), DataAreaType = DataArea.DataType.ToString(), DataAreaTypeId = (int)DataArea.DataType, Owner = owner, Write = write, Read = DataAreaNtfsFolder?.ReadGroupIdentifier ?? string.Empty, Traverse = DataAreaNtfsFolder?.TraverseGroupIdentifier ?? string.Empty, CreatedDate = DataAreaNtfsFolder?.CreatedDate ?? DateTime.MinValue.ToString("o"), }; }).ToList(); } catch (Exception E) { LogException(E); return Enumerable.Empty(); } finally { LogMethodEnd(CM); } } private async Task getDataAreaFromUID(string UID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var ProviderID = cLIAMHelper.getUidItem(ref UID); if (!Guid.TryParse(ProviderID, out var ProviderGuid)) { LogEntry($"No valid Provider config class ID in UID: {UID}", LogLevels.Warning); return null; } var ProviderEntry = await getDataProvider(ProviderGuid); if (ProviderEntry == null) { LogEntry($"Could not initialize Provider config class with ID {ProviderGuid}", LogLevels.Warning); return null; } var DA = await ProviderEntry.Provider.LoadDataArea(UID); if (DA == null) { LogEntry($"Could not load data area with UID '{UID}' from provider with ID '{ProviderGuid}'", LogLevels.Warning); return null; } return DA; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("getChildsFromUID"), HttpGet] public async Task> getChildsFromUID(string UID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new List(); } var myUID = UID; var DA = await getDataAreaFromUID(UID); if (DA == null) return new List(); var Childs = await DA.getChildrenAsync(0); if (Childs == null) { LogEntry($"Error while resolving data area children for UID: {UID}", LogLevels.Warning); return new List(); } var ProviderID = cLIAMHelper.getUidItem(ref myUID); var RetVal = Childs.Select(ChildEntry => new LiamDataAreaEntry { UID = $"{ProviderID} | {ChildEntry.UID}", DisplayName = ChildEntry.TechnicalName, SupportsPermissions = ChildEntry.SupportsPermissions }).ToList(); return RetVal; } catch (Exception E) { LogException(E); return new List(); } finally { LogMethodEnd(CM); } } [Route("getChildsFromDataArea"), HttpGet] public async Task> getChildsFromDataArea(Guid DataAreaClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new List(); } var DA = await getDataAreaFromId(DataAreaClassID); if (DA == null) return new List(); var lstChilds = await DA.dataArea.getChildrenAsync(); if (lstChilds == null) { LogEntry($"Error getting children of data area with UID: {DA.dataArea.UID}", LogLevels.Warning); return new List(); } LogEntry($"Number of children: {lstChilds.Count}", LogLevels.Debug); var RetVal = lstChilds.Select(ChildEntry => new LiamDataAreaEntry { UID = $"{DA.configId} | {ChildEntry.UID}", DisplayName = ChildEntry.TechnicalName, SupportsPermissions = ChildEntry.SupportsPermissions }).ToList(); return RetVal; } catch (Exception E) { LogException(E); return new List(); } finally { LogMethodEnd(CM); } } internal class cGetDataAreaResult { internal cLiamDataAreaBase dataArea; internal Guid configId; } private async Task getDataAreaFromId(Guid DataAreaClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var ClassID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameDataAreaMain); LogEntry($"Data area class ID: {ClassID}", LogLevels.Debug); var FragDataArea = FragmentRequest.GetSPSFragment(ClassID, DataAreaClassID, "DataAreaConfiguration,technicalName, Owner.uniqueID as ownerRef"); if (FragDataArea == null) { LogEntry($"Data area fragment not found: ClassID={ClassID}, FragmentId={DataAreaClassID}", LogLevels.Debug); return null; } var ConfigID = cLIAMHelper.getGuidFromObject(FragDataArea["DataAreaConfiguration"]); if (ConfigID == Guid.Empty) { LogEntry("DataAreaConfiguration value not found.", LogLevels.Warning); return null; } LogEntry($"Config provider class ID: {ConfigID}", LogLevels.Debug); var ConfigProviderEntry = await getDataProvider(ConfigID); if (ConfigProviderEntry == null) { LogEntry($"Could not load Config Provider from cache with ID: {ConfigID}", LogLevels.Debug); return null; } var UID = cLIAMHelper.getStringFromObject(FragDataArea["technicalName"]); LogEntry($"Data area UID: {UID}", LogLevels.Debug); var DA = await ConfigProviderEntry.Provider.LoadDataArea(UID); DA.OwnerRef = cLIAMHelper.getStringFromObject(FragDataArea["ownerRef"]); if (DA == null) { LogEntry($"Could not find LIAM data area with UID: {UID}", LogLevels.Debug); return null; } return new cGetDataAreaResult { dataArea = DA, configId = ConfigID }; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("getOwnerInfosFromDataArea"), HttpGet] public async Task> getOwnerInfosFromDataArea(Guid DataAreaClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new List(); } var DAResult = await getDataAreaFromId(DataAreaClassID); if (DAResult == null) return new List(); var lstOwners = await DAResult.dataArea.GetOwnersAsync(); if (lstOwners == null) { LogEntry($"Error getting owners of data area with UID: {DAResult.dataArea.UID}", LogLevels.Warning); return new List(); } LogEntry($"Number of owners: {lstOwners.Count}", LogLevels.Debug); return lstOwners; } catch (Exception E) { LogException(E); return new List(); } finally { LogMethodEnd(CM); } } private List getPersonsFromUsers(List Users) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var AccountAdClassId = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameAccountAd); var AccountBaseClassId = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameAccountBase); var UserBaseClassId = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameUserBase); var CommonClassId = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameCommon); var ListOwners = new List(); foreach (var OwnerEntry in Users) { if (string.IsNullOrEmpty(OwnerEntry.UserPrincipalName)) continue; var FilterValues = new List { OwnerEntry.UserPrincipalName }; var Filter = AsqlHelper.BuildInCondition("UserPrincipalName", FilterValues); LogEntry($"ASql Filter: {Filter}"); var tbl = FragmentRequestBase.SimpleLoad(AccountAdClassId, "[Expression-ObjectID] as Id, UserPrincipalName", Filter); if (tbl?.Rows == null) { LogEntry($"No AD account entry list found with UserPrincipalName='{OwnerEntry.UserPrincipalName}'", LogLevels.Warning); continue; } foreach (DataRow AdEntry in tbl.Rows) { var AdId = cLIAMHelper.getGuidFromObject(AdEntry["ID"]); if (AdId == Guid.Empty) { LogEntry("No expression object ID found for AccountAd entry", LogLevels.Warning); continue; } Guid[] ids2 = { AdId }; var tbl2 = FragmentRequestBase.SimpleLoad(AccountBaseClassId, "Owner", AsqlHelper.BuildInCondition("[Expression-ObjectID]", ids2)); if (tbl2?.Rows == null || tbl2.Rows.Count == 0) { LogEntry($"Account class base fragment not found: ClassId={AccountBaseClassId}, ObjectId={AdId}", LogLevels.Debug); continue; } var OwnerID = cLIAMHelper.getGuidFromObject(tbl2.Rows[0]["Owner"]); if (OwnerID == Guid.Empty) { LogEntry($"Could not get Owner ID for account class base: ObjectId={AdId}", LogLevels.Debug); continue; } var FragUserBase = FragmentRequest.GetSPSFragment(UserBaseClassId, OwnerID); if (FragUserBase == null) { LogEntry($"User class base entry not found: ClassID={UserBaseClassId}, FragmentId={OwnerID}", LogLevels.Debug); continue; } var UserID = cLIAMHelper.getGuidFromObject(FragUserBase["ID"]); var UserObjectID = cLIAMHelper.getGuidFromObject(FragUserBase["Expression-ObjectID"]); Guid[] ids3 = { UserObjectID }; var tbl3 = FragmentRequestBase.SimpleLoad(CommonClassId, "State", AsqlHelper.BuildInCondition("[Expression-ObjectID]", ids3)); if (tbl3?.Rows == null || tbl3.Rows.Count == 0) { LogEntry($"Common class base fragment not found: ClassId={CommonClassId}, ObjectId={UserObjectID}", LogLevels.Debug); continue; } var State = cLIAMHelper.getIntFromObject(tbl3.Rows[0]["State"]); LogEntry($"User found: ID={UserID}, ObjectID={UserObjectID}, State={State}", LogLevels.Debug); if (State == 2023) ListOwners.Add(UserID); else LogEntry("User is not active", LogLevels.Debug); } } return ListOwners; } catch (Exception E) { LogException(E); return new List(); } finally { LogMethodEnd(CM); } } [Route("getOwnersFromDataArea"), HttpGet] public async Task> getOwnersFromDataArea(Guid DataAreaClassID) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var OwnersInfo = await getOwnerInfosFromDataArea(DataAreaClassID); if (OwnersInfo == null) return new List(); return getPersonsFromUsers(OwnersInfo); } catch (Exception E) { LogException(E); return new List(); } finally { LogMethodEnd(CM); } } #if DEBUG [Route("grantPermissionByEMail_Debug"), HttpGet] public async Task grantPermissionByEMail_Debug(string UID, string EMail, int AccessType) { return await grantPermissionByEMail(UID, EMail, AccessType); } #endif //DEBUG [Route("grantPermission"), HttpPost] public async Task grantPermission(Guid DataAreaId, Guid PersonId, int AccessType, Guid AccoundId) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new cLiamPermissionResult { Valid = false }; } var DA = await getDataAreaFromId(DataAreaId); if (DA == null) return null; var UPN = GetUserPrincipalName(PersonId, AccoundId); if (string.IsNullOrEmpty(UPN)) return null; var User = new cLiamUserInfo { EMail = UPN, UserPrincipalName = UPN }; return await DA.dataArea.GrantPermissionAsync(User, (eLiamAccessRoles)AccessType); } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("grantPermission"), HttpPost] public async Task grantPermission(Guid DataAreaId, Guid PersonId, int AccessType) { return await grantPermission(DataAreaId, PersonId, AccessType, Guid.Empty); } public class RevokePermissionResponse { public bool success { get; set; } public string error { get; set; } // null wenn success=true } [Route("revokePermission"), HttpPost] public async Task revokePermission(Guid DataAreaId, Guid PersonId, int AccessType, Guid AccoundId) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new RevokePermissionResponse { success = false, error = "License not valid" }; } var DA = await getDataAreaFromId(DataAreaId); if (DA == null) return new RevokePermissionResponse { success = false, error = "DataArea not found" }; var UPN = GetUserPrincipalName(PersonId, AccoundId); if (string.IsNullOrEmpty(UPN)) return new RevokePermissionResponse { success = false, error = "UPN not found" }; // Optional: Enum-Validierung, verhindert interne Fehler if (!Enum.IsDefined(typeof(eLiamAccessRoles), AccessType)) return new RevokePermissionResponse { success = false, error = "Invalid AccessType" }; var user = new cLiamUserInfo { EMail = UPN, UserPrincipalName = UPN }; var ok = await DA.dataArea.RevokePermissionAsync(user, (eLiamAccessRoles)AccessType); return new RevokePermissionResponse { success = ok, error = ok ? null : "RevokePermissionAsync failed" }; } catch (Exception ex) { LogException(ex); return new RevokePermissionResponse { success = false, error = ex.Message }; } finally { LogMethodEnd(CM); } } [Route("revokePermission"), HttpPost] public async Task revokePermission(Guid DataAreaId, Guid PersonId, int AccessType) { return await revokePermission(DataAreaId, PersonId, AccessType, Guid.Empty); } [Route("grantPermissionByEMail"), HttpPost] public async Task grantPermissionByEMail(string UID, string EMail, int AccessType) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return new cLiamPermissionResult { Valid = false }; } var DA = await getDataAreaFromUID(UID); if (DA == null) return null; var User = new cLiamUserInfo { EMail = EMail }; return await DA.GrantPermissionAsync(User, (eLiamAccessRoles)AccessType); } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("revokePermissionByEMail"), HttpPost] public async Task revokePermissionByEMail(string UID, string EMail, int AccessType) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) { LogEntry("Error: License not valid", LogLevels.Error); return false; } var DA = await getDataAreaFromUID(UID); if (DA == null) return false; var User = new cLiamUserInfo { EMail = EMail }; return await DA.RevokePermissionAsync(User, (eLiamAccessRoles)AccessType); } catch (Exception E) { LogException(E); return false; } finally { LogMethodEnd(CM); } } [Route("encryptPassword"), HttpGet] public string encryptPassword(string Password) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { return CryptoManager.Instance.EncryptDBText(Password); } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("getLicenseInformation"), HttpGet] public cC4ITLicenseM42ESM getLicenseInformation() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) return null; return cC4ITLicenseM42ESM.Instance; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } [Route("getLicensedModules"), HttpGet] public List getLicensedModules() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!LoadLicensingInformation()) return new List(); var modules = cC4ITLicenseM42ESM.Instance?.Modules; if (modules == null || !cC4ITLicenseM42ESM.Instance.IsValid) return new List(); var rs = modules.Keys.Select(k => k.ToString()).ToList(); var ClassID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameDataAreaTargetPickupType); LogEntry($"Addon Config class ID: {ClassID}", LogLevels.Debug); var dataTable = FragmentRequest.SimpleLoad(ClassID, "Id, Value", AsqlHelper.BuildInCondition("ID", rs)); if (dataTable?.Rows == null || dataTable.Rows.Count == 0) { LogEntry($"Addon Config fragment not found: ClassID={ClassID}", LogLevels.Debug); return null; } var rs2 = new List(); foreach (DataRow p in dataTable.Rows) { var moduleId = cLIAMHelper.getGuidFromObject(p["Id"]); var module = cC4ITLicenseM42ESM.Instance.Modules[moduleId]; var obj = cLiamM42Helper.ToDynamic(module); obj.Value = cLIAMHelper.getStringFromObject(p["Value"]); rs2.Add(obj); } return rs2; } catch (Exception E) { LogException(E); return null; } finally { LogMethodEnd(CM); } } private string GetUserPrincipalName(Guid PersonId, Guid AccoundId) { Guid myAccountId = AccoundId != Guid.Empty ? AccoundId : GetPrimaryAccountId(PersonId); if (myAccountId == Guid.Empty) return null; var accountEoid = GetAccountEOID(myAccountId); if (accountEoid == Guid.Empty) return null; return GetUserPrincipalNameFromEOID(accountEoid); } private Guid GetPrimaryAccountId(Guid PersonId) { var ClassID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameUserBase); LogEntry($"Data area class ID: {ClassID}", LogLevels.Debug); var FragDataArea = FragmentRequest.GetSPSFragment(ClassID, PersonId); if (FragDataArea == null) { LogEntry($"Data area fragment not found: ClassID={ClassID}, FragmentId={PersonId}", LogLevels.Debug); return Guid.Empty; } var myAccountId = cLIAMHelper.getGuidFromObject(FragDataArea["PrimaryAccount"]); if (myAccountId == Guid.Empty) LogEntry("Account value not found.", LogLevels.Warning); else LogEntry($"Account class ID: {myAccountId}", LogLevels.Debug); return myAccountId; } private Guid GetAccountEOID(Guid myAccountId) { var ClassID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameAccountBase); LogEntry($"Data area class ID: {ClassID}", LogLevels.Debug); var FragDataArea = FragmentRequest.GetSPSFragment(ClassID, myAccountId); if (FragDataArea == null) { LogEntry($"Data area fragment not found: ClassID={ClassID}, FragmentId={myAccountId}", LogLevels.Debug); return Guid.Empty; } var accountEoid = cLIAMHelper.getGuidFromObject(FragDataArea["Expression-ObjectId"]); if (accountEoid == Guid.Empty) LogEntry("Account EOID value not found.", LogLevels.Warning); else LogEntry($"Account EOID: {accountEoid}", LogLevels.Debug); return accountEoid; } private string GetUserPrincipalNameFromEOID(Guid accountEoid) { var ClassID = SPSDataEngineSchemaReader.ClassGetIDFromName(constFragmentNameAccountAd); LogEntry($"Data area class ID: {ClassID}", LogLevels.Debug); var tbl = FragmentRequestBase.SimpleLoad(ClassID, "UserPrincipalName", $"[Expression-ObjectId]='{accountEoid}'"); if (tbl?.Rows == null || tbl.Rows.Count == 0) { LogEntry($"No AD account entry list found with eoid='{accountEoid}'", LogLevels.Warning); return null; } var UPN = cLIAMHelper.getStringFromObject(tbl.Rows[0]["UserPrincipalName"]); if (string.IsNullOrEmpty(UPN)) { LogEntry("No UserPrincipalName found for AccountAd entry", LogLevels.Warning); return null; } return UPN; } public class ProviderConfigurationExport { public Guid ProviderConfigClassID { get; set; } public Guid ProviderConfigObjectID { get; set; } public string SanitizedJson { get; set; } public cLiamProviderData Configuration { get; set; } public DateTime GeneratedAtUtc { get; set; } } } }