Prepare Data History Provider 2.7 integration update

- modularize Citrix and agent integrations and add remote desktop endpoints
- extend ticket overview, ticket links, token validation, and staged relation handling
- update configuration, licensing, project, signing, and publish artifacts
This commit is contained in:
Meik
2026-07-20 09:31:52 +02:00
parent a3357e2a36
commit ccc48c521a
62 changed files with 5267 additions and 2521 deletions

View File

@@ -2,7 +2,11 @@
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices.ActiveDirectory;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -13,28 +17,26 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.IdentityModel.Tokens.Jwt;
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using C4IT.Configuration;
using C4IT.DataHistoryProvider.Base.Modules.Citrix;
using C4IT.FASD.Base;
using C4IT.FASD.Licensing;
using C4IT.Logging;
using C4IT.Matrix42.WebClient;
using C4IT.Security;
using C4IT.XML;
using C4IT.Matrix42.WebClient;
using C4IT_DataHistoryProvider_Base;
using C4IT_DataHistoryProvider_Base.DataSources;
using C4IT_DataHistoryProvider_Base.Services;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static C4IT.FASD.Base.cF4sdQuickActionRevision;
using static C4IT.Logging.cLogManager;
@@ -105,7 +107,18 @@ namespace C4IT.DataHistoryProvider
public abstract Task<bool> DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false);
public abstract Task<List<object>> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep);
public virtual async Task<List<object>> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep)
{
await Task.CompletedTask;
if (IdEntry.sid == null)
return null;
return new List<object>() { IdEntry.Id };
}
public virtual bool UseForeignUserIds()
{
return false;
}
public virtual List<object> GetFilterValues(List<object> IDs, enumFasdInformationClass InfoClass)
{
@@ -222,6 +235,15 @@ namespace C4IT.DataHistoryProvider
await Task.CompletedTask;
return null;
}
public virtual async Task<int> ValidateTokenInfo(cDataHistoryCollectorTokenCache.cTokenInfo tokenInfo)
// 0: Token Info is correct
// -1: Token Info is incorrect
// 1: Token Info as to be updated due to newer infos
{
await Task.CompletedTask;
return 0;
}
}
public class cDataHistoryCollector : cDataHistoryCollectorModule, IConfigNodeValidation, ISearchResultRelationProvider
@@ -257,6 +279,7 @@ namespace C4IT.DataHistoryProvider
public cDataHistoryCollectorM42Wpm M42WpmCollector { get; private set; } = null;
public cDataHistoryCollectorNxql NxqlCollector { get; private set; } = null;
public cDataHistoryCollectorCitrix CitrixCollector { get; private set; } = null;
//public cDataHistoryCollectorEmpirum EmpirumCollector { get; private set; } = null;
public bool F4SDAnalyticsValid = false;
public cF4SDAnalyticsConfigDatabase F4SDAnalyticsDb { get; private set; } = null;
public event DataHistoryUiMessageFunc ProcessUiMessage;
@@ -279,6 +302,8 @@ namespace C4IT.DataHistoryProvider
private readonly List<ISearchResultRelationProvider> _searchResultRelationProviders = new List<ISearchResultRelationProvider>();
private Dictionary<cF4SDTokenRegistration.enumTokenType, cDataHistoryCollectorModule> _tokenValidators = new Dictionary<cF4SDTokenRegistration.enumTokenType, cDataHistoryCollectorModule>();
public bool RunningInIISExpress = false;
#region Services
@@ -288,7 +313,7 @@ namespace C4IT.DataHistoryProvider
public IStagedRelationService GetStagedRelationService()
{
if (_stagedRelationService is null)
_stagedRelationService = new StagedRelationService(_searchResultRelationProviders);
_stagedRelationService = new StagedRelationService(this, _searchResultRelationProviders);
return _stagedRelationService;
}
@@ -329,7 +354,7 @@ namespace C4IT.DataHistoryProvider
if (cF4SDLicense.Instance.Modules.ContainsKey(_ActiveDirectory.LicenseId))
{
ActiveDirectory = _ActiveDirectory;
Connectors.Add(enumDataHistoryOrigin.ActiveDirectory, ActiveDirectory);
Connectors.Add(enumDataHistoryOrigin.ActiveDirectory, ActiveDirectory);
}
var _F4sdAgent = new cDataHistoryCollectorClientAgent(this);
@@ -450,6 +475,7 @@ namespace C4IT.DataHistoryProvider
var HasIntuneConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true);
var HasMobileDeviceConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true);
var HasCitrixConfig = (InfrastructureConfig.Citrix != null);
var HasEmpirumConfig = true;
DoProcessUiMessage(1, "resolving the ad membership groups");
ActiveDirectory.ResolveWinAuthenticationGroups();
@@ -462,7 +488,7 @@ namespace C4IT.DataHistoryProvider
DoProcessUiMessage(0, "");
DoProcessUiMessage(1, "loading the data cluster definitions...");
var _cfgDataClusters = new cDataHistoryConfigClusters();
_cfgDataClusters.LoadFromFile(out PMs, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig,withMobileDeviceConfig:HasMobileDeviceConfig,withCitrixConfig:HasCitrixConfig);
_cfgDataClusters.LoadFromFile(out PMs, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig, withMobileDeviceConfig: HasMobileDeviceConfig, withCitrixConfig: HasCitrixConfig);
if (PMs != null && PMs.Count > 0)
DoProcessUiMessage(2, PMs);
@@ -509,24 +535,32 @@ namespace C4IT.DataHistoryProvider
{
var _CitrixCollector = new cDataHistoryCollectorCitrix(this);
if (cF4SDLicense.Instance?.Modules != null)
//if (cF4SDLicense.Instance.Modules.ContainsKey(_CitrixCollector.LicenseId))
//{
CitrixCollector = _CitrixCollector;
Connectors.Add(enumDataHistoryOrigin.Citrix, _CitrixCollector);
RegisterSearchRelationProvider(_CitrixCollector);
//}
if (cF4SDLicense.Instance.Modules.ContainsKey(_CitrixCollector.LicenseId))
{
CitrixCollector = _CitrixCollector;
Connectors.Add(enumDataHistoryOrigin.Citrix, _CitrixCollector);
RegisterSearchRelationProvider(_CitrixCollector);
}
}
if(HasIntuneConfig)
if (HasIntuneConfig)
{
Connectors.Add(enumDataHistoryOrigin.Intune, ActiveDirectory);
}
//if (HasIntuneConfig && HasMobileDeviceConfig)
//{
// RegisterSearchRelationProvider(ActiveDirectory);
//}
//if (HasEmpirumConfig)
//{
// var _EmpirumCollector = new cDataHistoryCollectorEmpirum(this);
// EmpirumCollector = _EmpirumCollector;
// Connectors.Add(enumDataHistoryOrigin.Empirum, EmpirumCollector);
//}
// do the post configuration tasks afer the infrastructure was loaded
DoProcessUiMessage(1, "processing post configuration tasks");
foreach (var Table in _cfgDataClusters.Tables.Values)
@@ -673,7 +707,7 @@ namespace C4IT.DataHistoryProvider
var HasMobileDeviceConfig = (InfrastructureConfig.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true);
var HasCitrixConfig = (InfrastructureConfig.Citrix != null);
var _cfg = cFasdBaseConfig.GetConfigByType(_item, null, _msg, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig, withMobileDeviceConfig: HasMobileDeviceConfig, withCitrixConfig:HasCitrixConfig);
var _cfg = cFasdBaseConfig.GetConfigByType(_item, null, _msg, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig, withMobileDeviceConfig: HasMobileDeviceConfig, withCitrixConfig: HasCitrixConfig);
if (_cfg.IsValid)
{
_Configs[_item] = _cfg;
@@ -1201,7 +1235,6 @@ namespace C4IT.DataHistoryProvider
return false;
}
private async Task<bool> UpdateF4SDAnalyticsViewsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
@@ -2490,7 +2523,7 @@ namespace C4IT.DataHistoryProvider
var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser;
Guid.TryParse(requestInfo.userInfo?.Id.ToString(), out Guid userGuid);
if (anonymous != null && (bool)anonymous)
Param.User = GetUserHashGuid(userGuid).ToString();
Param.User = GetUserHashGuid(userGuid).ToString();
else
Param.User = userGuid.ToString();
@@ -2666,17 +2699,27 @@ namespace C4IT.DataHistoryProvider
}
public async Task<cF4sdUserInfo> GetCurrentUserInfoAsync(CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
public async Task<cF4sdUserInfo> GetCurrentUserInfoAsync(CancellationToken Token, cF4sdWebRequestInfo requestInfo, int logDeep)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
var _startTime = DateTime.UtcNow;
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(logDeep, CM, requestInfo.id, requestInfo.created); }
var startTime = DateTime.UtcNow;
try
{
var _user = WindowsIdentity.GetCurrent();
var _res = await GetWinUserInfoAsync(_user, CultureInfo.CurrentCulture.DisplayName, true, Token, requestInfo, LogDeep + 1);
return _res;
if (!ActiveDirectory.WinAuthenticationGropsResolved)
{
ActiveDirectory.ResolveWinAuthenticationGroups();
if (!ActiveDirectory.WinAuthenticationGropsResolved)
{
LogEntry("Could not resolve authentication groups", LogLevels.Warning);
return null;
}
}
WindowsIdentity user = WindowsIdentity.GetCurrent();
return await GetWinUserInfoAsync(user, CultureInfo.CurrentCulture.DisplayName, true, Token, requestInfo, logDeep + 1);
}
catch (Exception E)
{
@@ -2684,7 +2727,7 @@ namespace C4IT.DataHistoryProvider
}
finally
{
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(logDeep, CM, requestInfo.id, requestInfo.created, startTime); }
if (CM != null) LogMethodEnd(CM);
}
@@ -2938,8 +2981,8 @@ namespace C4IT.DataHistoryProvider
}
if (strPhone != null)
{
Entry.Result.Name = strName + " (" + strPhone + ")";
Entry.Result.DisplayName = strName + " (" + strPhone + ")";
Entry.Result.Name = strName;
Entry.Result.DisplayName = $"{strName} ({strPhone})";
}
else
{
@@ -3853,7 +3896,7 @@ namespace C4IT.DataHistoryProvider
return null;
}
public async Task<List<cF4sdApiSearchResultRelation>> GetUsageFromOnlyAgentData(enumFasdInformationClass infoClass, List<Guid> Ids, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
public async Task<List<cF4sdApiSearchResultRelation>> GetUsageFromOnlyAgentData(IEnumerable<cF4sdConnectorIds> ids, enumFasdInformationClass infoClass, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
{
MethodBase CM = null;
if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
@@ -3862,20 +3905,15 @@ namespace C4IT.DataHistoryProvider
try
{
var _count = ids.Count();
var Age2 = Age;
if (Ids.Count == 1)
if (_count == 1)
Age2 = 365;
var AgentLimit = DateTime.UtcNow + TimeSpan.FromDays(-Age2);
var idInput = Ids.Select(v => new cF4sdIdentityEntry() { Id = v, Class = infoClass }).ToList();
var listIds = await getConnectorIdList(idInput, Token, requestInfo, LogDeep + 1);
var lstAgentIds = new Dictionary<int, cDataHistoryUsageIdInfo>(_count);
if (listIds == null || listIds.Count == 0)
return null;
var lstAgentIds = new Dictionary<int, cDataHistoryUsageIdInfo>(Ids.Count);
foreach (var Entry in listIds)
foreach (var Entry in ids)
{
if (Entry.lastSeenByAgent != null && Entry.lastSeenByAgent >= AgentLimit)
{
@@ -5237,7 +5275,7 @@ namespace C4IT.DataHistoryProvider
if (Connectors.TryGetValue(tableConfig.ParentCluster.Origin, out var C))
{
var IdValues = await C.GetIds(Identity, tableConfig.ParentCluster.InformationClass, requestInfo, LogDeep + 1);
if (IdValues != null && tableConfig.KeyColumns.Count == IdValues.Count)
if (IdValues != null && tableConfig.KeyColumns.Count == IdValues.Count)
{
var Filters = new Dictionary<string, object>();
for (int i = 0; i < IdValues.Count; i++)
@@ -5357,22 +5395,16 @@ namespace C4IT.DataHistoryProvider
return null;
}
private async Task<cF4sdConnectorIds> getConnectorIds(enumFasdInformationClass infoClass, cF4sdIdentityEntry Identity, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool WithLocalAccounts = false)
private async Task<cF4sdConnectorIds> getConnectorIdsFromDb(enumFasdInformationClass infoClass, cF4sdIdentityEntry Identity, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool WithLocalAccounts = false)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
var _startTime = DateTime.UtcNow;
int apiError = 0;
try
{
if (infoClass == enumFasdInformationClass.Ticket)
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.Ticket };
if (infoClass == enumFasdInformationClass.VirtualSession)
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.VirtualSession };
if (infoClass == enumFasdInformationClass.MobileDevice)
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.MobileDevice };
int apiError = 0;
if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"GetConnectorIdsFrom{infoClass}Id", out var Query))
return null;
@@ -5516,6 +5548,66 @@ namespace C4IT.DataHistoryProvider
return RetVal;
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
if (CM != null) LogMethodEnd(CM);
}
return null;
}
private async Task<cF4sdConnectorIds> getConnectorIds(enumFasdInformationClass infoClass, cF4sdIdentityEntry Identity, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool WithLocalAccounts = false)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
var _startTime = DateTime.UtcNow;
try
{
if (infoClass == enumFasdInformationClass.Ticket)
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.Ticket };
if (infoClass == enumFasdInformationClass.VirtualSession)
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.VirtualSession };
if (infoClass == enumFasdInformationClass.MobileDevice)
return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.MobileDevice };
var lstTasks = new List<Task>();
var _mainTask = getConnectorIdsFromDb(infoClass, Identity, Token, requestInfo, LogDeep + 1, WithLocalAccounts);
lstTasks.Add(_mainTask);
var _needForeignUserInfo = false;
if (infoClass == enumFasdInformationClass.User)
foreach (var module in this.Connectors.Values)
_needForeignUserInfo |= module.UseForeignUserIds();
Task<cForeignUserInfo> _userInfoTask = null;
if (_needForeignUserInfo)
{
_userInfoTask = GetForeignUserInfoAsync(Identity.Id, Token);
lstTasks.Add(_userInfoTask);
}
await Task.WhenAll(lstTasks);
var _result = _mainTask.Result;
if (_result == null)
return null;
if (_needForeignUserInfo)
_result.ForeignUserInfo = _userInfoTask?.Result;
return _result;
}
catch (Exception E)
{
@@ -6431,12 +6523,6 @@ namespace C4IT.DataHistoryProvider
return true;
}
public override async Task<List<object>> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep)
{
await Task.CompletedTask;
return new List<object>() { IdEntry.Id };
}
public static string getStingList(List<string> L)
{
if (L == null || L.Count == 0)
@@ -6495,7 +6581,7 @@ namespace C4IT.DataHistoryProvider
return null;
}
public cCollectorStatusInfo GetCollectorStatus(cF4sdWebRequestInfo requestInfo)
public cCollectorStatusInfo CheckCollectorStatus(cF4sdWebRequestInfo requestInfo)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
@@ -6598,11 +6684,100 @@ namespace C4IT.DataHistoryProvider
public HashSet<enumFasdInformationClass> GetSupportedInformationClasses() => new HashSet<enumFasdInformationClass>() { enumFasdInformationClass.User, enumFasdInformationClass.Computer };
public async Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdIdentityEntry> ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default)
public async Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdConnectorIds> ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default)
{
List<cF4sdApiSearchResultRelation> usageRelations = await GetUsageFromOnlyAgentData(informationClass, ids.Select(id => id.Id).ToList(), age, token, null, 1);
List<cF4sdApiSearchResultRelation> usageRelations = await GetUsageFromOnlyAgentData(ids, informationClass, age, token, null, 1);
return new cF4sdStagedSearchResultRelations() { Relations = usageRelations };
}
public void RegisterTokenValidator(cF4SDTokenRegistration.enumTokenType tokenType, cDataHistoryCollectorModule module)
{
_tokenValidators[tokenType] = module;
}
public async override Task<int> ValidateTokenInfo(cDataHistoryCollectorTokenCache.cTokenInfo tokenInfo)
{
if (_tokenValidators.TryGetValue(tokenInfo.type, out var module))
return await module.ValidateTokenInfo(tokenInfo);
return 0;
}
public class cForeignUserInfoEntry
{
public Guid MainID { get; set; }
public enumDataHistoryOrigin Origin { get; set; }
public string InstanceID { get; set; }
public string ForeignID { get; set; }
}
public class cForeignUserInfo : Dictionary<enumDataHistoryOrigin, List<cForeignUserInfoEntry>> { }
public async Task<cForeignUserInfo> GetForeignUserInfoAsync(Guid MainID, CancellationToken token)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetForeignUserInfo", out var QueryGetUser))
return null;
using (var Conn = new cDbConnection(Collector.mainDbConnection))
{
if (!Conn.IsOpen)
{
LogEntry($"Could not open main sql database '{Collector.mainDbConnection.Database}', aborting scan...'", LogLevels.Error);
return null;
}
var Params = new Dictionary<string, object>() { { "@ID", MainID } };
using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(Conn, QueryGetUser, Params, token))
{
if (Reader != null)
if (Reader.HasRows)
{
var _retVal = new cForeignUserInfo();
while (await Reader.ReadAsync(token))
{
try
{
var Entry = new cForeignUserInfoEntry();
Entry.MainID = Reader.GetGuid(0);
Entry.Origin = (enumDataHistoryOrigin)Reader.GetInt32(1);
Entry.InstanceID = Reader.GetString(2);
Entry.ForeignID = Reader.GetString(3);
if (!_retVal.TryGetValue(Entry.Origin, out var _lst))
{
_lst = new List<cForeignUserInfoEntry>();
_retVal.Add(Entry.Origin, _lst);
}
_lst.Add(Entry);
}
catch (Exception E)
{
cLogManager.DefaultLogger.LogException(E);
}
}
return _retVal;
}
}
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return null;
}
}
public class cScanTimeInfo
@@ -6736,7 +6911,13 @@ namespace C4IT.DataHistoryProvider
public Guid tenantId { get; set; }
public Guid intuneId { get; set; }
public Guid azureDeviceId { get; set; }
public cDataHistoryCollector.cForeignUserInfo ForeignUserInfo = null;
[Obsolete]
public string citrixTenantId { get; set; }
[Obsolete]
public int? citrixUserId { get; set; }
}

View File

@@ -1,7 +1,15 @@
using System;
using ActiveDs;
using C4IT.FASD.Base;
using C4IT.HTTP;
using C4IT.Logging;
using C4IT.MsGraph;
using C4IT_DataHistoryProvider_Base.DataSources;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices.Protocols;
using System.Globalization;
using System.Linq;
@@ -9,16 +17,8 @@ using System.Net;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using ActiveDs;
using C4IT.FASD.Base;
using C4IT.HTTP;
using C4IT.Logging;
using C4IT.MsGraph;
using C4IT_DataHistoryProvider_Base.DataSources;
using Newtonsoft.Json.Linq;
using static C4IT.Logging.cLogManager;
namespace C4IT.DataHistoryProvider
@@ -50,6 +50,7 @@ namespace C4IT.DataHistoryProvider
public const string constMsGraphDeviceBitlockerRecoveryKey = "informationProtection/bitlocker/recoveryKeys?$filter=deviceId eq '{0}'";
public const string constMsGraphDeviceBitlockerRecoveryKeyDetails = "informationProtection/bitlocker/recoveryKeys/{0}?$select=key";
public const string constMsGraphDeviceLAPS = "directory/deviceLocalCredentials/{0}?$select=credentials,deviceName";
public const string constMsGraphTAP = "users/{0}/authentication/temporaryAccessPassMethods";
public const int constMsGraphManagedDevicePaging = 100;
public const string constTableNameIntuneDeviceDetails = "intune-deviceInfo";
public const string constTableNameIntuneUserDeviceCount = "intune-userDeviceCount";
@@ -93,6 +94,7 @@ namespace C4IT.DataHistoryProvider
private DateTime LastDomainsUpdate = DateTime.MinValue;
private bool DomainsUpdateRunning = false;
private Dictionary<Guid, cMsGraphBase> tenantGraphCache = new Dictionary<Guid, cMsGraphBase>();
public bool WinAuthenticationGropsResolved { get; private set; }
static cDataHistoryCollectorActiveDirectory()
{
BaseDateTime = new DateTime(1601, 1, 1, 0, 0, 0, DateTimeKind.Utc);
@@ -2053,13 +2055,17 @@ namespace C4IT.DataHistoryProvider
return true;
}
public async Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdIdentityEntry> ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default)
public async Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdConnectorIds> ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default)
{
try
{
/*
List<cF4sdConnectorIds> Ids = await _collector.getConnectorIdList(ids.ToList(), token, null, 0);
List<cF4sdApiSearchResultRelation> relations = await GetUserMobileDevicesAsync(Ids, token, null);
return new cF4sdStagedSearchResultRelations() { Relations = relations };
*/
return null;
}
catch (Exception ex)
{
@@ -2082,14 +2088,16 @@ namespace C4IT.DataHistoryProvider
var bMobileDeviceExists = Tables.Exists(v => v.Name == constTableNameIntuneMobileDeviceDetails && v.ParentCluster?.Origin == enumDataHistoryOrigin.Intune);
if (!Identities.TryGetValue(enumFasdInformationClass.Computer, out var computer) && computer?.intuneId != Guid.Empty)
if (!Identities.TryGetValue(enumFasdInformationClass.User, out var user) && user?.intuneId != Guid.Empty && user?.tenantId != Guid.Empty)
bUserDeviceExists = false;
if (!Identities.TryGetValue(enumFasdInformationClass.Computer, out var computer) && computer?.intuneId != Guid.Empty && user?.tenantId != Guid.Empty)
bDeviceExists = false;
if(!Identities.TryGetValue(enumFasdInformationClass.MobileDevice, out var mobile) && mobile?.Id != Guid.Empty)
if (!Identities.TryGetValue(enumFasdInformationClass.MobileDevice, out var mobile) && mobile?.Id != Guid.Empty)
bMobileDeviceExists = false;
if(!Identities.TryGetValue(enumFasdInformationClass.User, out var user) && user?.intuneId != Guid.Empty)
bUserDeviceExists = false;
if (!(bDeviceExists || bMobileDeviceExists || bUserDeviceExists))
@@ -2111,8 +2119,8 @@ namespace C4IT.DataHistoryProvider
}
else
listTasks.Add(Task.Run<List<cF4SDHealthCardRawData.cHealthCardTable>>(async () => { return await GetIntuneDeviceTableAsync(computer.intuneId, computer.tenantId, requestInfo, LogDeep + 1, Token); }));
listTasks.Add(Task.Run<List<cF4SDHealthCardRawData.cHealthCardTable>>(async () => { return await GetIntuneDeviceTableAsync(computer.intuneId, user.tenantId, requestInfo, LogDeep + 1, Token); }));
if (bMobileDeviceExists)
if (CacheId == null && !instantly)
{
@@ -2237,20 +2245,22 @@ namespace C4IT.DataHistoryProvider
if (MsGraph == null)
return null;
var retVal = new cF4SDHealthCardRawData.cHealthCardTable()
{
Name = constTableNameIntuneDeviceDetails,
InformationClass = enumFasdInformationClass.Computer,
Origin = enumDataHistoryOrigin.Intune,
IsStatic = true,
TableType = eDataHistoryTableType.Static
};
var dicVals = new Dictionary<string, object>();
var res = await MsGraph.RequestAsync(strUrl, UseBeta: true, retryForbidden: false);
if (res != null)
{
JObject deviceInfos = res.Result;
var retVal = new cF4SDHealthCardRawData.cHealthCardTable()
{
Name = constTableNameIntuneDeviceDetails,
InformationClass = enumFasdInformationClass.Computer,
Origin = enumDataHistoryOrigin.Intune,
IsStatic = true,
TableType = eDataHistoryTableType.Static
};
var dicVals = new Dictionary<string, object>();
var vals = deviceInfos.Children();
if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetIntuneMainTableAsync #3");
@@ -2290,6 +2300,16 @@ namespace C4IT.DataHistoryProvider
else
{
LogEntry($"Could not get detailed device information from intune with id {IntuneId}. Device content is empty.", LogLevels.Warning);
foreach (var colInfo in IntuneTableDetails.Columns.Values)
{
try
{
var _col = new cF4SDHealthCardRawData.cHealthCardTableColumn(retVal) { ColumnName = colInfo.Name, Values = new List<object>(1) { } };
retVal.Columns[colInfo.Name] = _col;
}
catch { }
}
return new List<cF4SDHealthCardRawData.cHealthCardTable>(1) { retVal };
}
}
catch (Exception E)
@@ -2326,17 +2346,19 @@ namespace C4IT.DataHistoryProvider
if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetIntuneUserDeviceCountTableAsync #3");
var res = await MsGraph.RequestAsync(strUrl, UseBeta: false, retryForbidden: false);
if (cLogManager.DefaultLogger.IsDebug) LogEntry("SpecialDebug GetIntuneUserDeviceCountTableAsync #4");
var retVal = new cF4SDHealthCardRawData.cHealthCardTable()
{
Name = constTableNameIntuneUserDeviceCount,
InformationClass = enumFasdInformationClass.User,
Origin = enumDataHistoryOrigin.Intune,
IsStatic = true,
TableType = eDataHistoryTableType.Static
};
if (res != null)
{
JObject deviceInfos = res.Result;
var retVal = new cF4SDHealthCardRawData.cHealthCardTable()
{
Name = constTableNameIntuneUserDeviceCount,
InformationClass = enumFasdInformationClass.User,
Origin = enumDataHistoryOrigin.Intune,
IsStatic = true,
TableType = eDataHistoryTableType.Static
};
var vals = deviceInfos.Children();
@@ -2405,6 +2427,16 @@ namespace C4IT.DataHistoryProvider
else
{
LogEntry($"Could not get detailed DeviceCount information from intune with id {Userid}. DeviceCount content is empty.", LogLevels.Warning);
foreach (var colInfo in IntuneTableDetails.Columns.Values)
{
try
{
var _col = new cF4SDHealthCardRawData.cHealthCardTableColumn(retVal) { ColumnName = colInfo.Name, Values = new List<object>(1) { } };
retVal.Columns[colInfo.Name] = _col;
}
catch { }
}
return new List<cF4SDHealthCardRawData.cHealthCardTable>(1) { retVal };
}
}
catch (Exception E)
@@ -2437,26 +2469,25 @@ namespace C4IT.DataHistoryProvider
var MsGraph = await GetGraphForTenantAsync(TenantId, true);
if (MsGraph == null)
return null;
var retValList = new List<cF4SDHealthCardRawData.cHealthCardDetailsTable>();
var res = await MsGraph.RequestAsync(strUrl, UseBeta: false, retryForbidden: false);
var retVal = new cF4SDHealthCardRawData.cHealthCardDetailsTable()
{
Name = constTableNameIntuneUserDeviceCountDetail,
Columns = IntuneTableDetails.Columns.Values.Select(v => v.Name).ToList(),
Values = new Dictionary<int, List<object[]>>()
};
if (res != null)
{
JObject deviceInfos = res.Result;
var retValList = new List<cF4SDHealthCardRawData.cHealthCardDetailsTable>();
var vals = deviceInfos["value"] as JArray;
if (vals != null)
{
var retVal = new cF4SDHealthCardRawData.cHealthCardDetailsTable()
{
Name = constTableNameIntuneUserDeviceCountDetail,
Columns = IntuneTableDetails.Columns.Values.Select(v => v.Name).ToList(),
Values = new Dictionary<int, List<object[]>>()
};
int index = 0;
@@ -2488,6 +2519,8 @@ namespace C4IT.DataHistoryProvider
else
{
LogEntry($"Could not get detailed DeviceCount information from intune with id {Userid}. DeviceCount content is empty.", LogLevels.Warning);
retValList.Add(retVal);
return retValList;
}
}
return null;
@@ -2512,25 +2545,25 @@ namespace C4IT.DataHistoryProvider
{
string userIds = string.Join(",", UserId.Where(u => !string.IsNullOrWhiteSpace(u?.intuneId.ToString())).Select(u => u.intuneId));
var tenantId = UserId?.FirstOrDefault(u => u?.tenantId != Guid.Empty)?.tenantId ?? Guid.Empty;
var tenantId = UserId?.FirstOrDefault(u => u?.tenantId != Guid.Empty)?.tenantId ?? Guid.Empty;
var strUrl = string.Format(constMsGraphManagedMobileDeviceList, userIds);
var MsGraph = await GetGraphForTenantAsync(tenantId, true);
if (MsGraph == null)
return null;
var Result = await MsGraph.RequestListAsync(strUrl, UseBeta: false, retryForbidden: false);
if (Result != null == Result.Count > 0)
{
var searchResult = new List<cF4sdApiSearchResultRelation>(Result.Count);
foreach (var Entry in Result)
{
var endDate = DateTime.MinValue;
if (!DateTime.TryParse(Entry.Result.lastSyncDateTime?.ToString(), out endDate))
endDate = DateTime.UtcNow;
var searchInfo = new cF4sdApiSearchResultRelation()
{
Type = enumF4sdSearchResultClass.MobileDevice,
@@ -2677,6 +2710,9 @@ namespace C4IT.DataHistoryProvider
case "GetLAPS":
result = await GetLAPS(jsonRequest.Identities, requestInfo, CancellationToken.None);
break;
case "GetTAP":
result = await GetTAP(jsonRequest.Identities, requestInfo, CancellationToken.None);
break;
case "GetBitlockerKeyTest":
result = await GetBitlockerKeyTest(jsonRequest.Identities, requestInfo, CancellationToken.None);
break;
@@ -2688,7 +2724,7 @@ namespace C4IT.DataHistoryProvider
}
public override async Task<List<string>> GetQuickActionList()
{
var HasIntuneConfig = (Collector.InfrastructureConfig.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true);
if (HasIntuneConfig)
@@ -2699,8 +2735,9 @@ namespace C4IT.DataHistoryProvider
"Get Managed Apps",
"Get BitlockerKey",
"Get LAPS",
"Get TAP",
"GetLapsKeyTest",
};
};
return await Task.FromResult(quickactions);
}
var result = new List<string>();
@@ -2827,6 +2864,40 @@ namespace C4IT.DataHistoryProvider
return null;
}
public async Task<dynamic> GetTAP(List<cF4sdIdentityEntry> identities, cF4sdWebRequestInfo requestInfo, CancellationToken Token)
{
var Ids = await Collector.getConntectorIds(identities, Token, requestInfo, 1);
if (!Ids.TryGetValue(enumFasdInformationClass.User, out var _ids))
return null;
var strUrl = string.Format(constMsGraphTAP, _ids.intuneId);
var MsGraph = await GetGraphForTenantAsync(_ids.tenantId, true);
if (MsGraph == null)
return null;
var IntuneConfig = Collector?.GetGlobalConfig()?.IntuneConfiguration;
var body = new Dictionary<string, object>()
{
{ "isUsableOnce", IntuneConfig?.TAPIsUsableOnce ?? cF4sdIntuneConfig.DefaultTAPIsUsableOnce},
{ "lifetimeInMinutes", IntuneConfig?.TAPLifeTimeInMinutes ?? cF4sdIntuneConfig.DefaultTAPLifeTimeInMinutes}
};
var Result = await MsGraph.RequestAsync(strUrl, UseBeta: false, eHttpMethod.post, JsonData: body, retryForbidden: false);
if (Result != null)
{
var _resultJson = Result.Result as JObject;
if (_resultJson != null)
{
return _resultJson;
}
}
return null;
}
public async Task<dynamic> GetManagedApps(List<cF4sdIdentityEntry> identities, cF4sdWebRequestInfo requestInfo, CancellationToken Token)
{
var Ids = await Collector.getConntectorIds(identities, Token, requestInfo, 1);
@@ -3131,6 +3202,9 @@ namespace C4IT.DataHistoryProvider
if (Collector.InfrastructureConfig.AzureTenants != null)
await DoAzureScanAsync(requestInfo, LogDeep + 1, Token);
if (Collector.InfrastructureConfig.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true)
await DoScanIntuneAsync(requestInfo, LogDeep + 1, Token);
await Collector.SetLastScanTime("AdScan-all", DateTime.UtcNow, requestInfo, LogDeep + 1, Token);
return true;
@@ -3443,7 +3517,7 @@ namespace C4IT.DataHistoryProvider
if (Table?.ParentCluster?.Origin == enumDataHistoryOrigin.Intune)
return true;
return false;
}
}
private object ConvertToF4sdType(object objVal, enumFasdValueType ValueType)
{
@@ -3691,68 +3765,26 @@ namespace C4IT.DataHistoryProvider
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
if (Collector?.InfrastructureConfig?.Authorisation?.MembershipGroups?.GroupsAd == null)
if (Collector?.InfrastructureConfig?.Authorisation?.MembershipGroups?.GroupsAd is null)
return;
LogEntry("Resolving AD groups SIDs...");
var _lstDomains = Collector.InfrastructureConfig.Authorisation.MembershipGroups.GroupsAd;
var domains = Collector.InfrastructureConfig.Authorisation.MembershipGroups.GroupsAd.Values;
LogEntry("Resolving AD groups SIDs finished");
foreach (var _domain in _lstDomains.Values)
bool hasResolved = true;
foreach (cF4SDMembershipGroupsAd domain in domains)
{
try
{
LogEntry($"Start processing domain");
LogEntry($"Processing domain {_domain?.Domain?.FQDN}");
PrincipalContext PC;
if (_domain.Domain.Credential == null)
PC = new PrincipalContext(ContextType.Domain, _domain.Domain.FQDN);
else
PC = new PrincipalContext(ContextType.Domain, _domain.Domain.FQDN, _domain.Domain.Credential.User, _domain.Domain.Credential.NwCredential.Password);
LogEntry($"Principal context successful created");
foreach (var _group in _domain.Values)
{
try
{
LogEntry($"Start processing group.");
LogEntry($"Group: {_group.Name}.");
var GI = GroupPrincipal.FindByIdentity(PC, IdentityType.SamAccountName, _group.Account);
LogEntry($"Group principal found");
LogEntry($"GI.SID: {GI.Sid.ToString()}");
if (GI != null)
if (GI.Sid != null)
{
_group.SID = GI.Sid.ToString();
LogEntry($"AD group '{_group.Account}' in domain '{_domain.Domain.FQDN}' resolved. SID = {_group.SID}");
}
if (_group.SID == null)
LogEntry($"Could not resolve AD group '{_group.Account}' in domain '{_domain.Domain.FQDN}'", LogLevels.Warning);
}
catch (Exception E)
{
LogException(E);
}
finally
{
LogEntry($"End processing group.");
}
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
LogEntry($"End processing domain");
}
hasResolved = hasResolved && TryProcessDomain(domain);
}
WinAuthenticationGropsResolved = hasResolved;
}
catch (Exception E)
catch (Exception ex)
{
LogException(E);
LogException(ex);
WinAuthenticationGropsResolved = false;
}
finally
{
@@ -3760,6 +3792,80 @@ namespace C4IT.DataHistoryProvider
}
}
private bool TryProcessDomain(cF4SDMembershipGroupsAd domain)
{
try
{
bool hasProcessed = true;
if (domain?.Domain is null)
return hasProcessed;
LogEntry($"Start processing domain");
string domainName = domain.Domain.FQDN;
LogEntry($"Processing domain {domainName}");
PrincipalContext principalContext;
if (domain.Domain.Credential == null)
principalContext = new PrincipalContext(ContextType.Domain, domainName);
else
principalContext = new PrincipalContext(ContextType.Domain, domainName, domain.Domain.Credential.User, domain.Domain.Credential.NwCredential.Password);
LogEntry($"Principal context successful created");
foreach (var group in domain.Values)
{
hasProcessed = hasProcessed && TryProcessMembershipGroup(group, principalContext, domainName);
}
return hasProcessed;
}
catch (Exception ex)
{
LogException(ex);
return false;
}
finally
{
LogEntry($"End processing domain");
}
}
private bool TryProcessMembershipGroup(cF4SDMembershipGroupAd group, PrincipalContext principalContext, string domainName)
{
try
{
if (group is null)
return true;
LogEntry($"Start processing group.");
LogEntry($"Group: {group.Name}.");
var groupIdentity = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, group.Account);
LogEntry($"Group principal found");
LogEntry($"GI.SID: {groupIdentity.Sid}");
if (groupIdentity?.Sid != null)
{
group.SID = groupIdentity.Sid.ToString();
LogEntry($"AD group '{group.Account}' in domain '{domainName}' resolved. SID = {group.SID}");
}
if (group.SID == null)
LogEntry($"Could not resolve AD group '{group.Account}' in domain '{domainName}'", LogLevels.Warning);
return true;
}
catch (Exception ex)
{
LogException(ex);
return false;
}
finally
{
LogEntry($"End processing group.");
}
}
static public Guid ConvertAzureSidToGuid(string sid)
{
if (!sid.StartsWith("S-1-12-1-"))

View File

@@ -592,7 +592,6 @@ namespace C4IT.DataHistoryProvider
// check if wwe have a local account and process the localAccountAssignments
if (string.IsNullOrEmpty(domain) && localAccountAssignments != null)
{
var AdId = Guid.Empty;
foreach (var localAccountAssignment in localAccountAssignments)
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,16 @@
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT.Security;
using System;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT.Security;
using Newtonsoft.Json.Linq;
using static C4IT.DataHistoryProvider.cDataHistoryCollectorTokenCache;
using static C4IT.Logging.cLogManager;
namespace C4IT.DataHistoryProvider
@@ -29,6 +34,7 @@ namespace C4IT.DataHistoryProvider
public string secret;
public DateTime validUntil;
public DateTime renewUntil;
public string IdRemote;
public bool IsValid()
{
@@ -36,6 +42,7 @@ namespace C4IT.DataHistoryProvider
return false;
if (validUntil < DateTime.UtcNow + TimeSpan.FromMinutes(cDataHistoryCollector.constMinutesUntilTokenIsInvalid))
return false;
return true;
}
@@ -52,7 +59,8 @@ namespace C4IT.DataHistoryProvider
name2 = name2,
secret = _sec,
validUntil = validUntil,
renewUntil = renewUntil
renewUntil = renewUntil,
IdRemote = IdRemote
};
return _ret;
@@ -132,6 +140,9 @@ namespace C4IT.DataHistoryProvider
{
dicToken.Clear();
var _toDelete = new List<cTokenInfo>();
var _toUpdate = new List<cTokenInfo>();
using (var _reader = await DataHistorySqlHelper.GetDataReaderAsync(DbConn, Query, null, Token))
{
if (_reader != null)
@@ -139,7 +150,6 @@ namespace C4IT.DataHistoryProvider
{
if (_reader.HasRows)
{
var _toDelete = new List<cTokenInfo>();
while (await _reader.ReadAsync())
{
try
@@ -156,13 +166,22 @@ namespace C4IT.DataHistoryProvider
_entry.secret = cSecurePassword.Instance.Decode(_secret);
_entry.validUntil = _reader.IsDBNull(5) ? DateTime.MinValue : _reader.GetDateTime(5);
_entry.renewUntil = _reader.IsDBNull(6) ? DateTime.MinValue : _reader.GetDateTime(6);
_entry.IdRemote = _reader.IsDBNull(7) ? null : _reader.GetString(7);
int valid = -1;
if (_entry.IsValid())
valid = await Collector.ValidateTokenInfo(_entry);
if (valid < 0)
_toDelete.Add(_entry);
else
{
if (!privInsert(_entry, false))
_toDelete.Add(_entry);
if (valid > 0)
_toUpdate.Add(_entry);
}
else
_toDelete.Add(_entry);
}
catch (Exception E)
{
@@ -178,9 +197,18 @@ namespace C4IT.DataHistoryProvider
{
cLogManager.DefaultLogger.LogException(E);
}
}
if (_toUpdate.Count > 0)
{
foreach (var entry in _toUpdate)
{
var _secEnc = entry.secret;
if (!HasTokenTypeLongLifetime(entry.type))
_secEnc = cSecurePassword.Instance.Encode(entry.secret);
await SaveToDbAsync(entry, _secEnc, requestInfo, LogDeep + 1, Token);
}
}
}
catch (Exception E)
{
@@ -204,6 +232,54 @@ namespace C4IT.DataHistoryProvider
}
}
private async Task SaveToDbAsync(cTokenInfo _tokenInfo, string secEnc, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
var sqlerror = 0;
var sqlStartTime = DateTime.UtcNow;
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("InsertOrUpdateExternalToken", out var Query))
return;
try
{
var Params = new Dictionary<string, object>()
{
{ "Id", _tokenInfo.id },
{ "Type", (int)_tokenInfo.type },
{ "Name", _tokenInfo.name },
{ "Name2", _tokenInfo.name2 },
{ "Secret", secEnc },
{ "ValidUntil", _tokenInfo.validUntil },
{ "RenewUntil", _tokenInfo.renewUntil },
{ "IdRemote", _tokenInfo.IdRemote },
};
using (var Conn = new cDbConnection(Collector.mainDbConnection))
{
if (!Conn.IsOpen)
{
LogEntry($"Could not open main database '{Collector.mainDbConnection.Database}', aborting query'", LogLevels.Error);
return;
}
await DataHistorySqlHelper.ExecuteAsync(Conn, Query, Params, requestInfo, Token);
}
}
catch (Exception E)
{
sqlerror = E.HResult;
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
public async Task SetAsync(cF4SDTokenRegistration _tokenRegistration, cF4SDTokenValidityPeriod validityPeriod, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
@@ -229,50 +305,23 @@ namespace C4IT.DataHistoryProvider
renewUntil = validityPeriod.renewUntil
};
if (!DataHistorySqlHelper.GetWellKnownSqlStatement("InsertOrUpdateExternalToken", out var Query))
return;
var Params = new Dictionary<string, object>()
{
{ "Id", _tokenInfo.id },
{ "Type", (int)_tokenInfo.type },
{ "Name", _tokenInfo.name },
{ "Name2", _tokenInfo.name2 },
{ "Secret", _secEnc },
{ "ValidUntil", _tokenInfo.validUntil },
{ "RenewUntil", _tokenInfo.renewUntil },
};
var sqlerror = 0;
var sqlStartTime = DateTime.UtcNow;
await TokenCacheCriticalSection.EnterAsync();
try
{
await SaveToDbAsync(_tokenInfo, _secEnc, requestInfo, LogDeep + 1, Token);
privInsert(_tokenInfo, true);
using (var Conn = new cDbConnection(Collector.mainDbConnection))
{
if (!Conn.IsOpen)
{
LogEntry($"Could not open main database '{Collector.mainDbConnection.Database}', aborting query'", LogLevels.Error);
return;
}
await DataHistorySqlHelper.ExecuteAsync(Conn, Query, Params, requestInfo, Token);
}
}
catch (Exception E)
{
sqlerror = E.HResult;
LogException(E);
}
finally
{
TokenCacheCriticalSection.Leave();
}
}
catch (Exception E)
{

View File

@@ -1,188 +0,0 @@
using C4IT.DataHistoryProvider;
using C4IT.Logging;
using C4IT.Security;
using C4IT.XML;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using static C4IT.Logging.cLogManager;
namespace C4IT_DataHistoryProvider
{
public class cDataHistoryConfigCitrix : IConfigNodeValidation
{
public bool IsValid { get; private set; } = false;
public string Domain { get; private set; } = "";
public string TenantID { get; private set; } = String.Empty;
public cCredential Credential { get; private set; } = null;
public cDataHistoryScanTiming ScanTiming { get; private set; } = null;
public cDataHistoryConfigCitrix(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var XNode2 = XNode.SelectSingleNode("Citrix");
if (!(XNode2 is XmlElement XCitrix))
{
return;
}
Parser.EnterElement("Citrix");
try
{
ScanTiming = new cDataHistoryScanTiming(XCitrix, TimeSpan.FromHours(24), TimeSpan.FromMinutes(10), Parser);
IsValid = true;
}
finally
{
Parser.LeaveElement("Citrix");
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
public class cDataHistoryCitrixTenant : IConfigNodeValidation
{
public bool IsValid { get; private set; } = false;
public string Domain { get; private set; } = "";
public string TenantID { get; private set; } = String.Empty;
public string InstanceID { get; private set; } = String.Empty;
public cCredential Credential { get; private set; } = null;
internal cDataHistoryCitrixTenant(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
Domain = cXmlParser.GetStringFromXmlAttribute(XNode, "Domain");
if (string.IsNullOrWhiteSpace(Domain))
{
Parser.AddInvalidAttribute(XNode, null, "Domain");
return;
}
TenantID = cXmlParser.GetStringFromXmlAttribute(XNode, "TenantID");
if (TenantID == String.Empty)
{
Parser.AddInvalidAttribute(XNode, Domain, "TenantID");
return;
}
InstanceID = cXmlParser.GetStringFromXmlAttribute(XNode, "InstanceID");
if (InstanceID == String.Empty)
{
Parser.AddInvalidAttribute(XNode, Domain, "InstanceID");
return;
}
var strCreds = cXmlParser.GetStringFromXmlAttribute(XNode, "Credential");
if (!string.IsNullOrWhiteSpace(strCreds))
{
if (Credentials.TryGetValue(strCreds, out var Cred))
Credential = Cred;
}
if (Credential == null)
{
Parser.AddInvalidAttribute(XNode, Domain, "Credential");
return;
}
IsValid = true;
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
internal static Dictionary<string, cDataHistoryCitrixTenant> LoadFromXml(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
var RetVal = new Dictionary<string, cDataHistoryCitrixTenant>();
try
{
var XRoot = XNode.SelectSingleNode("Citrix");
if (XRoot == null)
{
return null;
}
Parser.EnterElement("Citrix");
try
{
var XList = XRoot.SelectNodes("Citrix-Tenant");
if (XList != null && XList.Count > 0)
{
Parser.EnterElement("Citrix-Tenant");
try
{
foreach (var Entry in XList)
{
if (!(Entry is XmlElement XEntry))
continue;
var Node = new cDataHistoryCitrixTenant(XEntry, Credentials, Parser);
if (Node.IsValid)
{
if (RetVal.ContainsKey(Node.Domain))
{
Parser.AddDuplicateName(XEntry, Node.Domain, LogLevels.Warning);
}
else
RetVal.Add(Node.Domain, Node);
}
Parser.SelectElementNext();
}
}
finally
{
Parser.LeaveElement("Citrix-Tenant");
}
}
}
finally
{
Parser.LeaveElement("Citrix");
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return RetVal;
}
}
}
}

View File

@@ -128,6 +128,8 @@ namespace C4IT.DataHistoryProvider
RetVal |= DoXmlInsertTableRow(XmlRoot, "AD-ComputerInfo", "ad-computer", "<Table-Column Name=\"domainDns\" SourceType =\"Static\" Type=\"string\" Cardinal=\"128\"/>", "account");
RetVal |= DoXmlInsertTableRow(XmlRoot, "AD-ComputerInfo", "ad-computer", "<Table-Column Name=\"domainNB\" SourceType =\"Static\" Type=\"string\" Cardinal=\"16\"/>", "account");
RetVal |= DoXmlInsertTableRow(XmlRoot, "Agent-DeviceInfo", "agnt-computer", "<Table-Column Name=\"IsPhoenixInstalled\" SourceName=\"Phoenix Installed\" Type=\"boolean\" Aggregation=\"latestValue\"/>");
RetVal |= DoXmlInsertTableRow(XmlRoot, "Agent-DeviceInfo", "agnt-computer-event-numerical", "<Table-Column Name=\"DeviceActivity\" SourceName=\"Device Activity\" Type=\"bigint\" Aggregation=\"sum\"/>");
RetVal |= DoXmlInsertTableRow(XmlRoot, "Agent-DeviceInfo", "agnt-computer-event-numerical", "<Table-Column Name=\"UserActivity\" SourceName=\"User Activity\" Type=\"bigint\" Aggregation=\"sum\"/>");
RetVal |= DoXmlInsertTableRow(XmlRoot, "Agent-DeviceInfo", "agnt-computer-event-numerical", "<Table-Column Name=\"ProcessorTaskManager\" SourceName=\"Task Manager % Score\" Type=\"float\" Aggregation=\"average\" LateDelivery=\"true\" />");
@@ -248,6 +250,11 @@ namespace C4IT.DataHistoryProvider
, "<Table Name=\"citrix-session-metrics\" Type=\"History\" Key=\"Id\"><Table-Columns><Table-Column Name=\"Id\" Type=\"int\"/><Table-Column Name=\"CollectedDate\" Type=\"datetime\"/><Table-Column Name=\"IcaRttMS\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"IcaLatency\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"ClientL7Latency\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"ServerL7Latency\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"ConnectionState\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"InputBandwidthUsed\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"OutputBandwidthUsed\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"OutputBandwidthAvailable\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"Fps\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"InputFps\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"OutputFps\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"WanLatency\" Type=\"int\" Aggregation=\"average\"/><Table-Column Name=\"DcLatency\" Type=\"int\" Aggregation=\"average\"/></Table-Columns></Table>"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='citrixMetrics']"
, "Table[@Name='citrix-connectionState-metrics']"
, "<Table Name=\"citrix-connectionState-metrics\" Type=\"History\" Key=\"Id\"><Table-Columns><Table-Column Name=\"Id\" Type=\"int\" /><Table-Column Name=\"StartDate\" Type=\"datetime\" /><Table-Column Name=\"ConnectionState\" Type=\"int\" /><Table-Column Name=\"ConnectionCount\" Type=\"int\" /></Table-Columns></Table>");
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='citrixMetrics']"
, "Table[@Name='citrix-session-details-icaRttMS']"
@@ -277,6 +284,10 @@ namespace C4IT.DataHistoryProvider
, "Table[@Name='citrix-session-details-inputBandwidthUsed']"
, "<Table Name=\"citrix-session-details-inputBandwidthUsed\" Type=\"Events\" Key=\"Id\" EventTimeCol=\"time\"><Table-Columns><Table-Column Name=\"Id\" Type=\"int\"/><Table-Column Name=\"Value\" SourceName=\"InputBandwidthUsed\" Type=\"int\"/><Table-Column Name=\"time\" SourceName=\"CollectedDate\" Type=\"datetime\"/></Table-Columns></Table>"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='citrixMetrics']"
, "Table[@Name='citrix-session-details-outputBandwidthUsed']"
, "<Table Name=\"citrix-session-details-outputBandwidthUsed\" Type=\"Events\" Key=\"Id\" EventTimeCol=\"time\"><Table-Columns><Table-Column Name=\"Id\" Type=\"int\" /><Table-Column Name=\"Value\" SourceName=\"OutputBandwidthUsed\" Type=\"int\" /><Table-Column Name=\"time\" SourceName=\"CollectedDate\" Type=\"datetime\" /></Table-Columns></Table>");
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='citrixMetrics']"
@@ -317,8 +328,7 @@ namespace C4IT.DataHistoryProvider
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='citrixMetrics']"
, "Table[@Name='citrix-session-machine']"
, "<Table Name=\"citrix-session-machine\" Type=\"Static\" Key=\"Id\"><Table-Columns><Table-Column Name=\"Id\" Type=\"guid\"/><Table-Column Name=\"Name\" Type=\"string\"/><Table-Column Name=\"CatalogName\" SourceName=\"Catalog\" SourceJsonField=\"Name\" Type=\"string\" Default=\"0\"/><Table-Column Name=\"AllocationType\" SourceName=\"Catalog\" SourceJsonField=\"AllocationType\" Type=\"int\" Default=\"0\"/><Table-Column Name=\"DesktopGroupName\" SourceName=\"DesktopGroup\" SourceJsonField=\"Name\" Type=\"string\"/><Table-Column Name=\"DnsName\" Type=\"string\"/><Table-Column Name=\"HostedMachine\" SourceName=\"HostedMachineId\" Type=\"string\"/><Table-Column Name=\"IPAddress\" Type=\"string\"/><Table-Column Name=\"WindowsConnectionSetting\" Type=\"int\" Default=\"0\"/><Table-Column Name=\"CurrentRegistrationState\" Type=\"int\" Default=\"0\"/><Table-Column Name=\"AgentVersion\" Type=\"string\"/><Table-Column Name=\"CurrentSessionCount\" Type=\"int\"/><Table-Column Name=\"OSType\" Type=\"string\"/><Table-Column Name=\"IsInMaintenanceMode\" Type=\"boolean\"/><Table-Column Name=\"Cpu\" SourceName=\"CurrentLoadIndex\" SourceJsonField=\"Cpu\" Type=\"int\" Default=\"0\"/><Table-Column Name=\"Memory\" SourceName=\"CurrentLoadIndex\" SourceJsonField=\"Memory\" Type=\"int\" Default=\"0\"/><Table-Column Name=\"Disk\" SourceName=\"CurrentLoadIndex\" SourceJsonField=\"Disk\" Type=\"int\" Default=\"0\"/></Table-Columns></Table>"
);
, "<Table Name=\"citrix-session-machine\" Type=\"Static\" Key=\"Id\"><Table-Columns><Table-Column Name=\"Id\" Type=\"guid\" /><Table-Column Name=\"Name\" Type=\"string\" /><Table-Column Name=\"CatalogName\" SourceName=\"Catalog\" SourceJsonField=\"Name\" Type=\"string\" Default=\"0\" /><Table-Column Name=\"AllocationType\" SourceName=\"Catalog\" SourceJsonField=\"AllocationType\" Type=\"int\" Default=\"0\" /><Table-Column Name=\"DesktopGroupName\" SourceName=\"DesktopGroup\" SourceJsonField=\"Name\" Type=\"string\" /><Table-Column Name=\"DnsName\" Type=\"string\" /><Table-Column Name=\"HostedMachine\" SourceName=\"HostedMachineId\" Type=\"string\" /><Table-Column Name=\"IPAddress\" Type=\"string\" /><Table-Column Name=\"WindowsConnectionSetting\" Type=\"int\" Default=\"0\" /><Table-Column Name=\"CurrentRegistrationState\" Type=\"int\" Default=\"0\" /><Table-Column Name=\"AgentVersion\" Type=\"string\" /><Table-Column Name=\"CurrentSessionCount\" Type=\"int\" /><Table-Column Name=\"OSType\" Type=\"string\" /><Table-Column Name=\"IsInMaintenanceMode\" Type=\"boolean\" /><Table-Column Name=\"Cpu\" SourceName=\"CurrentLoadIndex\" SourceJsonField=\"Cpu\" Type=\"int\" Default=\"0\" /><Table-Column Name=\"Memory\" SourceName=\"CurrentLoadIndex\" SourceJsonField=\"Memory\" Type=\"int\" Default=\"0\" /><Table-Column Name=\"Disk\" SourceName=\"CurrentLoadIndex\" SourceJsonField=\"Disk\" Type=\"int\" Default=\"0\" /></Table-Columns></Table>");
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='citrixMetrics']"
@@ -378,19 +388,19 @@ namespace C4IT.DataHistoryProvider
, "Table[@Name='M42Wpm-Ticket-Services']"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='M42Tickets']"
, "Table[@Name='M42Wpm-Ticket-QuickCalls']"
, "<Table Name=\"M42Wpm-Ticket-QuickCalls\" Type=\"Selection\" Key=\"id\"><Matrix42-DataQueryItems-Template EntityClassName=\"SPSQuickCallClassBase\" EntityTypeNames=\"SPSQuickCallType\" OrderBy=\"\" WhereExpression=\"Restricted = 0\" DataQueryName=\"C4IT - F4SD - Quick Calls\"/><Table-Columns><Table-Column Name=\"id\" SourceName=\"Id\" Type=\"guid\"/><Table-Column Name=\"SysObjectId\" SourceName=\"Sys-ObjectId\" Type=\"guid\"/><Table-Column Name=\"SysName\" SourceName=\"Sys-Name\" Type=\"string\" Cardinal=\"50\"/><Table-Column Name=\"Name\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"Subject\" Type=\"string\" Cardinal=\"1024\"/><Table-Column Name=\"Priority\" Type=\"string\" Cardinal=\"100\"/><Table-Column Name=\"Responsible\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"ResponsibleRole\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"Category\" SourceName=\"Category_Value\" Type=\"guid\"/></Table-Columns></Table>"
, "Table[@Name='M42Wpm-Ticket-Assets']"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='M42Tickets']"
, "Table[@Name='M42Wpm-Ticket-QuickCalls']"
, "<Table Name=\"M42Wpm-Ticket-QuickCalls\" Type=\"Selection\" Key=\"id\"><Matrix42-DataQueryItems-Template EntityClassName=\"SPSQuickCallClassBase\" EntityTypeNames=\"SPSQuickCallType\" OrderBy=\"\" WhereExpression=\"Restricted = 0\" DataQueryName=\"C4IT - F4SD - Quick Calls\"/><Table-Columns><Table-Column Name=\"id\" SourceName=\"Id\" Type=\"guid\"/><Table-Column Name=\"SysObjectId\" SourceName=\"Sys-ObjectId\" Type=\"guid\"/><Table-Column Name=\"SysName\" SourceName=\"Sys-Name\" Type=\"string\" Cardinal=\"50\"/><Table-Column Name=\"Name\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"Subject\" Type=\"string\" Cardinal=\"1024\"/><Table-Column Name=\"Priority\" Type=\"string\" Cardinal=\"100\"/><Table-Column Name=\"Responsible\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"ResponsibleRole\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"Category\" SourceName=\"Category_Value\" Type=\"guid\"/></Table-Columns></Table>"
, "Table[@Name='M42Wpm-Ticket-Assets']"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='M42Tickets']"
, "Table[@Name='M42Wpm-Ticket-Categories']"
, "<Table Name=\"M42Wpm-Ticket-Categories\" Type=\"Selection\" Key=\"id\"><Matrix42-DataQueryItems-Template EntityClassName=\"SPSScCategoryClassBase\" EntityTypeNames=\"SPSScCategoryType\" OrderBy=\"\" WhereExpression=\"Hidden = 0\"/><Table-Columns><Table-Column Name=\"id\" SourceName=\"Id\" Type=\"guid\"/><Table-Column Name=\"SysObjectId\" SourceName=\"Sys-ObjectId\" Type=\"guid\"/><Table-Column Name=\"SysName\" SourceName=\"Sys-Name\" Type=\"string\" Cardinal=\"50\"/><Table-Column Name=\"Name\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"parentValue\" SourceName=\"Parent_Value\" Type=\"guid\"/><Table-Column Name=\"parent\" SourceName=\"Parent\" Type=\"string\" Cardinal=\"300\"/></Table-Columns></Table>"
, "Table[@Name='M42Wpm-Ticket-QuickCalls']"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='M42Tickets']"
, "Table[@Name='M42Wpm-Ticket-Categories']"
, "<Table Name=\"M42Wpm-Ticket-Categories\" Type=\"Selection\" Key=\"id\"><Matrix42-DataQueryItems-Template EntityClassName=\"SPSScCategoryClassBase\" EntityTypeNames=\"SPSScCategoryType\" OrderBy=\"\" WhereExpression=\"Hidden = 0\"/><Table-Columns><Table-Column Name=\"id\" SourceName=\"Id\" Type=\"guid\"/><Table-Column Name=\"SysObjectId\" SourceName=\"Sys-ObjectId\" Type=\"guid\"/><Table-Column Name=\"SysName\" SourceName=\"Sys-Name\" Type=\"string\" Cardinal=\"50\"/><Table-Column Name=\"Name\" Type=\"string\" Cardinal=\"300\"/><Table-Column Name=\"parentValue\" SourceName=\"Parent_Value\" Type=\"guid\"/><Table-Column Name=\"parent\" SourceName=\"Parent\" Type=\"string\" Cardinal=\"300\"/></Table-Columns></Table>"
, "Table[@Name='M42Wpm-Ticket-QuickCalls']"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "DataCluster[@Name='M42Tickets']"
@@ -493,83 +503,96 @@ namespace C4IT.DataHistoryProvider
}
// update table 'M42Wpm-Tickets' columns
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"Urgency\" Type=\"string\" Cardinal=\"64\"/>", "AffectedUser");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"UrgencyId\" Type=\"int\"/>", "Urgency");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"Impact\" Type=\"string\" Cardinal=\"64\"/>", "UrgencyId");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"ImpactId\" Type=\"int\"/>", "Impact");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Ticket-QuickCalls", "<Table-Column Name=\"Category\" SourceName=\"Category_Value\" Type=\"guid\" />", "ResponsibleRole");
var quickCallsCategoryColumn = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-QuickCalls']/Table-Columns/Table-Column[@Name='Category']") as XmlElement;
if (quickCallsCategoryColumn != null)
{
if (!string.Equals(quickCallsCategoryColumn.GetAttribute("SourceName"), "Category_Value", StringComparison.OrdinalIgnoreCase))
{
quickCallsCategoryColumn.SetAttribute("SourceName", "Category_Value");
RetVal = true;
}
if (!string.Equals(quickCallsCategoryColumn.GetAttribute("Type"), "guid", StringComparison.OrdinalIgnoreCase))
{
quickCallsCategoryColumn.SetAttribute("Type", "guid");
RetVal = true;
}
}
var quickCallsTemplate = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-QuickCalls']/Matrix42-DataQueryItems-Template") as XmlElement;
if (quickCallsTemplate != null)
{
if (!string.Equals(quickCallsTemplate.GetAttribute("DataQueryName"), "C4IT - F4SD - Quick Calls", StringComparison.OrdinalIgnoreCase))
{
quickCallsTemplate.SetAttribute("DataQueryName", "C4IT - F4SD - Quick Calls");
RetVal = true;
}
}
var categoriesColumns = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-Categories']/Table-Columns") as XmlElement;
if (categoriesColumns != null)
{
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Ticket-Categories", "<Table-Column Name=\"parentValue\" SourceName=\"Parent_Value\" Type=\"guid\" />", "Name");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Ticket-Categories", "<Table-Column Name=\"parent\" SourceName=\"Parent\" Type=\"string\" Cardinal=\"300\" />", "parentValue");
var parentValueColumn = categoriesColumns.SelectSingleNode("Table-Column[@Name='parentValue']") as XmlElement;
if (parentValueColumn != null)
{
if (!string.Equals(parentValueColumn.GetAttribute("SourceName"), "Parent_Value", StringComparison.OrdinalIgnoreCase))
{
parentValueColumn.SetAttribute("SourceName", "Parent_Value");
RetVal = true;
}
if (!string.Equals(parentValueColumn.GetAttribute("Type"), "guid", StringComparison.OrdinalIgnoreCase))
{
parentValueColumn.SetAttribute("Type", "guid");
RetVal = true;
}
}
var parentColumn = categoriesColumns.SelectSingleNode("Table-Column[@Name='parent']") as XmlElement;
if (parentColumn != null)
{
if (!string.Equals(parentColumn.GetAttribute("SourceName"), "Parent", StringComparison.OrdinalIgnoreCase))
{
parentColumn.SetAttribute("SourceName", "Parent");
RetVal = true;
}
if (!string.Equals(parentColumn.GetAttribute("Type"), "string", StringComparison.OrdinalIgnoreCase))
{
parentColumn.SetAttribute("Type", "string");
RetVal = true;
}
if (!string.Equals(parentColumn.GetAttribute("Cardinal"), "300", StringComparison.OrdinalIgnoreCase))
{
parentColumn.SetAttribute("Cardinal", "300");
RetVal = true;
}
}
}
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"Urgency\" Type=\"string\" Cardinal=\"64\"/>", "AffectedUser");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"UrgencyId\" Type=\"int\"/>", "Urgency");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"Impact\" Type=\"string\" Cardinal=\"64\"/>", "UrgencyId");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Tickets", "<Table-Column Name=\"ImpactId\" Type=\"int\"/>", "Impact");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Ticket-QuickCalls", "<Table-Column Name=\"Category\" SourceName=\"Category_Value\" Type=\"guid\" />", "ResponsibleRole");
var quickCallsCategoryColumn = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-QuickCalls']/Table-Columns/Table-Column[@Name='Category']") as XmlElement;
if (quickCallsCategoryColumn != null)
{
if (!string.Equals(quickCallsCategoryColumn.GetAttribute("SourceName"), "Category_Value", StringComparison.OrdinalIgnoreCase))
{
quickCallsCategoryColumn.SetAttribute("SourceName", "Category_Value");
RetVal = true;
}
if (!string.Equals(quickCallsCategoryColumn.GetAttribute("Type"), "guid", StringComparison.OrdinalIgnoreCase))
{
quickCallsCategoryColumn.SetAttribute("Type", "guid");
RetVal = true;
}
}
var quickCallsTemplate = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-QuickCalls']/Matrix42-DataQueryItems-Template") as XmlElement;
if (quickCallsTemplate != null)
{
if (!string.Equals(quickCallsTemplate.GetAttribute("DataQueryName"), "C4IT - F4SD - Quick Calls", StringComparison.OrdinalIgnoreCase))
{
quickCallsTemplate.SetAttribute("DataQueryName", "C4IT - F4SD - Quick Calls");
RetVal = true;
}
}
var categoriesColumns = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-Categories']/Table-Columns") as XmlElement;
if (categoriesColumns != null)
{
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Ticket-Categories", "<Table-Column Name=\"parentValue\" SourceName=\"Parent_Value\" Type=\"guid\" />", "Name");
RetVal |= DoXmlInsertTableRow(XmlRoot, "M42Tickets", "M42Wpm-Ticket-Categories", "<Table-Column Name=\"parent\" SourceName=\"Parent\" Type=\"string\" Cardinal=\"300\" />", "parentValue");
var parentValueColumn = categoriesColumns.SelectSingleNode("Table-Column[@Name='parentValue']") as XmlElement;
if (parentValueColumn != null)
{
if (!string.Equals(parentValueColumn.GetAttribute("SourceName"), "Parent_Value", StringComparison.OrdinalIgnoreCase))
{
parentValueColumn.SetAttribute("SourceName", "Parent_Value");
RetVal = true;
}
if (!string.Equals(parentValueColumn.GetAttribute("Type"), "guid", StringComparison.OrdinalIgnoreCase))
{
parentValueColumn.SetAttribute("Type", "guid");
RetVal = true;
}
}
var parentColumn = categoriesColumns.SelectSingleNode("Table-Column[@Name='parent']") as XmlElement;
if (parentColumn != null)
{
if (!string.Equals(parentColumn.GetAttribute("SourceName"), "Parent", StringComparison.OrdinalIgnoreCase))
{
parentColumn.SetAttribute("SourceName", "Parent");
RetVal = true;
}
if (!string.Equals(parentColumn.GetAttribute("Type"), "string", StringComparison.OrdinalIgnoreCase))
{
parentColumn.SetAttribute("Type", "string");
RetVal = true;
}
if (!string.Equals(parentColumn.GetAttribute("Cardinal"), "300", StringComparison.OrdinalIgnoreCase))
{
parentColumn.SetAttribute("Cardinal", "300");
RetVal = true;
}
}
}
var categoriesTemplate = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-Categories']/Matrix42-DataQueryItems-Template") as XmlElement;
if (categoriesTemplate != null)
{
var whereExpression = categoriesTemplate.GetAttribute("WhereExpression");
var normalizedWhereExpression = Regex.Replace(whereExpression ?? string.Empty, @"\s+", string.Empty);
if (string.IsNullOrWhiteSpace(whereExpression)
|| string.Equals(normalizedWhereExpression, "Hidden=false", StringComparison.OrdinalIgnoreCase))
{
categoriesTemplate.SetAttribute("WhereExpression", "Hidden = 0");
RetVal = true;
}
}
// correct the type attribute for the M42Wpm-Ticket-History table to Events
var M42JournalItemNode = XmlRoot.SelectSingleNode("DataCluster[@Name='M42Tickets']/Table[@Name='M42Wpm-Ticket-History' and @Type!='HistoryEvents']") as XmlElement;
@@ -2517,13 +2540,13 @@ namespace C4IT.DataHistoryProvider
}
public class cDataHistoryConfigQueryTemplateM42DataQueryItems : cDataHistoryConfigQueryTemplate
{
public string EntityClassName { get; private set; } = null;
public List<string> EntityTypeNames { get; private set; } = null;
public string OrderBy { get; private set; } = null;
public string WhereExpression { get; private set; } = null;
public string DataQueryName { get; private set; } = null;
public class cDataHistoryConfigQueryTemplateM42DataQueryItems : cDataHistoryConfigQueryTemplate
{
public string EntityClassName { get; private set; } = null;
public List<string> EntityTypeNames { get; private set; } = null;
public string OrderBy { get; private set; } = null;
public string WhereExpression { get; private set; } = null;
public string DataQueryName { get; private set; } = null;
internal cDataHistoryConfigQueryTemplateM42DataQueryItems(XmlElement XNode, cXmlParser Parser) :
@@ -2555,11 +2578,11 @@ namespace C4IT.DataHistoryProvider
EntityTypeNames.Add(_e2);
}
OrderBy = cXmlParser.GetStringFromXmlAttribute(XNode2, "OrderBy");
WhereExpression = cXmlParser.GetStringFromXmlAttribute(XNode2, "WhereExpression");
DataQueryName = cXmlParser.GetStringFromXmlAttribute(XNode2, "DataQueryName");
Parser.LeaveElement("Matrix42-DataQueryItems-Template");
OrderBy = cXmlParser.GetStringFromXmlAttribute(XNode2, "OrderBy");
WhereExpression = cXmlParser.GetStringFromXmlAttribute(XNode2, "WhereExpression");
DataQueryName = cXmlParser.GetStringFromXmlAttribute(XNode2, "DataQueryName");
Parser.LeaveElement("Matrix42-DataQueryItems-Template");
IsValid = true;
}

View File

@@ -58,292 +58,355 @@ namespace C4IT.DataHistoryProvider
}
private cConfigHelperParameterList LoadParameters (XmlElement XRoot, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
var _result = new cConfigHelperParameterList();
try
{
var Items = XRoot.ChildNodes;
foreach (var _node in Items)
{
if (!(_node is XmlElement _item)) continue;
Parser.EnterElement(_item.Name);
try
{
var _attPolicy = _item.GetAttribute("Policy");
var _attValue = _item.GetAttribute("Value");
var _ElementCount = 0;
foreach (XmlNode _subNode in _item.ChildNodes)
{
if (_subNode is XmlElement)
_ElementCount++;
}
// check for special parameters
switch (_item.Name)
{
case "InformationClassSearchPriority":
var _val = getInformationClassSearchPriority(_item, Parser);
if (_val != null)
_result.Items[_val.Name] = _val;
continue;
case "OpenActivitiesExternally":
var _openActivitiesEntry = getOpenActivitiesExternallyEntry(_item);
if (_openActivitiesEntry != null)
_result.Items[_openActivitiesEntry.Name] = _openActivitiesEntry;
var _overrideValues = getOpenActivitiesExternallyOverrides(_item, Parser);
if (_overrideValues != null && _overrideValues.ValueList != null && _overrideValues.ValueList.Count > 0)
_result.Items[_overrideValues.Name] = _overrideValues;
continue;
}
if (_attPolicy != null && _attValue != null && _ElementCount == 0)
{
// we have a simple parameter
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(_item, "Policy", enumConfigPolicy.Default);
var _value = cXmlParser.GetStringFromXmlAttribute(_item, "Value", String.Empty);
_result.Items[_item.Name] = new cConfigHelperParameterEntry()
{
Name = _item.Name,
Value = _value,
Policy = _policy.ToString(),
};
}
else if (string.IsNullOrEmpty(_attPolicy) && string.IsNullOrEmpty(_attValue) && _ElementCount > 0)
{
// we have a sublist
if (_result.SubItems == null)
_result.SubItems = new Dictionary<string, cConfigHelperParameterList>();
_result.SubItems[_item.Name] = LoadParameters(_item, Parser);
}
else
{
// we have an invalid entry
var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return _result;
}
private cConfigHelperParameterEntry getInformationClassSearchPriority(XmlElement XNode, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var _xNodes = XNode.ChildNodes;
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _result = new List<string>();
foreach (var _xNode in _xNodes)
{
if (!(_xNode is XmlElement _item))
continue;
Parser.EnterElement(_item.Name);
try
{
if (_item.Name != "InformationClass")
{
// we have an invalid entry
var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}, should be <InformationClass/>";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var _InfoClass = cXmlParser.GetEnumFromAttribute<enumFasdInformationClass>(_item, "Type", enumFasdInformationClass.Unknown);
if (_InfoClass == enumFasdInformationClass.Unknown)
{
// we have an invalid type attribute
var _strType = cXmlParser.GetStringFromXmlAttribute(_item, "Type", String.Empty);
var _msg = $"Invalid type attribute value ({_strType}) in entry {_item.Name}";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var _strInfoClass = _InfoClass.ToString();
if (!_result.Contains(_strInfoClass))
_result.Add(_strInfoClass);
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
return new cConfigHelperParameterEntry()
{
Name = XNode.Name,
ValueList = _result,
Policy = _policy.ToString()
};
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return null;
}
private static cConfigHelperParameterEntry getOpenActivitiesExternallyEntry(XmlElement XNode)
{
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _value = cXmlParser.GetStringFromXmlAttribute(XNode, "Value", String.Empty);
if (string.IsNullOrWhiteSpace(_value))
return null;
return new cConfigHelperParameterEntry()
{
Name = "OpenActivitiesExternally",
Value = _value,
Policy = _policy.ToString(),
};
}
private cConfigHelperParameterEntry getOpenActivitiesExternallyOverrides(XmlElement XNode, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var _xNodes = XNode.ChildNodes;
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _result = new List<string>();
foreach (var _xNode in _xNodes)
{
if (!(_xNode is XmlElement _item))
continue;
Parser.EnterElement(_item.Name);
try
{
if (_item.Name != "OpenActivityOverride")
{
var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}, should be <OpenActivityOverride/>";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var activityType = cXmlParser.GetStringFromXmlAttribute(_item, "ActivityType", String.Empty)?.Trim();
if (string.IsNullOrWhiteSpace(activityType))
{
var _msg = $"Missing ActivityType attribute value in entry {_item.Name}";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var valueText = cXmlParser.GetStringFromXmlAttribute(_item, "Value", String.Empty)?.Trim();
if (string.IsNullOrWhiteSpace(valueText))
{
var _msg = $"Missing Value attribute value in entry {_item.Name} ({activityType})";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var normalizedValue = valueText.ToLowerInvariant();
bool? parsedValue = null;
switch (normalizedValue)
{
case "true":
case "1":
case "yes":
parsedValue = true;
break;
case "false":
case "0":
case "no":
parsedValue = false;
break;
}
if (!parsedValue.HasValue)
{
var _msg = $"Invalid Value attribute value ({valueText}) in entry {_item.Name} ({activityType})";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
_result.Add($"{activityType}={(parsedValue.Value ? "true" : "false")}");
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
return new cConfigHelperParameterEntry()
{
Name = "OpenActivitiesExternallyOverrides",
ValueList = _result,
Policy = _policy.ToString()
};
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return null;
}
private cConfigHelperParameterList LoadParameters (XmlElement XRoot, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
var _result = new cConfigHelperParameterList();
try
{
var Items = XRoot.ChildNodes;
foreach (var _node in Items)
{
if (!(_node is XmlElement _item)) continue;
Parser.EnterElement(_item.Name);
try
{
var _attPolicy = _item.GetAttribute("Policy");
var _attValue = _item.GetAttribute("Value");
var _ElementCount = 0;
foreach (XmlNode _subNode in _item.ChildNodes)
{
if (_subNode is XmlElement)
_ElementCount++;
}
// check for special parameters
switch (_item.Name)
{
case "InformationClassSearchPriority":
var _val = getInformationClassSearchPriority(_item, Parser);
if (_val != null)
_result.Items[_val.Name] = _val;
continue;
case "OpenActivitiesExternally":
var _openActivitiesEntry = getOpenActivitiesExternallyEntry(_item);
if (_openActivitiesEntry != null)
_result.Items[_openActivitiesEntry.Name] = _openActivitiesEntry;
var _overrideValues = getOpenActivitiesExternallyOverrides(_item, Parser);
if (_overrideValues != null && _overrideValues.ValueList != null && _overrideValues.ValueList.Count > 0)
_result.Items[_overrideValues.Name] = _overrideValues;
continue;
case "TicketProcessing":
var _ticketProcessingEntry = getTicketProcessingEntry(_item, Parser);
if (_ticketProcessingEntry != null)
_result.Items[_ticketProcessingEntry.Name] = _ticketProcessingEntry;
continue;
}
if (_attPolicy != null && _attValue != null && _ElementCount == 0)
{
// we have a simple parameter
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(_item, "Policy", enumConfigPolicy.Default);
var _value = cXmlParser.GetStringFromXmlAttribute(_item, "Value", String.Empty);
_result.Items[_item.Name] = new cConfigHelperParameterEntry()
{
Name = _item.Name,
Value = _value,
Policy = _policy.ToString(),
};
}
else if (string.IsNullOrEmpty(_attPolicy) && string.IsNullOrEmpty(_attValue) && _ElementCount > 0)
{
// we have a sublist
if (_result.SubItems == null)
_result.SubItems = new Dictionary<string, cConfigHelperParameterList>();
_result.SubItems[_item.Name] = LoadParameters(_item, Parser);
}
else
{
// we have an invalid entry
var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return _result;
}
private cConfigHelperParameterEntry getInformationClassSearchPriority(XmlElement XNode, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var _xNodes = XNode.ChildNodes;
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _result = new List<string>();
foreach (var _xNode in _xNodes)
{
if (!(_xNode is XmlElement _item))
continue;
Parser.EnterElement(_item.Name);
try
{
if (_item.Name != "InformationClass")
{
// we have an invalid entry
var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}, should be <InformationClass/>";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var _InfoClass = cXmlParser.GetEnumFromAttribute<enumFasdInformationClass>(_item, "Type", enumFasdInformationClass.Unknown);
if (_InfoClass == enumFasdInformationClass.Unknown)
{
// we have an invalid type attribute
var _strType = cXmlParser.GetStringFromXmlAttribute(_item, "Type", String.Empty);
var _msg = $"Invalid type attribute value ({_strType}) in entry {_item.Name}";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var _strInfoClass = _InfoClass.ToString();
if (!_result.Contains(_strInfoClass))
_result.Add(_strInfoClass);
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
return new cConfigHelperParameterEntry()
{
Name = XNode.Name,
ValueList = _result,
Policy = _policy.ToString()
};
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return null;
}
private static cConfigHelperParameterEntry getTicketProcessingEntry(XmlElement XNode, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var _xNodes = XNode.SelectNodes("TicketTypeProcessing");
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _value = cXmlParser.GetEnumFromAttribute<enumTicketProcessing>(XNode, "Value", enumTicketProcessing.Both);
var _result = new List<string>();
foreach (var _xNode in _xNodes)
{
if (!(_xNode is XmlElement _item))
continue;
Parser.EnterElement(_item.Name);
try
{
var _ticketType = cXmlParser.GetEnumFromAttribute<enumTicketType>(_item, "Type", enumTicketType.Ticket);
var _processingValue = cXmlParser.GetEnumFromAttribute<enumTicketProcessing>(_item, "Value", enumTicketProcessing.Both);
_result.Add(_ticketType.ToString() + "=" + _processingValue.ToString());
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
var _retVal = new cConfigHelperParameterEntry()
{
Name = XNode.Name,
ValueList = _result,
Policy = _policy.ToString()
};
return _retVal;
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return null;
}
private static cConfigHelperParameterEntry getOpenActivitiesExternallyEntry(XmlElement XNode)
{
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _value = cXmlParser.GetStringFromXmlAttribute(XNode, "Value", String.Empty);
if (string.IsNullOrWhiteSpace(_value))
return null;
return new cConfigHelperParameterEntry()
{
Name = "OpenActivitiesExternally",
Value = _value,
Policy = _policy.ToString(),
};
}
private cConfigHelperParameterEntry getOpenActivitiesExternallyOverrides(XmlElement XNode, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var _xNodes = XNode.ChildNodes;
var _policy = cXmlParser.GetEnumFromAttribute<enumConfigPolicy>(XNode, "Policy", enumConfigPolicy.Default);
var _result = new List<string>();
foreach (var _xNode in _xNodes)
{
if (!(_xNode is XmlElement _item))
continue;
Parser.EnterElement(_item.Name);
try
{
if (_item.Name != "OpenActivityOverride")
{
var _msg = $"Invalid entry in F4SD-Global-Configuration.xml: {_item.Name}, should be <OpenActivityOverride/>";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var activityType = cXmlParser.GetStringFromXmlAttribute(_item, "ActivityType", String.Empty)?.Trim();
if (string.IsNullOrWhiteSpace(activityType))
{
var _msg = $"Missing ActivityType attribute value in entry {_item.Name}";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var valueText = cXmlParser.GetStringFromXmlAttribute(_item, "Value", String.Empty)?.Trim();
if (string.IsNullOrWhiteSpace(valueText))
{
var _msg = $"Missing Value attribute value in entry {_item.Name} ({activityType})";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
var normalizedValue = valueText.ToLowerInvariant();
bool? parsedValue = null;
switch (normalizedValue)
{
case "true":
case "1":
case "yes":
parsedValue = true;
break;
case "false":
case "0":
case "no":
parsedValue = false;
break;
}
if (!parsedValue.HasValue)
{
var _msg = $"Invalid Value attribute value ({valueText}) in entry {_item.Name} ({activityType})";
Parser.AddMessage(_item, _msg, LogLevels.Warning);
LogEntry(_msg, LogLevels.Warning);
continue;
}
_result.Add($"{activityType}={(parsedValue.Value ? "true" : "false")}");
}
catch (Exception E)
{
LogException(E);
}
finally
{
Parser.LeaveElement(_item.Name);
}
}
return new cConfigHelperParameterEntry()
{
Name = "OpenActivitiesExternallyOverrides",
ValueList = _result,
Policy = _policy.ToString()
};
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return null;
}
public override bool DoXmlUpdates(XmlElement XmlRoot, bool withM42Config = false, bool withIntuneConfig = false, bool withMobileDeviceConfig = false, bool withCitrixConfig = false)
{
@@ -409,31 +472,31 @@ namespace C4IT.DataHistoryProvider
, "NotesMandatory"
, "<NotesMandatory Policy=\"Hidden\" Value=\"false\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "ShowOverview"
, "<ShowOverview Policy=\"Hidden\" Value=\"true\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "OpenActivitiesExternally"
, "<OpenActivitiesExternally Policy=\"Hidden\" Value=\"false\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration/OpenActivitiesExternally"
, "OpenActivityOverride[@ActivityType='SPSActivityTypeTicket']"
, "<OpenActivityOverride ActivityType=\"SPSActivityTypeTicket\" Value=\"false\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration/OpenActivitiesExternally"
, "OpenActivityOverride[@ActivityType='SPSActivityTypeServiceRequest']"
, "<OpenActivityOverride ActivityType=\"SPSActivityTypeServiceRequest\" Value=\"true\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "OverviewPollingPersonal"
, $"<OverviewPollingPersonal Policy=\"Hidden\" Value=\"{cF4sdTicketConfig.DefaultOverviewPollingPersonal}\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "ShowOverview"
, "<ShowOverview Policy=\"Hidden\" Value=\"true\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "OpenActivitiesExternally"
, "<OpenActivitiesExternally Policy=\"Hidden\" Value=\"false\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration/OpenActivitiesExternally"
, "OpenActivityOverride[@ActivityType='SPSActivityTypeTicket']"
, "<OpenActivityOverride ActivityType=\"SPSActivityTypeTicket\" Value=\"false\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration/OpenActivitiesExternally"
, "OpenActivityOverride[@ActivityType='SPSActivityTypeServiceRequest']"
, "<OpenActivityOverride ActivityType=\"SPSActivityTypeServiceRequest\" Value=\"true\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "OverviewPollingPersonal"
, $"<OverviewPollingPersonal Policy=\"Hidden\" Value=\"{cF4sdTicketConfig.DefaultOverviewPollingPersonal}\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "OverviewPollingRole"
@@ -451,8 +514,30 @@ namespace C4IT.DataHistoryProvider
RetVal |= DoXmlInsertElement(XmlRoot
, "TicketConfiguration"
, "DisableAutomaticTimeTracking"
, $"<DisableAutomaticTimeTracking Policy=\"Mandatory\" Value=\"{oldDisableAutomaticTimeTracking.ToString()}\" />"
, $"<DisableAutomaticTimeTracking Policy=\"Mandatory\" Value=\"{oldDisableAutomaticTimeTracking.ToString().ToLowerInvariant()}\" />"
);
if(withIntuneConfig)
{
RetVal |= DoXmlInsertElement(XmlRoot
, ""
, "IntuneConfiguration"
, "<IntuneConfiguration />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "IntuneConfiguration"
, "TAPLifeTimeInMinutes"
, $"<TAPLifeTimeInMinutes Policy=\"Default\" Value=\"{cF4sdIntuneConfig.DefaultTAPLifeTimeInMinutes}\" />"
);
RetVal |= DoXmlInsertElement(XmlRoot
, "IntuneConfiguration"
, "TAPIsUsableOnce"
, $"<TAPIsUsableOnce Policy=\"Default\" Value=\"{cF4sdIntuneConfig.DefaultTAPIsUsableOnce}\" />"
);
}
}
catch (Exception E)

View File

@@ -1,15 +1,15 @@
using C4IT.Configuration;
using C4IT.FASD.Base;
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT.Security;
using C4IT.XML;
using C4IT_DataHistoryProvider;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using C4IT.DataHistoryProvider.Base.Modules.Citrix;
using static C4IT.Logging.cLogManager;
using static C4IT_DataHistoryProvider.cDataHistoryConfigCitrix;
namespace C4IT.DataHistoryProvider
{
@@ -32,13 +32,14 @@ namespace C4IT.DataHistoryProvider
public cDataHistoryConfigClientAgent ClientAgent { get; private set; } = null;
public cDataHistoryConfigM42Wpm M42Wpm { get; private set; } = null;
public cDataHistoryConfigCitrix Citrix { get; private set; } = null;
public Dictionary<string, cDataHistoryCitrixTenant> CitrixTenants { get; private set; } = null;
public cDataHistoryConfigNexthink Nexthink { get; private set; } = null;
public cDataHistoryConfigActiveDirectory ActiveDirectory { get; private set; } = null;
public Dictionary<string, cDataHistoryAzureTenant> AzureTenants { get; private set; } = null;
public Dictionary<string, cDataHistoryAzureTenant> AzureTenants { get; private set; } = null; //ToDo: create a class for the azure configuration instead of only the tenants
public cF4SDAuthorisation Authorisation { get; private set; } = null;
@@ -81,7 +82,6 @@ namespace C4IT.DataHistoryProvider
ActiveDirectory = _ad;
AzureTenants = cDataHistoryAzureTenant.LoadFromXml(XRoot, Credentials, Parser);
CitrixTenants = cDataHistoryCitrixTenant.LoadFromXml(XRoot, Credentials, Parser);
// get the client agent config
var _cla = new cDataHistoryConfigClientAgent(XRoot, Credentials, Conns, Parser);

View File

@@ -102,9 +102,12 @@ namespace C4IT.DataHistoryProvider
string name = a["QueueName"]?.Value;
string id = a["QueueID"]?.Value;
Guid guid;
Guid guid = Guid.Empty;
if (string.IsNullOrWhiteSpace(name) || !Guid.TryParse(id, out guid))
if (string.IsNullOrWhiteSpace(name))
return null;
if (!string.IsNullOrWhiteSpace(id) && !Guid.TryParse(id, out guid))
return null;
return new cApiM42TicketQueueInfo

View File

@@ -0,0 +1,16 @@
using C4IT.FASD.Base;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace C4IT.DataHistoryProvider.Base.DataSources
{
public interface IRemoteDesktopManager<TRemoteConnectionInfo, TClientInfo, TRemoteConnectionStatus>
{
Task<TRemoteConnectionInfo> InitiateConnectionOfClient(TClientInfo clientInfos, bool isElevated, CancellationToken token = default);
Task TerminateConnection(Guid connectionId);
Task<TRemoteConnectionStatus> GetConnectionStatus(Guid connectionId);
bool IsActive();
Task<HealthInformation> GetHealthInfo();
}
}

View File

@@ -1,9 +1,11 @@
using C4IT.FASD.Base;
using System;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using C4IT.DataHistoryProvider;
using C4IT.FASD.Base;
namespace C4IT_DataHistoryProvider_Base.DataSources
{
public interface ISearchResultRelationProvider
@@ -17,6 +19,6 @@ namespace C4IT_DataHistoryProvider_Base.DataSources
/// <param name="informationClass">Determines the information class the objects have, for which relations should be searched.</param>
/// <param name="ageInDays">Specifies the time, in which the relations should be considered.</param>
/// <returns></returns>
Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdIdentityEntry> ids, enumFasdInformationClass informationClass, int ageInDays, CancellationToken token = default);
Task<cF4sdStagedSearchResultRelations> GetRelationsAsync(IEnumerable<cF4sdConnectorIds> ids, enumFasdInformationClass informationClass, int ageInDays, CancellationToken token = default);
}
}

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<PropertyGroup>
<OutputType>Library</OutputType>
<RootNamespace>C4IT_DataHistoryProvider_Base</RootNamespace>
<RootNamespace>C4IT.DataHistoryProvider.Base</RootNamespace>
<Configurations>Debug;Debug-Demo;Release;Release-Demo</Configurations>
<Deterministic>false</Deterministic>
</PropertyGroup>
@@ -50,6 +50,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\C4IT FASD\_Common\C4IT.F4SD.Base.Ticket.cs" Link="Common\C4IT.F4SD.Base.Ticket.cs" />
<Compile Include="..\..\C4IT FASD\_Common\C4IT.F4SD.GlobalConfig.cs">
<Link>Common\C4IT.F4SD.GlobalConfig.cs</Link>
</Compile>

View File

@@ -0,0 +1,95 @@
using C4IT.DataHistoryProvider.Base.Modules.Agent.DTOs;
using C4IT.FASD.Base;
using C4IT.FASD.Communication.Agent;
using C4IT.HTTP;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using static C4IT.Logging.cLogManager;
namespace C4IT.DataHistoryProvider.Base.Modules.Agent
{
internal class AgentApiHandler : cHttpApiBase
{
private readonly Uri _baseUrl;
private const string _agentLoginPath = "connect/token";
private readonly cAgentApiConfiguration _agentConfig;
public AgentApiHandler(cAgentApiConfiguration agentConfig) : base("Agent ID tenant", $"{agentConfig.ApiUrl}/{agentConfig.LogonUrl}")
{
_agentConfig = agentConfig;
_baseUrl = new Uri(_agentConfig.LogonUrl);
AlwaysReturnContent = true;
}
private protected override async Task<bool> privLogonAsync(cOAuthLogonInfo logonInfo)
{
try
{
var postData = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("client_id", logonInfo.ClientID),
new KeyValuePair<string, string>("client_secret", logonInfo.ClientSecret)
};
var formData = new FormUrlEncodedContent(postData);
var request = new HttpRequestMessage(HttpMethod.Post, new Uri(_baseUrl, _agentLoginPath)) { Content = formData };
using (var httpClient = new HttpClient())
{
var response = await httpClient.SendAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
{
var responseMessage = await response.Content.ReadAsStreamAsync();
LogEntry($"F4SD Agent Logon failed. StatusCode: {response.StatusCode}");
LogEntry($"F4SD Agent Logon failed. Response: {responseMessage}");
return false;
}
string responseContent = await response.Content.ReadAsStringAsync();
var logonResult = JsonConvert.DeserializeObject<cAgentApiLogonInfo>(responseContent);
if (logonResult.TokenType.Equals("Bearer", StringComparison.OrdinalIgnoreCase) == false)
{
LogEntry("F4SD Agent Access token is not of type 'Bearer'.");
return false;
}
cAgentApiLogonInfo.Instance = logonResult;
AccessToken = logonResult.AccessToken;
TokenExpiresIn = DateTime.UtcNow + TimeSpan.FromSeconds(logonResult.SecondsTillTokenExpires * RelogonFactor);
IsOnline = true;
}
return true;
}
catch (Exception ex)
{
LogException(ex);
return false;
}
}
internal async Task<T> Request<T>(string url, eHttpMethod httpMethod = eHttpMethod.get, object bodyData = null, CancellationToken token = default) where T : AgentApiResult
{
await LogonAsync(new cOAuthLogonInfo() { ClientID = _agentConfig.ClientId, ClientSecret = _agentConfig.ClientSecret, Tenant = "F4SD Agent" });
Uri agentUrl = new Uri(_baseUrl, url);
dynamic requestResult = await privRequestAsync(agentUrl.ToString(), httpMethod, bodyData, token: token);
// todo handle not successfull status
requestResult.ToObject<T>();
string serialized = JsonConvert.SerializeObject(requestResult); // todo find better approach for casting the dynamic
T deserialized = JsonConvert.DeserializeObject<T>(serialized);
return deserialized;
}
internal async Task Request(string url, eHttpMethod httpMethod = eHttpMethod.get, object bodyData = null)
=> await privRequestAsync(url, httpMethod, bodyData);
}
}

View File

@@ -0,0 +1,16 @@
using Newtonsoft.Json;
namespace C4IT.DataHistoryProvider.Base.Modules.Agent
{
public class AgentRemoteClientInfo
{
[JsonProperty("orgCode")]
public int OrganisationCode { get; set; }
[JsonProperty("deviceCode")]
public int DeviceCode { get; set; }
[JsonProperty("accountCode")]
public int AccountCode { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using C4IT.FASD.Communication.Agent;
using Newtonsoft.Json;
using System;
namespace C4IT.DataHistoryProvider.Base.Modules.Agent
{
public class AgentRemoteConnectionInfo : AgentApiResult
{
[JsonProperty("connectionId")]
public Guid ConnectionId { get; set; }
[JsonProperty("phoenixServiceUrl")]
public Uri ServiceUrl { get; set; }
[JsonProperty("secret")]
public string Secret { get; set; }
}
}

View File

@@ -0,0 +1,46 @@
using C4IT.DataHistoryProvider.Base.DataSources;
using C4IT.FASD.Base;
using C4IT.FASD.Communication.Agent;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace C4IT.DataHistoryProvider.Base.Modules.Agent
{
public class AgentRemoteDesktopManager : IRemoteDesktopManager<AgentRemoteConnectionInfo, AgentRemoteClientInfo, AgentRemoteConnectionStatusDto>
{
private readonly AgentApiHandler _agentApiHandler;
public AgentRemoteDesktopManager(cAgentApiConfiguration agentConfig)
{
_agentApiHandler = new AgentApiHandler(agentConfig);
}
public async Task<AgentRemoteConnectionStatusDto> GetConnectionStatus(Guid connectionId)
{
return await _agentApiHandler.Request<AgentRemoteConnectionStatusDto>($"api/management/c4it/phoenix-connections/{connectionId}/status", HTTP.eHttpMethod.get);
}
public async Task<AgentRemoteConnectionInfo> InitiateConnectionOfClient(AgentRemoteClientInfo clientInfos, bool isElevated, CancellationToken token)
{
string url = "api/management/c4it/phoenix-connections";
if (isElevated)
url += "/admin";
return await _agentApiHandler.Request<AgentRemoteConnectionInfo>(url, HTTP.eHttpMethod.post, clientInfos, token);
}
public async Task TerminateConnection(Guid connectionId)
{
await _agentApiHandler.Request($"api/management/c4it/phoenix-connections/{connectionId}", HTTP.eHttpMethod.delete);
}
public bool IsActive() => true;
public Task<HealthInformation> GetHealthInfo()
{
// todo Agent Server has to implement an "health" endpoint and return its result
return Task.FromResult(new HealthInformation(HealthStatus.healthy));
}
}
}

View File

@@ -0,0 +1,13 @@
using Newtonsoft.Json;
namespace C4IT.DataHistoryProvider.Base.Modules.Agent.DTOs
{
public class AgentErrorDto
{
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
using Newtonsoft.Json;
namespace C4IT.DataHistoryProvider.Base.Modules.Agent.DTOs
{
public class AgentLogonResultDto
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("scope")]
public string Scope { get; set; }
[JsonProperty("remote_ip")]
public string RemoteIp { get; set; }
}
}

View File

@@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Net;
using System.Reflection;
using System.Xml;
using C4IT.DataHistoryProvider;
using C4IT.Logging;
using C4IT.Security;
using C4IT.XML;
using static C4IT.Logging.cLogManager;
namespace C4IT.DataHistoryProvider.Base.Modules.Citrix
{
public class cDataHistoryConfigCitrix : IConfigNodeValidation
{
public bool IsValid { get; private set; } = false;
public cDataHistoryScanTiming ScanTiming { get; private set; } = null;
public cDataHistoryConfigCitrix(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var XNode2 = XNode.SelectSingleNode("Citrix");
if (!(XNode2 is XmlElement XCitrix))
{
return;
}
Parser.EnterElement("Citrix");
try
{
ScanTiming = new cDataHistoryScanTiming(XCitrix, TimeSpan.FromHours(24), TimeSpan.FromMinutes(10), Parser);
Systems = cDataHistoryCitrixCloudTenant.LoadFromXml(XCitrix, Credentials, Parser);
if (Systems == null)
Systems = new List<cDataHistoryCitrixSystem>();
var _onPremSystems = cDataHistoryCitrixOnPrem.LoadFromXml(XCitrix, Credentials, Parser);
if (_onPremSystems != null)
Systems.AddRange(_onPremSystems);
IsValid = true;
}
finally
{
Parser.LeaveElement("Citrix");
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
public List<cDataHistoryCitrixSystem> Systems { get; private set; } = null; //ToDo: Check all uses of the citrix systems to implement on prem and tenant specific handling if needed
}
public abstract class cDataHistoryCitrixSystem : cConfigNodeNamed
{
public cCredential Credential { get; private set; } = null;
public Guid SiteID { get; set; } = Guid.Empty;
public cDataHistoryCitrixSystem(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser) : base(XNode, Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
if (!IsValid)
return;
SiteID = cXmlParser.GetGuidFromXmlAttribute(XNode, "SiteID");
var strCreds = cXmlParser.GetStringFromXmlAttribute(XNode, "Credential");
if (!string.IsNullOrWhiteSpace(strCreds))
{
if (Credentials.TryGetValue(strCreds, out var Cred))
Credential = Cred;
}
if (Credential == null)
{
Parser.AddInvalidAttribute(XNode, null, "Credential");
return;
}
IsValid = true;
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
}
public class cDataHistoryCitrixCloudTenant : cDataHistoryCitrixSystem
{
public string Domain { get; private set; } = "";
public string TenantID { get; private set; } = String.Empty;
internal cDataHistoryCitrixCloudTenant(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser) : base(XNode, Credentials, Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
if (!IsValid)
return;
Domain = cXmlParser.GetStringFromXmlAttribute(XNode, "Domain");
if (string.IsNullOrWhiteSpace(Domain))
{
Parser.AddInvalidAttribute(XNode, null, "Domain");
return;
}
TenantID = cXmlParser.GetStringFromXmlAttribute(XNode, "TenantID");
if (TenantID == String.Empty)
{
Parser.AddInvalidAttribute(XNode, Domain, "TenantID");
return;
}
IsValid = true;
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
internal static List<cDataHistoryCitrixSystem> LoadFromXml(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
var RetVal = new List<cDataHistoryCitrixSystem>();
try
{
var XList = XNode.SelectNodes("Citrix-Cloud-Tenant");
if (XList != null && XList.Count > 0)
{
Parser.EnterElement("Citrix-Cloud-Tenant");
try
{
foreach (var Entry in XList)
{
if (!(Entry is XmlElement XEntry))
continue;
var Node = new cDataHistoryCitrixCloudTenant(XEntry, Credentials, Parser);
if (Node.IsValid)
RetVal.Add(Node);
Parser.SelectElementNext();
}
}
finally
{
Parser.LeaveElement("Citrix-Cloud-Tenant");
}
}
XList = XNode.SelectNodes("Citrix-OnPrem-System");
if (XList != null && XList.Count > 0)
{
Parser.EnterElement("Citrix-OnPrem-System");
try
{
foreach (var Entry in XList)
{
if (!(Entry is XmlElement XEntry))
continue;
var Node = new cDataHistoryCitrixOnPrem(XEntry, Credentials, Parser);
if (Node.IsValid)
RetVal.Add(Node);
Parser.SelectElementNext();
}
}
finally
{
Parser.LeaveElement("Citrix-OnPrem-System");
}
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return RetVal;
}
}
public class cDataHistoryCitrixOnPrem : cDataHistoryCitrixSystem
{
public string Server { get; private set; } = string.Empty;
internal cDataHistoryCitrixOnPrem(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser) : base(XNode, Credentials, Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
Server = cXmlParser.GetStringFromXmlAttribute(XNode, "Server");
if (string.IsNullOrWhiteSpace(Server))
{
Parser.AddInvalidAttribute(XNode, null, "Server");
return;
}
IsValid = true;
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
}
internal static List<cDataHistoryCitrixSystem> LoadFromXml(XmlElement XNode, Dictionary<string, cCredential> Credentials, cXmlParser Parser)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
var RetVal = new List<cDataHistoryCitrixSystem>();
try
{
var XList = XNode.SelectNodes("Citrix-OnPrem");
if (XList != null && XList.Count > 0)
{
Parser.EnterElement("Citrix-OnPrem");
try
{
foreach (var Entry in XList)
{
if (!(Entry is XmlElement XEntry))
continue;
var Node = new cDataHistoryCitrixOnPrem(XEntry, Credentials, Parser);
if (Node.IsValid)
RetVal.Add(Node);
Parser.SelectElementNext();
}
}
finally
{
Parser.LeaveElement("Citrix-OnPrem");
}
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return RetVal;
}
}
}

View File

@@ -11,7 +11,7 @@ namespace C4IT_DataHistoryProvider_Base.Services
/// <summary>
/// Triggers search for relations to given information objects.
/// </summary>
cF4sdStagedSearchResultRelationTaskId StartGatheringRelatedObjects(IEnumerable<cFasdApiSearchResultEntry> relatedTo, int ageInDays);
Task<cF4sdStagedSearchResultRelationTaskId> StartGatheringRelatedObjects(IEnumerable<cFasdApiSearchResultEntry> relatedTo, int ageInDays);
/// <summary>
/// Used after triggering search for related objects in <see cref="StartGatheringRelatedObjects"/> to retrieve the already found relations.

View File

@@ -1,4 +1,5 @@
using C4IT.FASD.Base;
using C4IT.DataHistoryProvider;
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT_DataHistoryProvider_Base.DataSources;
using System;
@@ -16,13 +17,16 @@ namespace C4IT_DataHistoryProvider_Base.Services
private static readonly Dictionary<Guid, GatherRelatedObjectTask> _relationTasks = new Dictionary<Guid, GatherRelatedObjectTask>();
private readonly IEnumerable<ISearchResultRelationProvider> _providers;
private readonly cDataHistoryCollector _collector;
private static readonly System.Timers.Timer _relationTaskCleanupTimer = new System.Timers.Timer(CleanupInterval);
private const int CleanupInterval = 5 * 60 * 1000;
private readonly TimeSpan RelationTaskExpiration = TimeSpan.FromMinutes(15);
public StagedRelationService(IEnumerable<ISearchResultRelationProvider> providers)
public StagedRelationService(cDataHistoryCollector collector, IEnumerable<ISearchResultRelationProvider> providers)
{
_providers = providers;
_collector = collector;
SetupCleanupTimer();
}
@@ -36,7 +40,7 @@ namespace C4IT_DataHistoryProvider_Base.Services
_relationTaskCleanupTimer.Start();
}
public cF4sdStagedSearchResultRelationTaskId StartGatheringRelatedObjects(IEnumerable<cFasdApiSearchResultEntry> relatedTo, int age)
public async Task<cF4sdStagedSearchResultRelationTaskId> StartGatheringRelatedObjects(IEnumerable<cFasdApiSearchResultEntry> relatedTo, int age)
{
cF4sdStagedSearchResultRelationTaskId taskId = new cF4sdStagedSearchResultRelationTaskId();
try
@@ -49,12 +53,14 @@ namespace C4IT_DataHistoryProvider_Base.Services
List<cF4sdIdentityEntry> identities = relatedTo.Select(relation => new cF4sdIdentityEntry() { Id = relation.id, Class = relatedToInformationClass }).ToList();
var _ids = await _collector.getConnectorIdList(identities, CancellationToken.None, null, age);
foreach (var collectorModule in _providers)
{
taskId.PendingInformationClasses.UnionWith(collectorModule.GetSupportedInformationClasses());
Task<cF4sdStagedSearchResultRelations> task = Task.Run(() =>
collectorModule.GetRelationsAsync(identities, relatedToInformationClass, age, relationTask.TokenSource.Token));
collectorModule.GetRelationsAsync(_ids, relatedToInformationClass, age, relationTask.TokenSource.Token));
relationTask.RelatedObjectTasks.Add((collectorModule.GetSupportedInformationClasses(), task));
}