From 0555ddf6930a5f6df25490fadae242a72af7c996 Mon Sep 17 00:00:00 2001 From: abarz722 Date: Sat, 8 Jun 2024 12:19:27 +0200 Subject: [PATCH 01/11] AppRule Report first steps + cleanup --- roles/api/files/replace_metadata.json | 498 ++++++++++++++ .../files/sql/idempotent/fworch-api-funcs.sql | 23 + .../files/sql/idempotent/fworch-texts.sql | 4 + roles/database/files/upgrade/8.2.4.sql | 22 + .../Data/ComplianceNetworkZone.cs | 20 +- .../files/FWO.Api.Client/Data/DeviceFilter.cs | 26 +- .../files/FWO.Api.Client/Data/DisplayBase.cs | 6 +- roles/lib/files/FWO.Api.Client/Data/Rule.cs | 17 +- .../FWO.Report.Filter/Ast/AstNodeConnector.cs | 40 +- .../Ast/AstNodeFilterBool.cs | 4 +- .../Ast/AstNodeFilterDateTimeRange.cs | 8 +- .../FWO.Report.Filter/Ast/AstNodeFilterInt.cs | 8 +- .../Ast/AstNodeFilterNetwork.cs | 35 +- .../Ast/AstNodeFilterReportType.cs | 2 +- .../Ast/AstNodeFilterString.cs | 24 +- .../FWO.Report.Filter/Ast/AstNodeUnary.cs | 4 +- roles/lib/files/FWO.Report.Filter/Compiler.cs | 4 +- .../FWO.Report.Filter/DynGraphqlQuery.cs | 629 +++++++++--------- .../FilterTypes/ReportFilters.cs | 13 +- .../FilterTypes/ReportType.cs | 5 +- .../FWO.Report/Display/RuleDisplayBase.cs | 42 +- .../FWO.Report/Display/RuleDisplayCsv.cs | 2 +- .../FWO.Report/Display/RuleDisplayHtml.cs | 55 +- .../FWO.Report/Display/RuleDisplayJson.cs | 2 +- roles/lib/files/FWO.Report/ReportAppRules.cs | 117 ++++ roles/lib/files/FWO.Report/ReportBase.cs | 1 + roles/lib/files/FWO.Report/ReportChanges.cs | 10 +- .../lib/files/FWO.Report/ReportDevicesBase.cs | 17 +- roles/lib/files/FWO.Report/ReportNatRules.cs | 4 +- roles/lib/files/FWO.Report/ReportRules.cs | 20 +- .../lib/files/FWO.Report/ReportStatistics.cs | 2 +- .../FWO.Middleware.Server/RecertCheck.cs | 22 +- .../FWO.UI/Pages/Compliance/ZonesChecks.razor | 14 +- .../files/FWO.UI/Pages/Reporting/Report.razor | 40 +- 34 files changed, 1233 insertions(+), 507 deletions(-) create mode 100644 roles/database/files/upgrade/8.2.4.sql create mode 100644 roles/lib/files/FWO.Report/ReportAppRules.cs diff --git a/roles/api/files/replace_metadata.json b/roles/api/files/replace_metadata.json index 991d9992a..776563c9c 100644 --- a/roles/api/files/replace_metadata.json +++ b/roles/api/files/replace_metadata.json @@ -4489,6 +4489,15 @@ }, "session_argument": "hasura_session" } + }, + { + "name": "get_rules_for_owner", + "definition": { + "function": { + "name": "get_rules_for_owner", + "schema": "public" + } + } } ], "insert_permissions": [ @@ -6078,6 +6087,32 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "changes_found", + "is_initial_import", + "successful_import", + "mgm_id", + "control_id", + "last_change_in_config", + "start_time", + "stop_time", + "delimiter_group", + "delimiter_list", + "delimiter_user", + "delimiter_zone", + "import_errors" + ], + "filter": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -8831,6 +8866,49 @@ "allow_aggregations": true } }, + { + "role": "modeller", + "permission": { + "columns": [ + "obj_id", + "last_change_admin", + "zone_id", + "mgm_id", + "obj_name", + "obj_comment", + "obj_uid", + "obj_typ_id", + "obj_location", + "obj_member_names", + "obj_member_refs", + "initial_config", + "obj_sw", + "obj_ip", + "obj_ip_end", + "obj_nat", + "nattyp_id", + "obj_nat_ip", + "obj_nat_ip_end", + "obj_nat_install", + "obj_color_id", + "obj_sys_name", + "obj_sys_location", + "obj_sys_contact", + "obj_sys_desc", + "obj_sys_readcom", + "obj_sys_writecom", + "active", + "obj_create", + "obj_last_seen" + ], + "filter": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -9019,6 +9097,21 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "objgrp_id", + "objgrp_member_id", + "import_created", + "import_last_seen", + "active", + "negated" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -9126,6 +9219,21 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "objgrp_flat_id", + "objgrp_flat_member_id", + "active", + "import_created", + "import_last_seen", + "negated" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -12822,6 +12930,75 @@ "allow_aggregations": true } }, + { + "role": "modeller", + "permission": { + "columns": [ + "parent_rule_id", + "rule_create", + "rule_id", + "rule_last_seen", + "xlate_rule", + "access_rule", + "active", + "nat_rule", + "rule_disabled", + "rule_dst_neg", + "rule_implied", + "rule_src_neg", + "rule_svc_neg", + "rule_installon", + "rule_name", + "rule_ruleid", + "rule_time", + "action_id", + "dev_id", + "last_change_admin", + "mgm_id", + "rule_from_zone", + "rule_num", + "rule_to_zone", + "track_id", + "rule_custom_fields", + "rule_num_numeric", + "parent_rule_type", + "rule_action", + "rule_comment", + "rule_dst", + "rule_dst_refs", + "rule_head_text", + "rule_src", + "rule_src_refs", + "rule_svc", + "rule_svc_refs", + "rule_track", + "rule_uid" + ], + "computed_fields": [ + "rule_relevant_for_tenant" + ], + "filter": { + "_and": [ + { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + }, + { + "dev_id": { + "_in": "x-hasura-visible-devices" + } + }, + { + "rule_relevant_for_tenant": { + "_eq": "true" + } + } + ] + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -13120,6 +13297,48 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "obj_id", + "rf_create", + "rf_last_seen", + "rule_from_id", + "rule_id", + "user_id", + "active", + "negated" + ], + "computed_fields": [ + "rule_from_relevant_for_tenant" + ], + "filter": { + "_and": [ + { + "rule": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + } + }, + { + "rule": { + "dev_id": { + "_in": "x-hasura-visible-devices" + } + } + }, + { + "rule_from_relevant_for_tenant": { + "_eq": "true" + } + } + ] + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -13425,6 +13644,36 @@ "allow_aggregations": true } }, + { + "role": "modeller", + "permission": { + "columns": [ + "rule_metadata_id", + "dev_id", + "rule_uid", + "rule_created", + "rule_last_modified", + "rule_first_hit", + "rule_last_hit", + "rule_hit_counter", + "rule_last_certified", + "rule_last_certifier", + "rule_last_certifier_dn", + "rule_owner", + "rule_owner_dn", + "rule_to_be_removed", + "last_change_admin", + "rule_decert_date", + "rule_recertification_comment" + ], + "filter": { + "dev_id": { + "_in": "x-hasura-visible-devices" + } + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -13785,6 +14034,21 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "rule_id", + "svc_id", + "active", + "rs_create", + "rs_last_seen", + "negated" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -14053,6 +14317,48 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "active", + "negated", + "obj_id", + "rt_create", + "rt_last_seen", + "rule_id", + "rule_to_id", + "user_id" + ], + "computed_fields": [ + "rule_to_relevant_for_tenant" + ], + "filter": { + "_and": [ + { + "rule": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + } + }, + { + "rule": { + "dev_id": { + "_in": "x-hasura-visible-devices" + } + } + }, + { + "rule_to_relevant_for_tenant": { + "_eq": "true" + } + } + ] + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -14598,6 +14904,52 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "svc_id", + "svc_uid", + "svc_name", + "svc_typ_id", + "mgm_id", + "svc_comment", + "svc_prod_specific", + "svc_member_names", + "svc_member_refs", + "svc_color_id", + "ip_proto_id", + "svc_port", + "svc_port_end", + "initial_config", + "srv_keeponinstall", + "svc_rpcnr", + "svc_code", + "svc_match", + "svc_source_port", + "svc_source_port_end", + "svc_tcp_res", + "svc_accept_rep", + "svc_accept_rep_any", + "svc_mfa", + "svc_timeout_std", + "svc_timeout", + "svc_sync", + "svc_sync_delay", + "svc_sync_delay_start", + "active", + "last_change_admin", + "svc_create", + "svc_last_seen" + ], + "filter": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -15721,6 +16073,17 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "obj_typ_id", + "obj_typ_name", + "obj_typ_comment" + ], + "filter": {} + } + }, { "role": "recertifier", "permission": { @@ -15820,6 +16183,18 @@ "allow_aggregations": true } }, + { + "role": "modeller", + "permission": { + "columns": [ + "svc_typ_id", + "svc_typ_name", + "svc_typ_comment" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -16085,6 +16460,17 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "usr_typ_name", + "usr_typ_id" + ], + "filter": {} + }, + "comment": "" + }, { "role": "recertifier", "permission": { @@ -16179,6 +16565,21 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "svcgrp_id", + "svcgrp_member_id", + "import_created", + "import_last_seen", + "active", + "negated" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -16286,6 +16687,21 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "svcgrp_flat_id", + "svcgrp_flat_member_id", + "import_created", + "import_last_seen", + "active", + "negated" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -18240,6 +18656,20 @@ "allow_aggregations": true } }, + { + "role": "modeller", + "permission": { + "columns": [ + "usergrp_id", + "usergrp_member_id", + "import_created", + "import_last_seen", + "active" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "planner", "permission": { @@ -18384,6 +18814,20 @@ "filter": {} } }, + { + "role": "modeller", + "permission": { + "columns": [ + "active", + "usergrp_flat_id", + "usergrp_flat_member_id", + "import_created", + "import_last_seen" + ], + "filter": {}, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -18728,6 +19172,41 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "user_id", + "usr_typ_id", + "user_color_id", + "mgm_id", + "user_name", + "active", + "user_member_names", + "user_member_refs", + "user_authmethod", + "user_valid_from", + "user_valid_until", + "src_restrict", + "dst_restrict", + "time_restrict", + "user_create", + "user_last_seen", + "user_comment", + "user_uid", + "user_firstname", + "user_lastname", + "last_change_admin", + "tenant_id" + ], + "filter": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { @@ -19292,6 +19771,25 @@ }, "comment": "" }, + { + "role": "modeller", + "permission": { + "columns": [ + "zone_id", + "zone_create", + "zone_last_seen", + "mgm_id", + "zone_name", + "active" + ], + "filter": { + "mgm_id": { + "_in": "x-hasura-visible-managements" + } + }, + "allow_aggregations": true + } + }, { "role": "recertifier", "permission": { diff --git a/roles/database/files/sql/idempotent/fworch-api-funcs.sql b/roles/database/files/sql/idempotent/fworch-api-funcs.sql index b04213500..84ff30a33 100644 --- a/roles/database/files/sql/idempotent/fworch-api-funcs.sql +++ b/roles/database/files/sql/idempotent/fworch-api-funcs.sql @@ -581,3 +581,26 @@ AS $function$ END IF; END; $function$ + +CREATE OR REPLACE FUNCTION get_rules_for_owner(device_row device, ownerid integer) +RETURNS SETOF rule AS $$ + BEGIN + RETURN QUERY + SELECT r.* FROM rule r + LEFT JOIN rule_from rf ON (r.rule_id=rf.rule_id) + LEFT JOIN objgrp_flat rf_of ON (rf.obj_id=rf_of.objgrp_flat_id) + LEFT JOIN object rf_o ON (rf_of.objgrp_flat_member_id=rf_o.obj_id) + LEFT JOIN owner_network ON + (ip_ranges_overlap(rf_o.obj_ip, rf_o.obj_ip_end, ip, ip_end, rf.negated != r.rule_src_neg)) + WHERE r.dev_id = device_row.dev_id AND owner_id = ownerid AND rule_head_text IS NULL + UNION + SELECT r.* FROM rule r + LEFT JOIN rule_to rt ON (r.rule_id=rt.rule_id) + LEFT JOIN objgrp_flat rt_of ON (rt.obj_id=rt_of.objgrp_flat_id) + LEFT JOIN object rt_o ON (rt_of.objgrp_flat_member_id=rt_o.obj_id) + LEFT JOIN owner_network ON + (ip_ranges_overlap(rt_o.obj_ip, rt_o.obj_ip_end, ip, ip_end, rt.negated != r.rule_dst_neg)) + WHERE r.dev_id = device_row.dev_id AND owner_id = ownerid AND rule_head_text IS NULL + ORDER BY rule_name; + END; +$$ LANGUAGE 'plpgsql' STABLE; diff --git a/roles/database/files/sql/idempotent/fworch-texts.sql b/roles/database/files/sql/idempotent/fworch-texts.sql index 5932835ae..4aa992e0e 100644 --- a/roles/database/files/sql/idempotent/fworch-texts.sql +++ b/roles/database/files/sql/idempotent/fworch-texts.sql @@ -125,6 +125,8 @@ INSERT INTO txt VALUES ('UnusedRules', 'German', 'Unbenutzte-Regel-Rep INSERT INTO txt VALUES ('UnusedRules', 'English', 'Unused Rules Report'); INSERT INTO txt VALUES ('Connections', 'German', 'Verbindungs-Report'); INSERT INTO txt VALUES ('Connections', 'English', 'Connections Report'); +INSERT INTO txt VALUES ('AppRules', 'German', 'App-Regel-Report'); +INSERT INTO txt VALUES ('AppRules', 'English', 'App Rules Report'); INSERT INTO txt VALUES ('mixed', 'German', 'Gemischt'); INSERT INTO txt VALUES ('mixed', 'English', 'Mixed'); INSERT INTO txt VALUES ('exclusive', 'German', 'Exklusiv'); @@ -706,6 +708,8 @@ INSERT INTO txt VALUES ('network', 'German', 'Netzwerk'); INSERT INTO txt VALUES ('network', 'English', 'network'); INSERT INTO txt VALUES ('ip_range', 'German', 'Ip-Bereich'); INSERT INTO txt VALUES ('ip_range', 'English', 'Ip Range'); +INSERT INTO txt VALUES ('more', 'German', 'weitere'); +INSERT INTO txt VALUES ('more', 'English', 'more'); -- schedule INSERT INTO txt VALUES ('schedule', 'German', 'Terminplan'); diff --git a/roles/database/files/upgrade/8.2.4.sql b/roles/database/files/upgrade/8.2.4.sql new file mode 100644 index 000000000..f8351008b --- /dev/null +++ b/roles/database/files/upgrade/8.2.4.sql @@ -0,0 +1,22 @@ +CREATE OR REPLACE FUNCTION get_rules_for_owner(device_row device, ownerid integer) +RETURNS SETOF rule AS $$ + BEGIN + RETURN QUERY + SELECT r.* FROM rule r + LEFT JOIN rule_from rf ON (r.rule_id=rf.rule_id) + LEFT JOIN objgrp_flat rf_of ON (rf.obj_id=rf_of.objgrp_flat_id) + LEFT JOIN object rf_o ON (rf_of.objgrp_flat_member_id=rf_o.obj_id) + LEFT JOIN owner_network ON + (ip_ranges_overlap(rf_o.obj_ip, rf_o.obj_ip_end, ip, ip_end, rf.negated != r.rule_src_neg)) + WHERE r.dev_id = device_row.dev_id AND owner_id = ownerid AND rule_head_text IS NULL + UNION + SELECT r.* FROM rule r + LEFT JOIN rule_to rt ON (r.rule_id=rt.rule_id) + LEFT JOIN objgrp_flat rt_of ON (rt.obj_id=rt_of.objgrp_flat_id) + LEFT JOIN object rt_o ON (rt_of.objgrp_flat_member_id=rt_o.obj_id) + LEFT JOIN owner_network ON + (ip_ranges_overlap(rt_o.obj_ip, rt_o.obj_ip_end, ip, ip_end, rt.negated != r.rule_dst_neg)) + WHERE r.dev_id = device_row.dev_id AND owner_id = ownerid AND rule_head_text IS NULL + ORDER BY rule_name; + END; +$$ LANGUAGE 'plpgsql' STABLE; diff --git a/roles/lib/files/FWO.Api.Client/Data/ComplianceNetworkZone.cs b/roles/lib/files/FWO.Api.Client/Data/ComplianceNetworkZone.cs index fe825434d..a745456d5 100644 --- a/roles/lib/files/FWO.Api.Client/Data/ComplianceNetworkZone.cs +++ b/roles/lib/files/FWO.Api.Client/Data/ComplianceNetworkZone.cs @@ -18,21 +18,21 @@ public class ComplianceNetworkZone public string Description { get; set; } = ""; [JsonProperty("ip_ranges", ItemConverterType = typeof(IpAddressRangeJsonTypeConverter)), JsonPropertyName("ip_ranges")] - public IPAddressRange[] IPRanges { get; set; } = new IPAddressRange[0]; + public IPAddressRange[] IPRanges { get; set; } = []; [JsonProperty("super_network_zone"), JsonPropertyName("super_network_zone")] public ComplianceNetworkZone? Superzone { get; set; } = null; [JsonProperty("sub_network_zones"), JsonPropertyName("sub_network_zones")] - public ComplianceNetworkZone[] Subzones { get; set; } = new ComplianceNetworkZone[0]; + public ComplianceNetworkZone[] Subzones { get; set; } = []; [JsonProperty("network_zone_communication_sources", ItemConverterType = typeof(WrapperConverter), - ItemConverterParameters = new object[] { "from_network_zone" }), JsonPropertyName("network_zone_communication_sources")] - public ComplianceNetworkZone[] AllowedCommunicationSources { get; set; } = new ComplianceNetworkZone[0]; + ItemConverterParameters = ["from_network_zone"]), JsonPropertyName("network_zone_communication_sources")] + public ComplianceNetworkZone[] AllowedCommunicationSources { get; set; } = []; [JsonProperty("network_zone_communication_destinations", ItemConverterType = typeof(WrapperConverter), - ItemConverterParameters = new object[] { "to_network_zone" }), JsonPropertyName("network_zone_communication_destinations")] - public ComplianceNetworkZone[] AllowedCommunicationDestinations { get; set; } = new ComplianceNetworkZone[0]; + ItemConverterParameters = ["to_network_zone"]), JsonPropertyName("network_zone_communication_destinations")] + public ComplianceNetworkZone[] AllowedCommunicationDestinations { get; set; } = []; public bool CommunicationAllowedFrom(ComplianceNetworkZone from) @@ -69,12 +69,12 @@ public bool OverlapExists(List ipRanges, ListFirst IP range /// Second IP range /// True, if IP ranges overlap, false otherwise. - private bool OverlapExists(IPAddressRange a, IPAddressRange b) + public static bool OverlapExists(IPAddressRange a, IPAddressRange b) { return IpToUint(a.Begin) <= IpToUint(b.End) && IpToUint(b.Begin) <= IpToUint(a.End); } - private void RemoveOverlap(List ranges, IPAddressRange toRemove) + private static void RemoveOverlap(List ranges, IPAddressRange toRemove) { for (int i = 0; i < ranges.Count; i++) { @@ -110,7 +110,7 @@ private void RemoveOverlap(List ranges, IPAddressRange toRemove) } } - private uint IpToUint(IPAddress ipAddress) + private static uint IpToUint(IPAddress ipAddress) { byte[] bytes = ipAddress.GetAddressBytes(); @@ -123,7 +123,7 @@ private uint IpToUint(IPAddress ipAddress) return BitConverter.ToUInt32(bytes, 0); } - private IPAddress UintToIp(uint ipAddress) + private static IPAddress UintToIp(uint ipAddress) { byte[] bytes = BitConverter.GetBytes(ipAddress); diff --git a/roles/lib/files/FWO.Api.Client/Data/DeviceFilter.cs b/roles/lib/files/FWO.Api.Client/Data/DeviceFilter.cs index 1d2412e12..2c390ed75 100644 --- a/roles/lib/files/FWO.Api.Client/Data/DeviceFilter.cs +++ b/roles/lib/files/FWO.Api.Client/Data/DeviceFilter.cs @@ -14,7 +14,7 @@ public class ManagementSelect public string? Name { get; set; } [JsonProperty("devices"), JsonPropertyName("devices")] - public List Devices { get; set; } = new List(); + public List Devices { get; set; } = []; public ElementReference? UiReference { get; set; } @@ -23,7 +23,7 @@ public class ManagementSelect public bool Shared { get; set; } = true; public ManagementSelect Clone() { - List ClonedDevices = new(); + List ClonedDevices = []; foreach(var dev in Devices) { ClonedDevices.Add(new DeviceSelect(dev)); @@ -68,13 +68,13 @@ public DeviceSelect(DeviceSelect dev) public class DeviceFilter { [JsonProperty("management"), JsonPropertyName("management")] - public List Managements { get; set; } = new List(); + public List Managements { get; set; } = []; [JsonProperty("visibleManagements"), JsonPropertyName("visibleManagements")] - public List VisibleManagements { get; set; } = new List(); + public List VisibleManagements { get; set; } = []; [JsonProperty("visibleGateways"), JsonPropertyName("visibleGateways")] - public List VisibleGateways { get; set; } = new List(); + public List VisibleGateways { get; set; } = []; public DeviceFilter() {} @@ -90,7 +90,7 @@ public DeviceFilter(List mgmSelect) } public DeviceFilter(List devIds) { - ManagementSelect dummyManagement = new ManagementSelect(); + ManagementSelect dummyManagement = new(); foreach(int id in devIds) { dummyManagement.Devices.Add(new DeviceSelect(){Id = id}); @@ -99,7 +99,7 @@ public DeviceFilter(List devIds) } public DeviceFilter(int[] devIds) { - ManagementSelect dummyManagement = new ManagementSelect(); + ManagementSelect dummyManagement = new(); foreach(int id in devIds) { dummyManagement.Devices.Add(new DeviceSelect(){Id = id}); @@ -109,7 +109,7 @@ public DeviceFilter(int[] devIds) public DeviceFilter Clone() { - List ClonedManagements = new(); + List ClonedManagements = []; foreach(var mgt in Managements) { ClonedManagements.Add(mgt.Clone()); @@ -167,7 +167,7 @@ public static bool IsSelectedManagement(ManagementSelect management) public List getSelectedManagements() { - List selectedMgmts = new List(); + List selectedMgmts = []; foreach (ManagementSelect mgmt in Managements) { if (IsSelectedManagement(mgmt)) @@ -180,7 +180,7 @@ public List getSelectedManagements() public string listAllSelectedDevices() { - List devs = new List(); + List devs = []; foreach (ManagementSelect mgmt in Managements) foreach (DeviceSelect dev in mgmt.Devices) if (dev.Selected) @@ -190,7 +190,7 @@ public string listAllSelectedDevices() public static List ExtractAllDevIds(Management[] managements) { - List devs = new List(); + List devs = []; foreach (Management mgmt in managements) foreach (Device dev in mgmt.Devices) devs.Add(dev.Id); @@ -199,7 +199,7 @@ public static List ExtractAllDevIds(Management[] managements) public static List ExtractSelectedDevIds(Management[] managements) { - List selectedDevs = new List(); + List selectedDevs = []; foreach (Management mgmt in managements) foreach (Device dev in mgmt.Devices) if (dev.Selected) @@ -265,7 +265,7 @@ public int NumberMgmtDev() public override string ToString() { - StringBuilder result = new StringBuilder(); + StringBuilder result = new(); foreach (ManagementSelect management in Managements) { result.Append($"{management.Name} [{string.Join(", ", management.Devices.ConvertAll(device => device.Name))}]; "); diff --git a/roles/lib/files/FWO.Api.Client/Data/DisplayBase.cs b/roles/lib/files/FWO.Api.Client/Data/DisplayBase.cs index 0c625782e..02b127982 100644 --- a/roles/lib/files/FWO.Api.Client/Data/DisplayBase.cs +++ b/roles/lib/files/FWO.Api.Client/Data/DisplayBase.cs @@ -134,7 +134,7 @@ public static string DisplayIp(string ip1, string ip2, string nwObjType, bool in public static string GetNetmask(string ip) { - int pos = ip.LastIndexOf("/"); + int pos = ip.LastIndexOf('/'); if (pos > -1 && ip.Length > pos + 1) { return ip[(pos + 1)..]; @@ -142,9 +142,9 @@ public static string GetNetmask(string ip) return ""; } - private static string StripOffNetmask(string ip) + public static string StripOffNetmask(string ip) { - int pos = ip.LastIndexOf("/"); + int pos = ip.LastIndexOf('/'); if (pos > -1 && ip.Length > pos + 1) { return ip[..pos]; diff --git a/roles/lib/files/FWO.Api.Client/Data/Rule.cs b/roles/lib/files/FWO.Api.Client/Data/Rule.cs index 2e15c8ab1..092c7ff23 100644 --- a/roles/lib/files/FWO.Api.Client/Data/Rule.cs +++ b/roles/lib/files/FWO.Api.Client/Data/Rule.cs @@ -27,7 +27,7 @@ public class Rule public bool Disabled { get; set; } [JsonProperty("rule_services"), JsonPropertyName("rule_services")] - public ServiceWrapper[] Services { get; set; } = new ServiceWrapper[]{}; + public ServiceWrapper[] Services { get; set; } = []; [JsonProperty("rule_svc_neg"), JsonPropertyName("rule_svc_neg")] public bool ServiceNegated { get; set; } @@ -42,10 +42,10 @@ public class Rule public string Source { get; set; } = ""; [JsonProperty("src_zone"), JsonPropertyName("src_zone")] - public NetworkZone? SourceZone { get; set; } = new NetworkZone(); + public NetworkZone? SourceZone { get; set; } = new (); [JsonProperty("rule_froms"), JsonPropertyName("rule_froms")] - public NetworkLocation[] Froms { get; set; } = new NetworkLocation[]{}; + public NetworkLocation[] Froms { get; set; } = []; [JsonProperty("rule_dst_neg"), JsonPropertyName("rule_dst_neg")] public bool DestinationNegated { get; set; } @@ -54,10 +54,10 @@ public class Rule public string Destination { get; set; } = ""; [JsonProperty("dst_zone"), JsonPropertyName("dst_zone")] - public NetworkZone? DestinationZone { get; set; } = new NetworkZone(); + public NetworkZone? DestinationZone { get; set; } = new (); [JsonProperty("rule_tos"), JsonPropertyName("rule_tos")] - public NetworkLocation[] Tos { get; set; } = new NetworkLocation[]{}; + public NetworkLocation[] Tos { get; set; } = []; [JsonProperty("rule_action"), JsonPropertyName("rule_action")] public string Action { get; set; } = ""; @@ -69,10 +69,10 @@ public class Rule public string? SectionHeader { get; set; } = ""; [JsonProperty("rule_metadatum"), JsonPropertyName("rule_metadatum")] - public RuleMetadata Metadata {get; set;} = new RuleMetadata(); + public RuleMetadata Metadata {get; set;} = new (); [JsonProperty("translate"), JsonPropertyName("translate")] - public NatData NatData {get; set;} = new NatData(); + public NatData NatData {get; set;} = new (); [JsonProperty("owner_name"), JsonPropertyName("owner_name")] public string OwnerName {get; set;} = ""; @@ -93,6 +93,7 @@ public class Rule public int DisplayOrderNumber { get; set; } public bool Certified { get; set; } public string DeviceName { get; set; } = ""; + public NetworkLocation[] DisregardedFroms { get; set; } = []; + public NetworkLocation[] DisregardedTos { get; set; } = []; } - } diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeConnector.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeConnector.cs index a21f7682e..504f166e4 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeConnector.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeConnector.cs @@ -20,18 +20,18 @@ public override void Extract(ref DynGraphqlQuery query, ReportType? reportType) switch (Connector.Kind) { case TokenKind.And: // and terms should be enclosed in [] - query.ruleWhereStatement += "_and: [{"; - query.nwObjWhereStatement += "_and: [{"; - query.svcObjWhereStatement += "_and: [{"; - query.userObjWhereStatement += "_and: [{"; - query.connectionWhereStatement += "_and: [{"; + query.RuleWhereStatement += "_and: [{"; + query.NwObjWhereStatement += "_and: [{"; + query.SvcObjWhereStatement += "_and: [{"; + query.UserObjWhereStatement += "_and: [{"; + query.ConnectionWhereStatement += "_and: [{"; break; case TokenKind.Or: // or terms need to be enclosed in [] - query.ruleWhereStatement += "_or: [{"; - query.nwObjWhereStatement += "_or: [{"; - query.svcObjWhereStatement += "_or: [{"; - query.userObjWhereStatement += "_or: [{"; - query.connectionWhereStatement += "_or: [{"; + query.RuleWhereStatement += "_or: [{"; + query.NwObjWhereStatement += "_or: [{"; + query.SvcObjWhereStatement += "_or: [{"; + query.UserObjWhereStatement += "_or: [{"; + query.ConnectionWhereStatement += "_or: [{"; break; default: throw new SemanticException($"### Compiler Error: Found unexpected and unsupported connector token (prefix): \"{Connector}\". ###", Connector.Position); @@ -43,11 +43,11 @@ public override void Extract(ref DynGraphqlQuery query, ReportType? reportType) { case TokenKind.And: case TokenKind.Or: - query.ruleWhereStatement += "}, {"; - query.nwObjWhereStatement += "}, {"; - query.svcObjWhereStatement += "}, {"; - query.userObjWhereStatement += "}, {"; - query.connectionWhereStatement += "}, {"; + query.RuleWhereStatement += "}, {"; + query.NwObjWhereStatement += "}, {"; + query.SvcObjWhereStatement += "}, {"; + query.UserObjWhereStatement += "}, {"; + query.ConnectionWhereStatement += "}, {"; break; default: throw new SemanticException($"### Compiler Error: Found unexpected and unsupported connector token (operator): \"{Connector}\". ###", Connector.Position); @@ -59,11 +59,11 @@ public override void Extract(ref DynGraphqlQuery query, ReportType? reportType) { case TokenKind.And: case TokenKind.Or: - query.ruleWhereStatement += "}] "; - query.nwObjWhereStatement += "}] "; - query.svcObjWhereStatement += "}] "; - query.userObjWhereStatement += "}] "; - query.connectionWhereStatement += "}] "; + query.RuleWhereStatement += "}] "; + query.NwObjWhereStatement += "}] "; + query.SvcObjWhereStatement += "}] "; + query.UserObjWhereStatement += "}] "; + query.ConnectionWhereStatement += "}] "; break; default: throw new SemanticException($"### Compiler Error: Found unexpected and unsupported connector token (suffix): \"{Connector}\" ###", Connector.Position); diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterBool.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterBool.cs index 19581c34b..c107df3fc 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterBool.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterBool.cs @@ -49,14 +49,14 @@ public override void Extract(ref DynGraphqlQuery query, ReportType? reportType) private DynGraphqlQuery ExtractRemoveFilter(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "remove", Operator.Kind, semanticValue); - query.ruleWhereStatement += $"rule_metadatum: {{rule_to_be_removed: {{ {ExtractOperator()}: ${queryVarName} }}}}"; + query.RuleWhereStatement += $"rule_metadatum: {{rule_to_be_removed: {{ {ExtractOperator()}: ${queryVarName} }}}}"; return query; } private DynGraphqlQuery ExtractDisabledQuery(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "disabled", Operator.Kind, semanticValue); - query.ruleWhereStatement += $"rule_disabled: {{ {ExtractOperator()}: ${queryVarName} }}"; + query.RuleWhereStatement += $"rule_disabled: {{ {ExtractOperator()}: ${queryVarName} }}"; return query; } } diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterDateTimeRange.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterDateTimeRange.cs index 0de31b27e..19d4b5234 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterDateTimeRange.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterDateTimeRange.cs @@ -32,7 +32,7 @@ private DynGraphqlQuery ExtractLastHitFilter(DynGraphqlQuery query, ReportType r { if (Operator.Kind==TokenKind.LSS) // only show rules which have a hit before a certain date (including no hit rules) { - query.ruleWhereStatement += $@" + query.RuleWhereStatement += $@" _or: [ {{ rule: {{ rule_metadatum: {{ rule_last_hit: {{{ExtractOperator()}: ${queryVarName} }} }} }} }} {{ rule: {{ rule_metadatum: {{ rule_last_hit: {{_is_null: true }} }} }} }} @@ -40,14 +40,14 @@ private DynGraphqlQuery ExtractLastHitFilter(DynGraphqlQuery query, ReportType r } else // only show rules which have a hit after a certain date (leaving out no hit rules) { - query.ruleWhereStatement += $"rule: {{ rule_metadatum:{{ rule_last_hit: {{{ExtractOperator()}: ${queryVarName} }} }} }}"; + query.RuleWhereStatement += $"rule: {{ rule_metadatum:{{ rule_last_hit: {{{ExtractOperator()}: ${queryVarName} }} }} }}"; } } else { if (Operator.Kind==TokenKind.LSS) // only show rules which have a hit before a certain date (including no hit rules) { - query.ruleWhereStatement += $@" + query.RuleWhereStatement += $@" _or: [ {{ rule_metadatum: {{ rule_last_hit: {{{ExtractOperator()}: ${queryVarName} }} }} }} {{ rule_metadatum: {{ rule_last_hit: {{_is_null: true }} }} }} @@ -55,7 +55,7 @@ private DynGraphqlQuery ExtractLastHitFilter(DynGraphqlQuery query, ReportType r } else // only show rules which have a hit after a certain date (leaving out no hit rules) { - query.ruleWhereStatement += $"rule_metadatum: {{ rule_last_hit: {{{ExtractOperator()}: ${queryVarName} }} }}"; + query.RuleWhereStatement += $"rule_metadatum: {{ rule_last_hit: {{{ExtractOperator()}: ${queryVarName} }} }}"; } } return query; diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterInt.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterInt.cs index efa418c73..c75dd9e36 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterInt.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterInt.cs @@ -52,9 +52,9 @@ private DynGraphqlQuery ExtractRecertDisplayFilter(DynGraphqlQuery query) private DynGraphqlQuery ExtractDestinationPortFilter(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "dport", Operator.Kind, semanticValue); - query.ruleWhereStatement += "rule_services: { service: { svcgrp_flats: { serviceBySvcgrpFlatMemberId: { svc_port: {_lte" + + query.RuleWhereStatement += "rule_services: { service: { svcgrp_flats: { serviceBySvcgrpFlatMemberId: { svc_port: {_lte" + ": $" + queryVarName + "}, svc_port_end: {_gte: $" + queryVarName + " } } } } }"; - query.connectionWhereStatement += $"_or: [ {{ service_connections: {{service: {{ port: {{ _lte: ${queryVarName} }}, port_end: {{ _gte: ${queryVarName} }} }} }} }}, " + + query.ConnectionWhereStatement += $"_or: [ {{ service_connections: {{service: {{ port: {{ _lte: ${queryVarName} }}, port_end: {{ _gte: ${queryVarName} }} }} }} }}, " + $"{{ service_group_connections: {{service_group: {{ service_service_groups: {{ service: {{ port: {{ _lte: ${queryVarName} }}, port_end: {{ _gte: ${queryVarName} }} }} }} }} }} }} ]"; return query; } @@ -62,14 +62,14 @@ private DynGraphqlQuery ExtractDestinationPortFilter(DynGraphqlQuery query) private DynGraphqlQuery ExtractOwnerFilter(DynGraphqlQuery query) { string QueryVarName = AddVariable(query, "owner", Operator.Kind, Value.Text); - query.ruleWhereStatement += $"owner: {{ {ExtractOperator()}: ${QueryVarName} }}"; + query.RuleWhereStatement += $"owner: {{ {ExtractOperator()}: ${QueryVarName} }}"; return query; } private DynGraphqlQuery ExtractUnusedFilter(DynGraphqlQuery query) { string QueryVarName = AddVariable(query, "cut", Operator.Kind, DateTime.Now.AddDays(-semanticValue)); - query.ruleWhereStatement += $@"rule_metadatum: {{_or: [ + query.RuleWhereStatement += $@"rule_metadatum: {{_or: [ {{_and: [{{rule_last_hit: {{_is_null: false}} }}, {{rule_last_hit: {{_lte: ${QueryVarName} }} }} ] }}, {{ rule_last_hit: {{_is_null: true}} }} ]}}"; diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterNetwork.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterNetwork.cs index 014f849ec..731e11f7c 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterNetwork.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterNetwork.cs @@ -32,12 +32,14 @@ public override void Extract(ref DynGraphqlQuery query, ReportType? reportType) private DynGraphqlQuery ExtractDestinationFilter(DynGraphqlQuery query) { if (IsCidr(Value.Text)) // filtering for ip addresses + { query = ExtractIpFilter(query, location: "dst", locationTable: "rule_tos"); + } else // string search against dst obj name { string QueryVarName = AddVariable(query, "dst", Operator.Kind, Value.Text); - query.ruleWhereStatement += $"rule_tos: {{ object: {{ objgrp_flats: {{ objectByObjgrpFlatMemberId: {{ obj_name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }} }}"; - query.connectionWhereStatement += $"_or: [ {{ nwobject_connections: {{connection_field: {{ _eq: 2 }}, owner_network: {{name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }}, " + + query.RuleWhereStatement += $"rule_tos: {{ object: {{ objgrp_flats: {{ objectByObjgrpFlatMemberId: {{ obj_name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }} }}"; + query.ConnectionWhereStatement += $"_or: [ {{ nwobject_connections: {{connection_field: {{ _eq: 2 }}, owner_network: {{name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }}, " + $"{{ nwgroup_connections: {{connection_field: {{ _eq: 2 }}, nwgroup: {{ name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }} ]"; } return query; @@ -47,12 +49,14 @@ private DynGraphqlQuery ExtractDestinationFilter(DynGraphqlQuery query) private DynGraphqlQuery ExtractSourceFilter(DynGraphqlQuery query) { if (IsCidr(Value.Text)) // filtering for ip addresses + { query = ExtractIpFilter(query, location: "src", locationTable: "rule_froms"); + } else // string search against src obj name { string QueryVarName = AddVariable(query, "src", Operator.Kind, Value.Text); - query.ruleWhereStatement += $"rule_froms: {{ object: {{ objgrp_flats: {{ objectByObjgrpFlatMemberId: {{ obj_name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }} }}"; - query.connectionWhereStatement += $"_or: [ {{ nwobject_connections: {{connection_field: {{ _eq: 1 }}, owner_network: {{name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }}, " + + query.RuleWhereStatement += $"rule_froms: {{ object: {{ objgrp_flats: {{ objectByObjgrpFlatMemberId: {{ obj_name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }} }}"; + query.ConnectionWhereStatement += $"_or: [ {{ nwobject_connections: {{connection_field: {{ _eq: 1 }}, owner_network: {{name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }}, " + $"{{ nwgroup_connections: {{connection_field: {{ _eq: 1 }}, nwgroup: {{ name: {{ {ExtractOperator()}: ${QueryVarName} }} }} }} }} ]"; } return query; @@ -60,19 +64,18 @@ private DynGraphqlQuery ExtractSourceFilter(DynGraphqlQuery query) private static string SanitizeIp(string cidr_str) { - IPAddress? ip; - if (IPAddress.TryParse(cidr_str, out ip)) + if (IPAddress.TryParse(cidr_str, out IPAddress? ip)) { if (ip != null) { if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { cidr_str = ip.ToString(); - if (cidr_str.IndexOf("/") < 0) // a single ip without mask + if (cidr_str.IndexOf('/') < 0) // a single ip without mask { cidr_str += "/128"; } - if (cidr_str.IndexOf("/") == cidr_str.Length - 1) // wrong format (/ at the end, fixing this by adding 128 mask) + if (cidr_str.IndexOf('/') == cidr_str.Length - 1) // wrong format (/ at the end, fixing this by adding 128 mask) { cidr_str += "128"; } @@ -80,19 +83,19 @@ private static string SanitizeIp(string cidr_str) else if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { cidr_str = ip.ToString(); - if (cidr_str.IndexOf("/") < 0) // a single ip without mask + if (cidr_str.IndexOf('/') < 0) // a single ip without mask { cidr_str += "/32"; } - if (cidr_str.IndexOf("/") == cidr_str.Length - 1) // wrong format (/ at the end, fixing this by adding 32 mask) + if (cidr_str.IndexOf('/') == cidr_str.Length - 1) // wrong format (/ at the end, fixing this by adding 32 mask) { cidr_str += "32"; } } } - else + else { - Log.WriteWarning("SanitizeIP", $"unexpected IP address family (neither v4 nor v6) found"); + Log.WriteWarning("SanitizeIP", $"unexpected IP address family (neither v4 nor v6) found"); } } return cidr_str; @@ -100,7 +103,7 @@ private static string SanitizeIp(string cidr_str) private static bool IsCidr(string cidr) { - return IPAddressRange.TryParse(cidr, out IPAddressRange range); + return IPAddressRange.TryParse(cidr, out _); } private DynGraphqlQuery ExtractIpFilter(DynGraphqlQuery query, string location, string locationTable) @@ -126,7 +129,7 @@ private DynGraphqlQuery ExtractIpFilter(DynGraphqlQuery query, string location, string ipFilterString = $@" obj_ip_end: {{ _gte: ${QueryVarNameFirst1} }} obj_ip: {{ _lte: ${QueryVarNameLast2} }}"; - query.ruleWhereStatement += + query.RuleWhereStatement += $@" {locationTable}: {{ object: {{ objgrp_flats: @@ -135,7 +138,7 @@ private DynGraphqlQuery ExtractIpFilter(DynGraphqlQuery query, string location, }} }} }}"; - query.nwObjWhereStatement += + query.NwObjWhereStatement += $@" {locationTable}: {{ object: {{ objgrp_flats: @@ -146,7 +149,7 @@ private DynGraphqlQuery ExtractIpFilter(DynGraphqlQuery query, string location, }}"; ipFilterString = $@" ip_end: {{ _gte: ${QueryVarNameFirst1} }} ip: {{ _lte: ${QueryVarNameLast2} }}"; int conField = location == "src" ? 1 : 2; - query.connectionWhereStatement += $"nwobject_connections: {{connection_field: {{ _eq: {conField} }}, owner_network: {{ {ipFilterString} }} }}"; + query.ConnectionWhereStatement += $"nwobject_connections: {{connection_field: {{ _eq: {conField} }}, owner_network: {{ {ipFilterString} }} }}"; return query; } diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterReportType.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterReportType.cs index b86611f5b..2cc1ddb61 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterReportType.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterReportType.cs @@ -46,7 +46,7 @@ private DynGraphqlQuery ExtractReportTypeFilter(DynGraphqlQuery query) if (query.ReportType == ReportType.Statistics) { - query.ruleWhereStatement += + query.RuleWhereStatement += @$"rule_head_text: {{_is_null: true}}"; } diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterString.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterString.cs index cf9ba9041..71cd38368 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterString.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeFilterString.cs @@ -54,7 +54,7 @@ private DynGraphqlQuery ExtractFullTextFilter(DynGraphqlQuery query) { ruleSearchParts.Add($"{{{field}: {{{queryOperator}: ${queryVarName} }} }} "); } - query.ruleWhereStatement += $"_or: [ {string.Join(", ", ruleSearchParts)} ]"; + query.RuleWhereStatement += $"_or: [ {string.Join(", ", ruleSearchParts)} ]"; List connFieldNames = new () { "name", "reason" /*, "creator" */ }; List nwobjFieldNames = new () { "name" /*, "creator" */ }; @@ -82,14 +82,14 @@ private DynGraphqlQuery ExtractFullTextFilter(DynGraphqlQuery query) { connSearchParts.Add($"{{ service_group_connections: {{service_group: {{{field}: {{{queryOperator}: ${queryVarName} }} }} }} }} "); } - query.connectionWhereStatement += $"_or: [ {string.Join(", ", connSearchParts)} ]"; + query.ConnectionWhereStatement += $"_or: [ {string.Join(", ", connSearchParts)} ]"; return query; } private DynGraphqlQuery ExtractGatewayFilter(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "gwName", Operator.Kind, semanticValue); - query.ruleWhereStatement += $"device: {{dev_name : {{{ExtractOperator()}: ${queryVarName} }} }}"; + query.RuleWhereStatement += $"device: {{dev_name : {{{ExtractOperator()}: ${queryVarName} }} }}"; // query.nwObjWhereStatement += $"device: {{dev_name : {{{QueryOperation}: ${QueryVarName} }} }}"; // query.svcObjWhereStatement += $"device: {{dev_name : {{{QueryOperation}: ${QueryVarName} }} }}"; // query.userObjWhereStatement += $"device: {{dev_name : {{{QueryOperation}: ${QueryVarName} }} }}"; @@ -112,18 +112,18 @@ private DynGraphqlQuery ExtractManagementFilter(DynGraphqlQuery query) queryVarName = AddVariable(query, "mgmName", Operator.Kind, semanticValue!); queryFilterValue = "mgm_name"; } - query.ruleWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; - query.nwObjWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; - query.svcObjWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; - query.userObjWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; + query.RuleWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; + query.NwObjWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; + query.SvcObjWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; + query.UserObjWhereStatement += $"management: {{{queryFilterValue} : {{{queryOperation}: ${queryVarName} }} }}"; return query; } private DynGraphqlQuery ExtractProtocolFilter(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "proto", Operator.Kind, semanticValue!); - query.ruleWhereStatement += $"rule_services: {{service: {{stm_ip_proto: {{ip_proto_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }}"; - query.connectionWhereStatement += $"_or: [ {{ service_connections: {{service: {{stm_ip_proto: {{ip_proto_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }} }}, " + + query.RuleWhereStatement += $"rule_services: {{service: {{stm_ip_proto: {{ip_proto_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }}"; + query.ConnectionWhereStatement += $"_or: [ {{ service_connections: {{service: {{stm_ip_proto: {{ip_proto_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }} }}, " + $"{{ service_group_connections: {{service_group: {{ service_service_groups: {{ service: {{ stm_ip_proto: {{ip_proto_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }} }} }} }} ]"; return query; } @@ -131,15 +131,15 @@ private DynGraphqlQuery ExtractProtocolFilter(DynGraphqlQuery query) private DynGraphqlQuery ExtractActionFilter(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "action", Operator.Kind, semanticValue!); - query.ruleWhereStatement += $"rule_action: {{ {ExtractOperator()}: ${queryVarName} }}"; + query.RuleWhereStatement += $"rule_action: {{ {ExtractOperator()}: ${queryVarName} }}"; return query; } private DynGraphqlQuery ExtractServiceFilter(DynGraphqlQuery query) { string queryVarName = AddVariable(query, "svc", Operator.Kind, semanticValue!); - query.ruleWhereStatement += $"rule_services: {{ service: {{ svcgrp_flats: {{ serviceBySvcgrpFlatMemberId: {{ svc_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }} }} "; - query.connectionWhereStatement += $"_or: [ {{ service_connections: {{ service: {{ name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }}, " + + query.RuleWhereStatement += $"rule_services: {{ service: {{ svcgrp_flats: {{ serviceBySvcgrpFlatMemberId: {{ svc_name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }} }} "; + query.ConnectionWhereStatement += $"_or: [ {{ service_connections: {{ service: {{ name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }}, " + $"{{ service_group_connections: {{service_group: {{ _or: [ {{ name: {{ {ExtractOperator()}: ${queryVarName} }} }}, " + $"{{ service_service_groups: {{ service: {{ name: {{ {ExtractOperator()}: ${queryVarName} }} }} }} }} ] }} }} }} ]"; return query; diff --git a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeUnary.cs b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeUnary.cs index e205235da..5490e8242 100644 --- a/roles/lib/files/FWO.Report.Filter/Ast/AstNodeUnary.cs +++ b/roles/lib/files/FWO.Report.Filter/Ast/AstNodeUnary.cs @@ -8,13 +8,13 @@ class AstNodeUnary : AstNode public override void Extract(ref DynGraphqlQuery query, ReportType? reportType) { - query.ruleWhereStatement += Operator.Kind switch + query.RuleWhereStatement += Operator.Kind switch { TokenKind.Not => "_not: {", _ => throw new NotSupportedException($"### Compiler Error: Found unexpected and unsupported unary token \"{Operator}\" ###"), }; Value?.Extract(ref query, reportType); - query.ruleWhereStatement += "}"; + query.RuleWhereStatement += "}"; } } } diff --git a/roles/lib/files/FWO.Report.Filter/Compiler.cs b/roles/lib/files/FWO.Report.Filter/Compiler.cs index c1f1f6157..e4aafb78b 100644 --- a/roles/lib/files/FWO.Report.Filter/Compiler.cs +++ b/roles/lib/files/FWO.Report.Filter/Compiler.cs @@ -9,11 +9,11 @@ public class Compiler { public static AstNode? CompileToAst(string input) { - Scanner scanner = new Scanner(input); + Scanner scanner = new(input); List tokens = scanner.Scan(); if(tokens.Count > 0) { - Parser parser = new Parser(tokens); + Parser parser = new(tokens); return parser.Parse(); } else return null; diff --git a/roles/lib/files/FWO.Report.Filter/DynGraphqlQuery.cs b/roles/lib/files/FWO.Report.Filter/DynGraphqlQuery.cs index 14ceb8a7a..b889fd8a1 100644 --- a/roles/lib/files/FWO.Report.Filter/DynGraphqlQuery.cs +++ b/roles/lib/files/FWO.Report.Filter/DynGraphqlQuery.cs @@ -1,6 +1,5 @@ using FWO.Report.Filter.Ast; using FWO.Api.Client.Queries; -using FWO.GlobalConstants; using FWO.Api.Data; using System.Text.RegularExpressions; using FWO.Logging; @@ -12,311 +11,50 @@ public class DynGraphqlQuery public string RawFilter { get; private set; } public int parameterCounter = 0; - public Dictionary QueryVariables { get; set; } = new Dictionary(); + public Dictionary QueryVariables { get; set; } = []; public string FullQuery { get; set; } = ""; - public string ruleWhereStatement { get; set; } = ""; - public string nwObjWhereStatement { get; set; } = ""; - public string svcObjWhereStatement { get; set; } = ""; - public string userObjWhereStatement { get; set; } = ""; - public string connectionWhereStatement { get; set; } = ""; - public List QueryParameters { get; set; } = new List() - { + public string RuleWhereStatement { get; set; } = ""; + public string NwObjWhereStatement { get; set; } = ""; + public string SvcObjWhereStatement { get; set; } = ""; + public string UserObjWhereStatement { get; set; } = ""; + public string ConnectionWhereStatement { get; set; } = ""; + public string OpenRulesTable { get; set; } = "rules("; + public string OpenChangeLogRulesTable { get; set; } = "changelog_rules("; + public List QueryParameters { get; set; } = + [ " $limit: Int ", " $offset: Int " - }; + ]; public string ReportTimeString { get; set; } = ""; - public List RelevantManagementIds { get; set; } = new List(); + public List RelevantManagementIds { get; set; } = []; public ReportType ReportType { get; set; } = ReportType.Rules; + public FwoOwner? SelectedOwner { get; set; } public DynGraphqlQuery(string rawInput) { RawFilter = rawInput; } public static string fullTimeFormat = "yyyy-MM-dd HH:mm:ss"; public static string dateFormat = "yyyy-MM-dd"; - private static void SetDeviceFilter(ref DynGraphqlQuery query, DeviceFilter? deviceFilter) - { - bool first = true; - if (deviceFilter != null) - { - query.RelevantManagementIds = deviceFilter.getSelectedManagements(); - query.ruleWhereStatement += "{_or: [{"; - foreach (ManagementSelect mgmt in deviceFilter.Managements) - { - foreach (DeviceSelect dev in mgmt.Devices) - { - if (dev.Selected == true) - { - if (first == false) - { - query.ruleWhereStatement += "}, {"; - } - query.ruleWhereStatement += $" device: {{dev_id: {{_eq:{dev.Id}}} }}"; - first = false; - } - } - } - query.ruleWhereStatement += "}]}, "; - } - } - - private static void SetTenantFilter(ref DynGraphqlQuery query, ReportTemplate filter) - { - // the following additional filters are used for standard and simulated tenant filtering (by admin users) - if (filter.ReportParams.TenantFilter.IsActive) - { - int tenant_id = filter.ReportParams.TenantFilter.TenantId; - query.FullQuery = Regex.Replace(query.FullQuery, @"\srules\s*\(", $" rules: get_rules_for_tenant(args: {{tenant: {tenant_id}}}, "); - query.FullQuery = Regex.Replace(query.FullQuery, @"changelog_rules\s*\(", $" changelog_rules: get_changelog_rules_for_tenant(args: {{tenant: {tenant_id}}}, "); - query.FullQuery = Regex.Replace(query.FullQuery, @"rule_froms\s*\(", $"rule_froms: get_rule_froms_for_tenant(args: {{tenant: {tenant_id}}}"); - query.FullQuery = Regex.Replace(query.FullQuery, @"rule_froms\s*{", $"rule_froms: get_rule_froms_for_tenant(args: {{tenant: {tenant_id}}}) {{"); - query.FullQuery = Regex.Replace(query.FullQuery, @"rule_tos\s*\(", $"rule_tos: get_rule_tos_for_tenant(args: {{tenant: {tenant_id}}}"); - query.FullQuery = Regex.Replace(query.FullQuery, @"rule_tos\s*{", $"rule_tos: get_rule_tos_for_tenant(args: {{tenant: {tenant_id}}}) {{"); - } - } - - private static void SetTimeFilter(ref DynGraphqlQuery query, TimeFilter? timeFilter, ReportType? reportType, RecertFilter recertFilter) - { - if (timeFilter != null) - { - query.ruleWhereStatement += "{"; - switch (reportType) - { - case ReportType.Rules: - case ReportType.ResolvedRules: - case ReportType.ResolvedRulesTech: - case ReportType.Statistics: - case ReportType.NatRules: - case ReportType.UnusedRules: - query.QueryParameters.Add("$relevantImportId: bigint "); - query.ruleWhereStatement += - $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + - $"importControlByRuleLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; - query.nwObjWhereStatement += - $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + - $"importControlByObjLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; - query.svcObjWhereStatement += - $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + - $"importControlBySvcLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; - query.userObjWhereStatement += - $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + - $"importControlByUserLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; - query.ReportTimeString = (timeFilter.IsShortcut ? - DateTime.Now.ToString(fullTimeFormat) : - timeFilter.ReportTime.ToString(fullTimeFormat)); - break; - case ReportType.Changes: - case ReportType.ResolvedChanges: - case ReportType.ResolvedChangesTech: - (string start, string stop) = ResolveTimeRange(timeFilter); - query.QueryVariables["start"] = start; - query.QueryVariables["stop"] = stop; - query.QueryParameters.Add("$start: timestamp! "); - query.QueryParameters.Add("$stop: timestamp! "); - query.QueryParameters.Add("$relevantImportId: bigint "); - - query.ruleWhereStatement += $@" - _and: [ - {{ import_control: {{ stop_time: {{ _gte: $start }} }} }} - {{ import_control: {{ stop_time: {{ _lte: $stop }} }} }} - ] - change_type_id: {{ _eq: 3 }} - security_relevant: {{ _eq: true }}"; - break; - case ReportType.Recertification: - query.nwObjWhereStatement += "{}"; - query.svcObjWhereStatement += "{}"; - query.userObjWhereStatement += "{}"; - query.ReportTimeString = DateTime.Now.AddDays(recertFilter.RecertificationDisplayPeriod).ToString(fullTimeFormat); - query.QueryParameters.Add("$refdate1: timestamp! "); - query.QueryVariables["refdate1"] = query.ReportTimeString; - query.ruleWhereStatement += $@" rule_metadatum: {{ recertifications: {{ next_recert_date: {{ _lte: $refdate1 }} }} }} "; - break; - case ReportType.Connections: - break; - default: - Log.WriteError("Filter", $"Unexpected report type found: {reportType}"); - break; - } - query.ruleWhereStatement += "}, "; - } - } - - private static (string, string) ResolveTimeRange(TimeFilter timeFilter) - { - string start; - string stop; - DateTime startOfCurrentYear = new DateTime(DateTime.Now.Year, 1, 1); - DateTime startOfCurrentMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); - DateTime startOfCurrentWeek = DateTime.Now.AddDays(-(int)DateTime.Now.DayOfWeek); - - switch (timeFilter.TimeRangeType) - { - case TimeRangeType.Shortcut: - switch (timeFilter.TimeRangeShortcut) - { - case "this year": - start = startOfCurrentYear.ToString(dateFormat); - stop = startOfCurrentYear.AddYears(1).ToString(dateFormat); - break; - case "last year": - start = startOfCurrentYear.AddYears(-1).ToString(dateFormat); - stop = startOfCurrentYear.ToString(dateFormat); - break; - case "this month": - start = startOfCurrentMonth.ToString(dateFormat); - stop = startOfCurrentMonth.AddMonths(1).ToString(dateFormat); - break; - case "last month": - start = startOfCurrentMonth.AddMonths(-1).ToString(dateFormat); - stop = startOfCurrentMonth.ToString(dateFormat); - break; - case "this week": - start = startOfCurrentWeek.ToString(dateFormat); - stop = DateTime.Now.AddDays(1).ToString(dateFormat); - break; - case "last week": - start = startOfCurrentWeek.AddDays(-7).ToString(dateFormat); - stop = startOfCurrentWeek.ToString(dateFormat); - break; - case "today": - start = DateTime.Now.ToString(dateFormat); - stop = DateTime.Now.AddDays(1).ToString(dateFormat); - break; - case "yesterday": - start = DateTime.Now.AddDays(-1).ToString(dateFormat); - stop = DateTime.Now.ToString(dateFormat); - break; - default: - throw new Exception($"Error: wrong time range format:" + timeFilter.TimeRangeShortcut); - } - break; - - case TimeRangeType.Interval: - start = timeFilter.Interval switch - { - Interval.Days => DateTime.Now.AddDays(-timeFilter.Offset).ToString(fullTimeFormat), - Interval.Weeks => DateTime.Now.AddDays(-7 * timeFilter.Offset).ToString(fullTimeFormat), - Interval.Months => DateTime.Now.AddMonths(-timeFilter.Offset).ToString(fullTimeFormat), - Interval.Years => DateTime.Now.AddYears(-timeFilter.Offset).ToString(fullTimeFormat), - _ => throw new Exception($"Error: wrong time interval format:" + timeFilter.Interval.ToString()), - }; - stop = DateTime.Now.ToString(fullTimeFormat); - break; - - case TimeRangeType.Fixeddates: - if (timeFilter.OpenStart) - start = DateTime.MinValue.ToString(fullTimeFormat); - else - start = timeFilter.StartTime.ToString(fullTimeFormat); - if (timeFilter.OpenEnd) - stop = DateTime.MaxValue.ToString(fullTimeFormat); - else - stop = timeFilter.EndTime.ToString(fullTimeFormat); - break; - - default: - throw new NotSupportedException($"Found unexpected TimeRangeType"); - } - return (start, stop); - } - - private static void SetRecertFilter(ref DynGraphqlQuery query, RecertFilter? recertFilter) - { - if (recertFilter != null) - { - // setting owner filter: - if (recertFilter.RecertOwnerList.Count > 0) - { - query.QueryParameters.Add("$ownerWhere: owner_bool_exp"); - query.QueryVariables["ownerWhere"] = new {id = new {_in = recertFilter.RecertOwnerList}}; - } - else - { - // if no ownerIds are set in the filter, return all recerts - query.QueryParameters.Add("$ownerWhere: owner_bool_exp"); - query.QueryVariables["ownerWhere"] = new {id = new {}}; - } - } - } - - private static void SetConnectionFilter(ref DynGraphqlQuery query, ModellingFilter? modellingFilter) - { - if (modellingFilter != null) - { - query.QueryParameters.Add("$appId: Int!"); - query.QueryVariables["appId"] = modellingFilter.SelectedOwner.Id; - query.connectionWhereStatement += $@"{{ _or: [ {{ app_id: {{ _eq: $appId }} }}, {{ proposed_app_id: {{ _eq: $appId }} }} ] }}"; - } - } - - private static void SetUnusedFilter(ref DynGraphqlQuery query, UnusedFilter? unusedFilter) - { - if (unusedFilter != null) - { - query.QueryParameters.Add("$cut: timestamp"); - query.QueryParameters.Add("$tolerance: timestamp"); - query.QueryVariables["cut"] = DateTime.Now.AddDays(-unusedFilter.UnusedForDays); - query.QueryVariables["tolerance"] = DateTime.Now.AddDays(-unusedFilter.CreationTolerance); - query.ruleWhereStatement += $@"{{rule_metadatum: {{_or: [ - {{_and: [{{rule_last_hit: {{_is_null: false}} }}, {{rule_last_hit: {{_lte: $cut}} }} ] }}, - {{_and: [{{rule_last_hit: {{_is_null: true}} }}, {{rule_created: {{_lte: $tolerance}} }} ] }} - ]}} }}"; - } - } - - private static void SetFixedFilters(ref DynGraphqlQuery query, ReportTemplate reportParams) - { - if (((ReportType)reportParams.ReportParams.ReportType).IsRuleReport() || reportParams.ReportParams.ReportType == (int)ReportType.Statistics) - { - query.QueryParameters.Add("$mgmId: [Int!] "); - } - - // leave out all header texts - if (reportParams.ReportParams.ReportType == (int)ReportType.Statistics || - reportParams.ReportParams.ReportType == (int)ReportType.Recertification) - { - query.ruleWhereStatement += "{rule_head_text: {_is_null: true}}, "; - } - SetTenantFilter(ref query, reportParams); - if (((ReportType)reportParams.ReportParams.ReportType).IsDeviceRelatedReport()) - { - SetDeviceFilter(ref query, reportParams.ReportParams.DeviceFilter); - SetTimeFilter(ref query, reportParams.ReportParams.TimeFilter, (ReportType)reportParams.ReportParams.ReportType, reportParams.ReportParams.RecertFilter); - } - if ((ReportType)reportParams.ReportParams.ReportType==ReportType.Recertification) - { - SetRecertFilter(ref query, reportParams.ReportParams.RecertFilter); - } - if ((ReportType)reportParams.ReportParams.ReportType==ReportType.UnusedRules) - { - SetUnusedFilter(ref query, reportParams.ReportParams.UnusedFilter); - } - if ((ReportType)reportParams.ReportParams.ReportType==ReportType.Connections) - { - SetConnectionFilter(ref query, reportParams.ReportParams.ModellingFilter); - } - } public static DynGraphqlQuery GenerateQuery(ReportTemplate filter, AstNode? ast) { - DynGraphqlQuery query = new DynGraphqlQuery(filter.Filter); + DynGraphqlQuery query = new(filter.Filter); - query.ruleWhereStatement += "_and: ["; - query.connectionWhereStatement += "_and: ["; + query.RuleWhereStatement += "_and: ["; + query.ConnectionWhereStatement += "_and: ["; SetFixedFilters(ref query, filter); - query.ruleWhereStatement += "{"; - query.connectionWhereStatement += "{"; + query.RuleWhereStatement += "{"; + query.ConnectionWhereStatement += "{"; // now we convert the ast into a graphql query: - if (ast != null) - ast.Extract(ref query, (ReportType)filter.ReportParams.ReportType); + ast?.Extract(ref query, (ReportType)filter.ReportParams.ReportType); - query.ruleWhereStatement += "}] "; - query.connectionWhereStatement += "}] "; + query.RuleWhereStatement += "}] "; + query.ConnectionWhereStatement += "}] "; string paramString = string.Join(" ", query.QueryParameters.ToArray()); @@ -329,6 +67,9 @@ public static DynGraphqlQuery GenerateQuery(ReportTemplate filter, AstNode? ast) stm_dev_typ: {{is_pure_routing_device:{{_eq:false}} }} }} order_by: {{ dev_name: asc }}"; + string limitOffsetString = $@"limit: $limit + offset: $offset "; + if (((ReportType)filter.ReportParams.ReportType).IsResolvedReport()) filter.Detailed = true; @@ -342,15 +83,15 @@ query statisticsReport ({paramString}) {{ name: mgm_name id: mgm_id - objects_aggregate(where: {{ {query.nwObjWhereStatement} }}) {{ aggregate {{ count }} }} - services_aggregate(where: {{ {query.svcObjWhereStatement} }}) {{ aggregate {{ count }} }} - usrs_aggregate(where: {{ {query.userObjWhereStatement} }}) {{ aggregate {{ count }} }} - rules_aggregate(where: {{ {query.ruleWhereStatement} }}) {{ aggregate {{ count }} }} + objects_aggregate(where: {{ {query.NwObjWhereStatement} }}) {{ aggregate {{ count }} }} + services_aggregate(where: {{ {query.SvcObjWhereStatement} }}) {{ aggregate {{ count }} }} + usrs_aggregate(where: {{ {query.UserObjWhereStatement} }}) {{ aggregate {{ count }} }} + rules_aggregate(where: {{ {query.RuleWhereStatement} }}) {{ aggregate {{ count }} }} devices({devWhereString}) {{ name: dev_name id: dev_id - rules_aggregate(where: {{ {query.ruleWhereStatement} }}) {{ aggregate {{ count }} }} + rules_aggregate(where: {{ {query.RuleWhereStatement} }}) {{ aggregate {{ count }} }} }} }} }} @@ -361,6 +102,7 @@ query statisticsReport ({paramString}) case ReportType.ResolvedRules: case ReportType.ResolvedRulesTech: case ReportType.UnusedRules: + case ReportType.AppRules: query.FullQuery = Queries.compact($@" {(filter.Detailed ? RuleQueries.ruleDetailsForReportFragments : RuleQueries.ruleOverviewFragments)} query rulesReport ({paramString}) @@ -373,10 +115,9 @@ query rulesReport ({paramString}) {{ id: dev_id name: dev_name - rules( - limit: $limit - offset: $offset - where: {{ access_rule: {{_eq: true}} {query.ruleWhereStatement} }} + {query.OpenRulesTable} + {limitOffsetString} + where: {{ access_rule: {{_eq: true}} {query.RuleWhereStatement} }} order_by: {{ rule_num_numeric: asc }} ) {{ mgm_id: mgm_id @@ -402,14 +143,13 @@ query rulesCertReport({paramString}) {{ id: dev_id name: dev_name - rules( + {query.OpenRulesTable} where: {{ rule_metadatum: {{ recertifications_aggregate: {{ count: {{ filter: {{ _and: [{{owner: $ownerWhere}}, {{recert_date: {{_is_null: true}}}}, {{next_recert_date: {{_lte: $refdate1}}}}]}}, predicate: {{_gt: 0}}}}}}}} active:{{ _eq:true }} - {query.ruleWhereStatement} + {query.RuleWhereStatement} }} - limit: $limit - offset: $offset + {limitOffsetString} order_by: {{ rule_num_numeric: asc }} ) {{ @@ -437,16 +177,15 @@ query changeReport({paramString}) {{ id: dev_id name: dev_name - changelog_rules( - offset: $offset - limit: $limit + {query.OpenChangeLogRulesTable} + {limitOffsetString} where: {{ _or:[ {{_and: [{{change_action:{{_eq:""I""}}}}, {{rule: {{access_rule:{{_eq:true}}}}}}]}}, {{_and: [{{change_action:{{_eq:""D""}}}}, {{ruleByOldRuleId: {{access_rule:{{_eq:true}}}}}}]}}, {{_and: [{{change_action:{{_eq:""C""}}}}, {{rule: {{access_rule:{{_eq:true}}}}}}, {{ruleByOldRuleId: {{access_rule:{{_eq:true}}}}}}]}} ] - {query.ruleWhereStatement} + {query.RuleWhereStatement} }} order_by: {{ control_id: asc }} ) @@ -481,10 +220,9 @@ query natRulesReport ({paramString}) {{ id: dev_id name: dev_name - rules( - limit: $limit - offset: $offset - where: {{ nat_rule: {{_eq: true}}, ruleByXlateRule: {{}} {query.ruleWhereStatement} }} + {query.OpenRulesTable} + {limitOffsetString} + where: {{ nat_rule: {{_eq: true}}, ruleByXlateRule: {{}} {query.RuleWhereStatement} }} order_by: {{ rule_num_numeric: asc }} ) {{ mgm_id: mgm_id @@ -502,7 +240,7 @@ query natRulesReport ({paramString}) {ModellingQueries.connectionDetailsFragment} query getConnections ({paramString}) {{ - modelling_connection (where: {{ {query.connectionWhereStatement} }} order_by: {{ is_interface: desc, common_service: desc, name: asc }}) + modelling_connection (where: {{ {query.ConnectionWhereStatement} }} order_by: {{ is_interface: desc, common_service: desc, name: asc }}) {{ ...connectionDetails }} @@ -511,7 +249,7 @@ query getConnections ({paramString}) break; } - SetTenantFilter(ref query, filter); + OverwriteMissingTenantFilters(ref query, filter); string pattern = ""; // remove comment lines (#) before joining lines! @@ -541,5 +279,284 @@ query getConnections ({paramString}) return query; } + + private static void SetFixedFilters(ref DynGraphqlQuery query, ReportTemplate reportParams) + { + if (((ReportType)reportParams.ReportParams.ReportType).IsRuleReport() || reportParams.ReportParams.ReportType == (int)ReportType.Statistics) + { + query.QueryParameters.Add("$mgmId: [Int!] "); + } + + // leave out all header texts + if ((ReportType)reportParams.ReportParams.ReportType == ReportType.Statistics || + (ReportType)reportParams.ReportParams.ReportType == ReportType.Recertification) + { + query.RuleWhereStatement += "{rule_head_text: {_is_null: true}}, "; + } + SetTenantFilter(ref query, reportParams); + if (((ReportType)reportParams.ReportParams.ReportType).IsDeviceRelatedReport()) + { + SetDeviceFilter(ref query, reportParams.ReportParams.DeviceFilter); + SetTimeFilter(ref query, reportParams.ReportParams.TimeFilter, (ReportType)reportParams.ReportParams.ReportType, reportParams.ReportParams.RecertFilter); + } + if ((ReportType)reportParams.ReportParams.ReportType == ReportType.Recertification) + { + SetRecertFilter(ref query, reportParams.ReportParams.RecertFilter); + } + if ((ReportType)reportParams.ReportParams.ReportType == ReportType.UnusedRules) + { + SetUnusedFilter(ref query, reportParams.ReportParams.UnusedFilter); + } + if ((ReportType)reportParams.ReportParams.ReportType == ReportType.AppRules) + { + SetOwnerFilter(ref query, reportParams.ReportParams.ModellingFilter); + } + if ((ReportType)reportParams.ReportParams.ReportType == ReportType.Connections) + { + SetConnectionFilter(ref query, reportParams.ReportParams.ModellingFilter); + } + } + + private static void SetDeviceFilter(ref DynGraphqlQuery query, DeviceFilter? deviceFilter) + { + bool first = true; + if (deviceFilter != null) + { + query.RelevantManagementIds = deviceFilter.getSelectedManagements(); + query.RuleWhereStatement += "{_or: [{"; + foreach (ManagementSelect mgmt in deviceFilter.Managements) + { + foreach (DeviceSelect dev in mgmt.Devices) + { + if (dev.Selected == true) + { + if (first == false) + { + query.RuleWhereStatement += "}, {"; + } + query.RuleWhereStatement += $" device: {{dev_id: {{_eq:{dev.Id}}} }}"; + first = false; + } + } + } + query.RuleWhereStatement += "}]}, "; + } + } + + private static void SetTimeFilter(ref DynGraphqlQuery query, TimeFilter? timeFilter, ReportType? reportType, RecertFilter recertFilter) + { + if (timeFilter != null) + { + query.RuleWhereStatement += "{"; + switch (reportType) + { + case ReportType.Rules: + case ReportType.ResolvedRules: + case ReportType.ResolvedRulesTech: + case ReportType.Statistics: + case ReportType.NatRules: + case ReportType.UnusedRules: + case ReportType.AppRules: + query.QueryParameters.Add("$relevantImportId: bigint "); + query.RuleWhereStatement += + $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + + $"importControlByRuleLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; + query.NwObjWhereStatement += + $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + + $"importControlByObjLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; + query.SvcObjWhereStatement += + $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + + $"importControlBySvcLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; + query.UserObjWhereStatement += + $"import_control: {{ control_id: {{_lte: $relevantImportId }} }}, " + + $"importControlByUserLastSeen: {{ control_id: {{_gte: $relevantImportId }} }}"; + query.ReportTimeString = timeFilter.IsShortcut ? + DateTime.Now.ToString(fullTimeFormat) : timeFilter.ReportTime.ToString(fullTimeFormat); + break; + case ReportType.Changes: + case ReportType.ResolvedChanges: + case ReportType.ResolvedChangesTech: + (string start, string stop) = ResolveTimeRange(timeFilter); + query.QueryVariables["start"] = start; + query.QueryVariables["stop"] = stop; + query.QueryParameters.Add("$start: timestamp! "); + query.QueryParameters.Add("$stop: timestamp! "); + query.QueryParameters.Add("$relevantImportId: bigint "); + + query.RuleWhereStatement += $@" + _and: [ + {{ import_control: {{ stop_time: {{ _gte: $start }} }} }} + {{ import_control: {{ stop_time: {{ _lte: $stop }} }} }} + ] + change_type_id: {{ _eq: 3 }} + security_relevant: {{ _eq: true }}"; + break; + case ReportType.Recertification: + query.NwObjWhereStatement += "{}"; + query.SvcObjWhereStatement += "{}"; + query.UserObjWhereStatement += "{}"; + query.ReportTimeString = DateTime.Now.AddDays(recertFilter.RecertificationDisplayPeriod).ToString(fullTimeFormat); + query.QueryParameters.Add("$refdate1: timestamp! "); + query.QueryVariables["refdate1"] = query.ReportTimeString; + query.RuleWhereStatement += $@" rule_metadatum: {{ recertifications: {{ next_recert_date: {{ _lte: $refdate1 }} }} }} "; + break; + case ReportType.Connections: + break; + default: + Log.WriteError("Filter", $"Unexpected report type found: {reportType}"); + break; + } + query.RuleWhereStatement += "}, "; + } + } + + private static (string, string) ResolveTimeRange(TimeFilter timeFilter) + { + string start; + string stop; + DateTime startOfCurrentYear = new(DateTime.Now.Year, 1, 1); + DateTime startOfCurrentMonth = new(DateTime.Now.Year, DateTime.Now.Month, 1); + DateTime startOfCurrentWeek = DateTime.Now.AddDays(-(int)DateTime.Now.DayOfWeek); + + switch (timeFilter.TimeRangeType) + { + case TimeRangeType.Shortcut: + switch (timeFilter.TimeRangeShortcut) + { + case "this year": + start = startOfCurrentYear.ToString(dateFormat); + stop = startOfCurrentYear.AddYears(1).ToString(dateFormat); + break; + case "last year": + start = startOfCurrentYear.AddYears(-1).ToString(dateFormat); + stop = startOfCurrentYear.ToString(dateFormat); + break; + case "this month": + start = startOfCurrentMonth.ToString(dateFormat); + stop = startOfCurrentMonth.AddMonths(1).ToString(dateFormat); + break; + case "last month": + start = startOfCurrentMonth.AddMonths(-1).ToString(dateFormat); + stop = startOfCurrentMonth.ToString(dateFormat); + break; + case "this week": + start = startOfCurrentWeek.ToString(dateFormat); + stop = DateTime.Now.AddDays(1).ToString(dateFormat); + break; + case "last week": + start = startOfCurrentWeek.AddDays(-7).ToString(dateFormat); + stop = startOfCurrentWeek.ToString(dateFormat); + break; + case "today": + start = DateTime.Now.ToString(dateFormat); + stop = DateTime.Now.AddDays(1).ToString(dateFormat); + break; + case "yesterday": + start = DateTime.Now.AddDays(-1).ToString(dateFormat); + stop = DateTime.Now.ToString(dateFormat); + break; + default: + throw new Exception($"Error: wrong time range format:" + timeFilter.TimeRangeShortcut); + } + break; + + case TimeRangeType.Interval: + start = timeFilter.Interval switch + { + Interval.Days => DateTime.Now.AddDays(-timeFilter.Offset).ToString(fullTimeFormat), + Interval.Weeks => DateTime.Now.AddDays(-7 * timeFilter.Offset).ToString(fullTimeFormat), + Interval.Months => DateTime.Now.AddMonths(-timeFilter.Offset).ToString(fullTimeFormat), + Interval.Years => DateTime.Now.AddYears(-timeFilter.Offset).ToString(fullTimeFormat), + _ => throw new Exception($"Error: wrong time interval format:" + timeFilter.Interval.ToString()), + }; + stop = DateTime.Now.ToString(fullTimeFormat); + break; + + case TimeRangeType.Fixeddates: + if (timeFilter.OpenStart) + start = DateTime.MinValue.ToString(fullTimeFormat); + else + start = timeFilter.StartTime.ToString(fullTimeFormat); + if (timeFilter.OpenEnd) + stop = DateTime.MaxValue.ToString(fullTimeFormat); + else + stop = timeFilter.EndTime.ToString(fullTimeFormat); + break; + + default: + throw new NotSupportedException($"Found unexpected TimeRangeType"); + } + return (start, stop); + } + + private static void SetRecertFilter(ref DynGraphqlQuery query, RecertFilter? recertFilter) + { + if (recertFilter != null) + { + query.QueryParameters.Add("$ownerWhere: owner_bool_exp"); + query.QueryVariables["ownerWhere"] = recertFilter.RecertOwnerList.Count > 0 ? + new {id = new {_in = recertFilter.RecertOwnerList}} : new {id = new {}}; + } + } + + private static void SetOwnerFilter(ref DynGraphqlQuery query, ModellingFilter? modellingFilter) + { + if (modellingFilter != null) + { + // currently overruling tenant filter!! + query.OpenRulesTable = $"rules: get_rules_for_owner(args: {{ownerid: {modellingFilter.SelectedOwner.Id}}}, "; + query.SelectedOwner = modellingFilter.SelectedOwner; + } + } + + private static void SetConnectionFilter(ref DynGraphqlQuery query, ModellingFilter? modellingFilter) + { + if (modellingFilter != null) + { + query.QueryParameters.Add("$appId: Int!"); + query.QueryVariables["appId"] = modellingFilter.SelectedOwner.Id; + query.ConnectionWhereStatement += $@"{{ _or: [ {{ app_id: {{ _eq: $appId }} }}, {{ proposed_app_id: {{ _eq: $appId }} }} ] }}"; + } + } + + private static void SetUnusedFilter(ref DynGraphqlQuery query, UnusedFilter? unusedFilter) + { + if (unusedFilter != null) + { + query.QueryParameters.Add("$cut: timestamp"); + query.QueryParameters.Add("$tolerance: timestamp"); + query.QueryVariables["cut"] = DateTime.Now.AddDays(-unusedFilter.UnusedForDays); + query.QueryVariables["tolerance"] = DateTime.Now.AddDays(-unusedFilter.CreationTolerance); + query.RuleWhereStatement += $@"{{rule_metadatum: {{_or: [ + {{_and: [{{rule_last_hit: {{_is_null: false}} }}, {{rule_last_hit: {{_lte: $cut}} }} ] }}, + {{_and: [{{rule_last_hit: {{_is_null: true}} }}, {{rule_created: {{_lte: $tolerance}} }} ] }} + ]}} }}"; + } + } + + private static void SetTenantFilter(ref DynGraphqlQuery query, ReportTemplate filter) + { + if (filter.ReportParams.TenantFilter.IsActive) + { + int tenant_id = filter.ReportParams.TenantFilter.TenantId; + query.OpenRulesTable = $"rules: get_rules_for_tenant(args: {{tenant: {tenant_id}}}, "; + query.OpenChangeLogRulesTable = $"changelog_rules: get_changelog_rules_for_tenant(args: {{tenant: {tenant_id}}}, "; + } + } + + private static void OverwriteMissingTenantFilters(ref DynGraphqlQuery query, ReportTemplate filter) + { + // the following additional filters are used for standard and simulated tenant filtering (by admin users) + if (filter.ReportParams.TenantFilter.IsActive) + { + int tenant_id = filter.ReportParams.TenantFilter.TenantId; + query.FullQuery = Regex.Replace(query.FullQuery, @"\srules\s*\(", $" rules: get_rules_for_tenant(args: {{tenant: {tenant_id}}}, "); + query.FullQuery = Regex.Replace(query.FullQuery, @"changelog_rules\s*\(", $" changelog_rules: get_changelog_rules_for_tenant(args: {{tenant: {tenant_id}}}, "); + query.FullQuery = Regex.Replace(query.FullQuery, @"rule_froms\s*\(", $"rule_froms: get_rule_froms_for_tenant(args: {{tenant: {tenant_id}}}"); + query.FullQuery = Regex.Replace(query.FullQuery, @"rule_froms\s*{", $"rule_froms: get_rule_froms_for_tenant(args: {{tenant: {tenant_id}}}) {{"); + query.FullQuery = Regex.Replace(query.FullQuery, @"rule_tos\s*\(", $"rule_tos: get_rule_tos_for_tenant(args: {{tenant: {tenant_id}}}"); + query.FullQuery = Regex.Replace(query.FullQuery, @"rule_tos\s*{", $"rule_tos: get_rule_tos_for_tenant(args: {{tenant: {tenant_id}}}) {{"); + } + } } } diff --git a/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportFilters.cs b/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportFilters.cs index 73665fd93..400664bda 100644 --- a/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportFilters.cs +++ b/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportFilters.cs @@ -1,4 +1,3 @@ -using FWO.GlobalConstants; using FWO.Api.Data; using FWO.Config.Api; @@ -68,7 +67,7 @@ public void SyncFiltersFromTemplate(ReportTemplate template) public ReportParams ToReportParams() { - ReportParams reportParams = new ReportParams((int)ReportType, ReportType == ReportType.UnusedRules ? ReducedDeviceFilter : DeviceFilter) + ReportParams reportParams = new((int)ReportType, ReportType == ReportType.UnusedRules ? ReducedDeviceFilter : DeviceFilter) { TimeFilter = SavedTimeFilter, RecertFilter = new RecertFilter(RecertFilter), @@ -150,9 +149,9 @@ public void TenantViewChanged(Tenant? newTenantView) SelectedTenant = newTenantView; // we must modify the device visibility in the device filter - if (SelectedTenant==null || SelectedTenant.Id == 1) + if (SelectedTenant == null || SelectedTenant.Id == 1) { - // tenant0 or no tenant selected --> all devices are visible + // tenant0 or no tenant selected --> all devices are visible MarkAllDevicesVisible(DeviceFilter.Managements); } else @@ -163,7 +162,7 @@ public void TenantViewChanged(Tenant? newTenantView) SelectAll = !DeviceFilter.isAnyDeviceFilterSet(); } - private void MarkAllDevicesVisible(List mgms) + private static void MarkAllDevicesVisible(List mgms) { foreach (ManagementSelect management in mgms) { @@ -187,7 +186,7 @@ private void SetDeviceVisibility(Tenant tenantView) if (!tenantView.VisibleGatewayIds.Contains(gw.VisibleGateway.Id)) { tenantView.VisibleGatewayIds.Append(gw.VisibleGateway.Id); - tenantView.VisibleGatewayIds = tenantView.VisibleGatewayIds.Concat(new int[] { gw.VisibleGateway.Id }).ToArray(); + tenantView.VisibleGatewayIds = tenantView.VisibleGatewayIds.Concat([gw.VisibleGateway.Id]).ToArray(); } } @@ -201,7 +200,7 @@ private void SetDeviceVisibility(Tenant tenantView) if (!tenantView.VisibleGatewayIds.Contains(gw.Id)) { tenantView.VisibleGatewayIds.Append(gw.Id); - tenantView.VisibleGatewayIds = tenantView.VisibleGatewayIds.Concat(new int[] { gw.Id }).ToArray(); + tenantView.VisibleGatewayIds = tenantView.VisibleGatewayIds.Concat([gw.Id]).ToArray(); } } } diff --git a/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportType.cs b/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportType.cs index 15d263ba0..a2c8182fd 100644 --- a/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportType.cs +++ b/roles/lib/files/FWO.Report.Filter/FilterTypes/ReportType.cs @@ -13,7 +13,8 @@ public enum ReportType ResolvedChangesTech = 9, UnusedRules = 10, - Connections = 21 + Connections = 21, + AppRules = 22 } public static class ReportTypeGroups @@ -28,6 +29,7 @@ public static bool IsRuleReport(this ReportType reportType) case ReportType.NatRules: case ReportType.Recertification: case ReportType.UnusedRules: + case ReportType.AppRules: return true; default: return false; @@ -83,6 +85,7 @@ public static bool IsModellingReport(this ReportType reportType) switch(reportType) { case ReportType.Connections: + case ReportType.AppRules: return true; default: return false; diff --git a/roles/lib/files/FWO.Report/Display/RuleDisplayBase.cs b/roles/lib/files/FWO.Report/Display/RuleDisplayBase.cs index 5b209faa8..8c2ba2950 100644 --- a/roles/lib/files/FWO.Report/Display/RuleDisplayBase.cs +++ b/roles/lib/files/FWO.Report/Display/RuleDisplayBase.cs @@ -22,7 +22,7 @@ public string DisplayNumber(Rule rule) public string DisplayName(Rule rule) { - return rule.Name != null ? rule.Name : ""; + return rule.Name ?? ""; } public string DisplaySourceZone(Rule rule) @@ -35,29 +35,29 @@ public string DisplayDestinationZone(Rule rule) return rule.DestinationZone != null ? rule.DestinationZone.Name : ""; } - public string DisplayAction(Rule rule) + public static string DisplayAction(Rule rule) { return rule.Action; } - public string DisplayTrack(Rule rule) + public static string DisplayTrack(Rule rule) { return rule.Track; } - public string DisplayUid(Rule rule) + public static string DisplayUid(Rule rule) { - return rule.Uid != null ? rule.Uid : ""; + return rule.Uid ?? ""; } - public string DisplayComment(Rule rule) + public static string DisplayComment(Rule rule) { - return rule.Comment != null ? rule.Comment : ""; + return rule.Comment ?? ""; } - public StringBuilder DisplayNetworkLocation(NetworkLocation userNetworkObject, ReportType reportType, string? userName = null, string? objName = null) + public static StringBuilder DisplayNetworkLocation(NetworkLocation userNetworkObject, ReportType reportType, string? userName = null, string? objName = null) { - StringBuilder result = new StringBuilder(); + StringBuilder result = new(); if (userNetworkObject.User != null && userNetworkObject.User.Id > 0) { @@ -85,21 +85,21 @@ public static StringBuilder DisplayService(NetworkService service, ReportType re return DisplayBase.DisplayService(service, reportType.IsTechReport(), serviceName); } - public StringBuilder RemoveLastChars(StringBuilder s, int count) + public static StringBuilder RemoveLastChars(StringBuilder s, int count) { string x = s.ToString(); x = x.Remove(x.ToString().Length - count, count).ToString(); return s.Remove(s.ToString().Length - count, count); } - public string Quote(string? input) + public static string Quote(string? input) { return $"\"{input ?? ""}\""; } - public List getNetworkLocations(NetworkLocation[] locationArray) + public static List GetNetworkLocations(NetworkLocation[] locationArray) { - HashSet collectedUserNetworkObjects = new HashSet(); + HashSet collectedUserNetworkObjects = []; foreach (NetworkLocation networkObject in locationArray) { foreach (GroupFlat nwObject in networkObject.Object.ObjectGroupFlats) @@ -110,14 +110,14 @@ public List getNetworkLocations(NetworkLocation[] locationArray } } } - List userNwObjectList = collectedUserNetworkObjects.ToList(); + List userNwObjectList = [.. collectedUserNetworkObjects]; userNwObjectList.Sort(); return userNwObjectList; } - public List GetNetworkServices(ServiceWrapper[] serviceArray) + public static List GetNetworkServices(ServiceWrapper[] serviceArray) { - HashSet collectedServices = new HashSet(); + HashSet collectedServices = []; foreach (ServiceWrapper service in serviceArray) { foreach (GroupFlat nwService in service.Content.ServiceGroupFlats) @@ -128,16 +128,16 @@ public List GetNetworkServices(ServiceWrapper[] serviceArray) } } } - List serviceList = collectedServices.ToList(); + List serviceList = [.. collectedServices]; serviceList.Sort(delegate (NetworkService x, NetworkService y) { return x.Name.CompareTo(y.Name); }); return serviceList; } - protected void AnalyzeElements(string oldElement, string newElement, ref List unchanged, ref List deleted, ref List added) + protected static void AnalyzeElements(string oldElement, string newElement, ref List unchanged, ref List deleted, ref List added) { - string[] separatingStrings = { "," }; - string[] oldAr = oldElement.Split(separatingStrings, System.StringSplitOptions.RemoveEmptyEntries); - string[] newAr = newElement.Split(separatingStrings, System.StringSplitOptions.RemoveEmptyEntries); + string[] separatingStrings = [","]; + string[] oldAr = oldElement.Split(separatingStrings, StringSplitOptions.RemoveEmptyEntries); + string[] newAr = newElement.Split(separatingStrings, StringSplitOptions.RemoveEmptyEntries); foreach (var item in oldAr) { diff --git a/roles/lib/files/FWO.Report/Display/RuleDisplayCsv.cs b/roles/lib/files/FWO.Report/Display/RuleDisplayCsv.cs index acb145f32..344ace0a8 100644 --- a/roles/lib/files/FWO.Report/Display/RuleDisplayCsv.cs +++ b/roles/lib/files/FWO.Report/Display/RuleDisplayCsv.cs @@ -141,7 +141,7 @@ private string DisplaySourceOrDestination(Rule rule, ReportType reportType , boo if (reportType.IsResolvedReport()) { List displayedLocations = new List(); - foreach (NetworkLocation networkLocation in getNetworkLocations(isSource ? rule.Froms : rule.Tos)) + foreach (NetworkLocation networkLocation in GetNetworkLocations(isSource ? rule.Froms : rule.Tos)) { displayedLocations.Add(DisplayNetworkLocation(networkLocation, reportType).ToString()); } diff --git a/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs b/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs index 5f59dbb66..48b5c53cc 100644 --- a/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs +++ b/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs @@ -1,5 +1,4 @@ -using FWO.GlobalConstants; -using FWO.Api.Data; +using FWO.Api.Data; using FWO.Config.Api; using System.Text; using FWO.Report; @@ -24,7 +23,7 @@ public string DisplayDestination(Rule rule, OutputLocation location, ReportType public string DisplayServices(Rule rule, OutputLocation location, ReportType reportType, string style = "") { - StringBuilder result = new StringBuilder(); + StringBuilder result = new (); if (rule.ServiceNegated) { result.AppendLine(userConfig.GetText("negated") + "
"); @@ -57,19 +56,19 @@ public string DisplayEnabled(Rule rule, OutputLocation location) public string DisplayNextRecert(Rule rule) { int count = 0; - return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => getNextRecertDateString(countString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); + return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => GetNextRecertDateString(CountString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); } public string DisplayOwner(Rule rule) { int count = 0; - return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => getOwnerDisplayString(countString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); + return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => GetOwnerDisplayString(CountString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); } public string DisplayRecertIpMatches(Rule rule) { int count = 0; - return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => getIpMatchDisplayString(countString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); + return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => GetIpMatchDisplayString(CountString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); } public string DisplayLastHit(Rule rule) @@ -83,20 +82,21 @@ public string DisplayLastHit(Rule rule) public string DisplayLastRecertifier(Rule rule) { int count = 0; - return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => getLastRecertifierDisplayString(countString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); + return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => GetLastRecertifierDisplayString(CountString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); } - protected string NetworkLocationToHtml(NetworkLocation networkLocation, int mgmtId, OutputLocation location, string style, ReportType reportType) + protected static string NetworkLocationToHtml(NetworkLocation networkLocation, int mgmtId, OutputLocation location, string style, ReportType reportType, bool disregarded = false) { - return DisplayNetworkLocation(networkLocation, reportType, - reportType.IsResolvedReport() || networkLocation.User == null ? null : + string nwLocation = DisplayNetworkLocation(networkLocation, reportType, + reportType.IsResolvedReport() || networkLocation.User == null || disregarded ? null : ReportDevicesBase.ConstructLink(ObjCatString.User, ReportBase.GetIconClass(ObjCategory.user, networkLocation.User?.Type.Name), networkLocation.User!.Id, networkLocation.User.Name, location, mgmtId, style), - reportType.IsResolvedReport() ? null : + reportType.IsResolvedReport() || disregarded ? null : ReportDevicesBase.ConstructLink(ObjCatString.NwObj, ReportBase.GetIconClass(ObjCategory.nobj, networkLocation.Object.Type.Name), networkLocation.Object.Id, networkLocation.Object.Name, location, mgmtId, style) ).ToString(); + return $"{nwLocation}"; } - protected string ServiceToHtml(NetworkService service, int mgmtId, OutputLocation location, string style, ReportType reportType) + protected static string ServiceToHtml(NetworkService service, int mgmtId, OutputLocation location, string style, ReportType reportType) { return DisplayService(service, reportType, reportType.IsResolvedReport() ? null : ReportDevicesBase.ConstructLink(ObjCatString.Svc, ReportBase.GetIconClass(ObjCategory.nsrv, service.Type.Name), service.Id, service.Name, location, mgmtId, style)).ToString(); @@ -104,26 +104,39 @@ protected string ServiceToHtml(NetworkService service, int mgmtId, OutputLocatio private string DisplaySourceOrDestination(Rule rule, OutputLocation location, ReportType reportType, string style, bool isSource) { - StringBuilder result = new StringBuilder(); + StringBuilder result = new(); if ((isSource && rule.SourceNegated) ||(!isSource && rule.DestinationNegated)) { result.AppendLine(userConfig.GetText("negated") + "
"); } + string highlightedStyle = style + (reportType == ReportType.AppRules ? " color:red;" : ""); if(reportType.IsResolvedReport()) { - NetworkLocation[] userNwObjects = getNetworkLocations(isSource ? rule.Froms : rule.Tos).ToArray(); - result.AppendJoin("
", Array.ConvertAll(userNwObjects, networkLocation => NetworkLocationToHtml(networkLocation, rule.MgmtId, location, style, reportType))); + NetworkLocation[] userNwObjects = [.. GetNetworkLocations(isSource ? rule.Froms : rule.Tos)]; + result.AppendJoin("
", Array.ConvertAll(userNwObjects, networkLocation => NetworkLocationToHtml(networkLocation, rule.MgmtId, location, highlightedStyle, reportType))); } else { - result.AppendJoin("
", Array.ConvertAll(isSource ? rule.Froms : rule.Tos, networkLocation => NetworkLocationToHtml(networkLocation, rule.MgmtId, location, style, reportType))); + result.AppendJoin("
", Array.ConvertAll(isSource ? rule.Froms : rule.Tos, networkLocation => NetworkLocationToHtml(networkLocation, rule.MgmtId, location, highlightedStyle, reportType))); + } + if(reportType == ReportType.AppRules) + { + if((isSource && rule.Froms.Length > 0 && rule.DisregardedFroms.Length > 0) || + (!isSource && rule.Tos.Length > 0 && rule.DisregardedTos.Length > 0)) + { + result.Append($"
... ({(isSource ? rule.DisregardedFroms.Length : rule.DisregardedTos.Length)} {userConfig.GetText("more")})"); + } + else + { + result.AppendJoin("
", Array.ConvertAll(isSource ? rule.DisregardedFroms : rule.DisregardedTos, networkLocation => NetworkLocationToHtml(networkLocation, rule.MgmtId, location, style, reportType, true))); + } } return result.ToString(); } - private string getNextRecertDateString (string countString, Recertification recert) + private static string GetNextRecertDateString (string countString, Recertification recert) { string color = ""; string dateOnly = "-"; @@ -138,22 +151,22 @@ private string getNextRecertDateString (string countString, Recertification rece return "" + countString + dateOnly + "

"; } - private string getOwnerDisplayString (string countString, Recertification recert) + private static string GetOwnerDisplayString (string countString, Recertification recert) { return "

" + countString + (recert.FwoOwner != null && recert.FwoOwner?.Name != null ? recert.FwoOwner.Name : "") + "

"; } - private string getIpMatchDisplayString (string countString, Recertification recert) + private static string GetIpMatchDisplayString (string countString, Recertification recert) { return "

" + countString + (recert.IpMatch != null && recert.IpMatch != "" ? recert.IpMatch : "‐") + "

"; } - private string getLastRecertifierDisplayString (string countString, Recertification recert) + private static string GetLastRecertifierDisplayString (string countString, Recertification recert) { return "

" + countString + "

"; // TODO: fetch last recertifier } - private string countString(bool multipleOwners, int ownerCounter) + private static string CountString(bool multipleOwners, int ownerCounter) { return multipleOwners ? ownerCounter.ToString() + ". " : ""; } diff --git a/roles/lib/files/FWO.Report/Display/RuleDisplayJson.cs b/roles/lib/files/FWO.Report/Display/RuleDisplayJson.cs index 119b82fac..1a60c618d 100644 --- a/roles/lib/files/FWO.Report/Display/RuleDisplayJson.cs +++ b/roles/lib/files/FWO.Report/Display/RuleDisplayJson.cs @@ -106,7 +106,7 @@ protected string ListNetworkLocations(Rule rule, ReportType reportType, bool isS if (reportType.IsResolvedReport()) { List displayedLocations = new List(); - foreach (NetworkLocation networkLocation in getNetworkLocations(isSource ? rule.Froms : rule.Tos)) + foreach (NetworkLocation networkLocation in GetNetworkLocations(isSource ? rule.Froms : rule.Tos)) { displayedLocations.Add(Quote(DisplayNetworkLocation(networkLocation, reportType).ToString())); } diff --git a/roles/lib/files/FWO.Report/ReportAppRules.cs b/roles/lib/files/FWO.Report/ReportAppRules.cs new file mode 100644 index 000000000..3fb9e622d --- /dev/null +++ b/roles/lib/files/FWO.Report/ReportAppRules.cs @@ -0,0 +1,117 @@ +using FWO.Api.Client; +using FWO.Api.Client.Queries; +using FWO.Api.Data; +using FWO.Report.Filter; +using FWO.Config.Api; +using NetTools; +using System.Net; + +namespace FWO.Report +{ + public class ReportAppRules : ReportRules + { + private List ownerIps = []; + + public ReportAppRules(DynGraphqlQuery query, UserConfig userConfig, ReportType reportType) : base(query, userConfig, reportType) { } + + public override async Task Generate(int rulesPerFetch, ApiConnection apiConnection, Func callback, CancellationToken ct) + { + await base.Generate(rulesPerFetch, apiConnection, callback, ct); + await PrepareAppRulesReport(apiConnection); + } + + private async Task PrepareAppRulesReport(ApiConnection apiConnection) + { + await GetAppServers(apiConnection); + List relevantData = []; + foreach(var mgt in ReportData.ManagementData) + { + ManagementReport relevantMgt = new(); + foreach(var dev in mgt.Devices) + { + DeviceReport relevantDevice = new(); + if(dev.Rules != null) + { + relevantDevice.Rules = []; + foreach(var rule in dev.Rules) + { + (List relevantFroms, List disregardedFroms) = CheckNetworkObjects(rule.Froms); + (List relevantTos, List disregardedTos) = CheckNetworkObjects(rule.Tos); + + if(relevantFroms.Count > 0 || relevantTos.Count > 0) + { + rule.Froms = [.. relevantFroms]; + rule.Tos = [.. relevantTos]; + rule.DisregardedFroms = [.. disregardedFroms]; + rule.DisregardedTos = [.. disregardedTos]; + relevantDevice.Rules = [.. relevantDevice.Rules, rule]; + } + } + if(relevantDevice.Rules.Length > 0) + { + relevantMgt.Devices = [.. relevantMgt.Devices, relevantDevice]; + } + } + } + if(relevantMgt.Devices.Length > 0) + { + relevantData.Add(relevantMgt); + } + } + ReportData.ManagementData = relevantData; + } + + private async Task GetAppServers(ApiConnection apiConnection) + { + List appServers = await apiConnection.SendQueryAsync>(ModellingQueries.getAppServers, + new { appId = Query.SelectedOwner?.Id }); + ownerIps = [.. appServers.ConvertAll(s => new IPAddressRange(IPAddress.Parse(DisplayBase.StripOffNetmask(s.Ip)), + IPAddress.Parse(DisplayBase.StripOffNetmask(s.IpEnd != "" ? s.IpEnd : s.Ip))))]; + } + + private (List, List) CheckNetworkObjects(NetworkLocation[] objList) + { + List relevantObjects = []; + List disregardedObjects = []; + foreach(var obj in objList.Where(o => o.Object.IP != null)) + { + bool found = false; + foreach(var ownerIpRange in ownerIps) + { + if(ComplianceNetworkZone.OverlapExists(new IPAddressRange(IPAddress.Parse(DisplayBase.StripOffNetmask(obj.Object.IP)), + IPAddress.Parse(DisplayBase.StripOffNetmask(obj.Object.IpEnd != "" ? obj.Object.IpEnd : obj.Object.IP))), ownerIpRange)) + { + relevantObjects.Add(obj); + found = true; + break; + } + } + if(!found) + { + disregardedObjects.Add(obj); + } + } + return (relevantObjects, disregardedObjects); + } + + // public override string SetDescription() + // { + // return ""; + // } + + // public override string ExportToJson() + // { + // return ""; + // } + + // public override string ExportToHtml() + // { + // return ""; + // } + + // public override string ExportToCsv() + // { + // return ""; + // } + } +} diff --git a/roles/lib/files/FWO.Report/ReportBase.cs b/roles/lib/files/FWO.Report/ReportBase.cs index 2cc7eaa28..5c30c4413 100644 --- a/roles/lib/files/FWO.Report/ReportBase.cs +++ b/roles/lib/files/FWO.Report/ReportBase.cs @@ -139,6 +139,7 @@ public static ReportBase ConstructReport(ReportTemplate reportFilter, UserConfig ReportType.Recertification => new ReportRules(query, userConfig, repType), ReportType.UnusedRules => new ReportRules(query, userConfig, repType), ReportType.Connections => new ReportConnections(query, userConfig, repType), + ReportType.AppRules => new ReportAppRules(query, userConfig, repType), _ => throw new NotSupportedException("Report Type is not supported."), }; } diff --git a/roles/lib/files/FWO.Report/ReportChanges.cs b/roles/lib/files/FWO.Report/ReportChanges.cs index af18084c8..8b5abf0ab 100644 --- a/roles/lib/files/FWO.Report/ReportChanges.cs +++ b/roles/lib/files/FWO.Report/ReportChanges.cs @@ -101,7 +101,7 @@ public override string ExportToCsv() report.Append(ruleChangeDisplayCsv.DisplayEnabled(ruleChange)); report.Append(ruleChangeDisplayCsv.DisplayUid(ruleChange)); report.Append(ruleChangeDisplayCsv.DisplayComment(ruleChange)); - report = ruleChangeDisplayCsv.RemoveLastChars(report, 1); // remove last chars (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last chars (comma) report.AppendLine(""); } } @@ -231,21 +231,21 @@ private string ExportResolvedChangesToJson() report.Append(ruleChangeDisplayJson.DisplayEnabled(ruleChange)); report.Append(ruleChangeDisplayJson.DisplayUid(ruleChange)); report.Append(ruleChangeDisplayJson.DisplayComment(ruleChange)); - report = ruleChangeDisplayJson.RemoveLastChars(report, 1); // remove last chars (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last chars (comma) report.Append("},"); // EO ruleChange } // rules - report = ruleChangeDisplayJson.RemoveLastChars(report, 1); // remove last char (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last char (comma) report.Append(']'); // EO rules report.Append('}'); // EO gateway internal report.Append("},"); // EO gateway external } } // gateways - report = ruleChangeDisplayJson.RemoveLastChars(report, 1); // remove last char (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last char (comma) report.Append(']'); // EO gateways report.Append('}'); // EO management internal report.Append("},"); // EO management external } // managements - report = ruleChangeDisplayJson.RemoveLastChars(report, 1); // remove last char (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last char (comma) report.Append(']'); // EO managements report.Append('}'); // EO top diff --git a/roles/lib/files/FWO.Report/ReportDevicesBase.cs b/roles/lib/files/FWO.Report/ReportDevicesBase.cs index 6bc941189..f82d8de26 100644 --- a/roles/lib/files/FWO.Report/ReportDevicesBase.cs +++ b/roles/lib/files/FWO.Report/ReportDevicesBase.cs @@ -1,6 +1,5 @@ using FWO.Api.Client; using FWO.Api.Client.Queries; -using FWO.GlobalConstants; using FWO.Api.Data; using FWO.Report.Filter; using FWO.Config.Api; @@ -13,17 +12,19 @@ public abstract class ReportDevicesBase : ReportBase public ReportDevicesBase(DynGraphqlQuery query, UserConfig UserConfig, ReportType reportType) : base (query, UserConfig, reportType) {} - public async Task> getRelevantImportIds(ApiConnection apiConnection) + public async Task> GetRelevantImportIds(ApiConnection apiConnection) { - Dictionary ImpIdQueryVariables = new (); - ImpIdQueryVariables["time"] = Query.ReportTimeString != "" ? Query.ReportTimeString : DateTime.Now.ToString(DynGraphqlQuery.fullTimeFormat); - ImpIdQueryVariables["mgmIds"] = Query.RelevantManagementIds; + Dictionary ImpIdQueryVariables = new() + { + ["time"] = Query.ReportTimeString != "" ? Query.ReportTimeString : DateTime.Now.ToString(DynGraphqlQuery.fullTimeFormat), + ["mgmIds"] = Query.RelevantManagementIds + }; return await apiConnection.SendQueryAsync>(ReportQueries.getRelevantImportIdsAtTime, ImpIdQueryVariables); } public static async Task<(List unsupportedList, DeviceFilter reducedDeviceFilter)> GetUsageDataUnsupportedDevices(ApiConnection apiConnection, DeviceFilter deviceFilter) { - List unsupportedList = new (); + List unsupportedList = []; DeviceFilter reducedDeviceFilter = new (deviceFilter); foreach (ManagementSelect management in reducedDeviceFilter.Managements) { @@ -61,11 +62,11 @@ public override bool NoRuleFound() { foreach(var dev in mgmt.Devices) { - if(dev.Rules != null && dev.Rules.Count() > 0) + if(dev.Rules != null && dev.Rules.Length > 0) { return false; } - if(dev.RuleChanges != null && dev.RuleChanges.Count() > 0) + if(dev.RuleChanges != null && dev.RuleChanges.Length > 0) { return false; } diff --git a/roles/lib/files/FWO.Report/ReportNatRules.cs b/roles/lib/files/FWO.Report/ReportNatRules.cs index 554e6679e..7187f05c6 100644 --- a/roles/lib/files/FWO.Report/ReportNatRules.cs +++ b/roles/lib/files/FWO.Report/ReportNatRules.cs @@ -60,8 +60,8 @@ public override string ExportToHtml() report.AppendLine($"{ruleDisplay.DisplayTranslatedDestination(rule, OutputLocation.export)}"); report.AppendLine($"{ruleDisplay.DisplayTranslatedService(rule, OutputLocation.export)}"); report.AppendLine($"{ruleDisplay.DisplayEnabled(rule, OutputLocation.export)}"); - report.AppendLine($"{ruleDisplay.DisplayUid(rule)}"); - report.AppendLine($"{ruleDisplay.DisplayComment(rule)}"); + report.AppendLine($"{RuleDisplayBase.DisplayUid(rule)}"); + report.AppendLine($"{RuleDisplayBase.DisplayComment(rule)}"); report.AppendLine(""); } else diff --git a/roles/lib/files/FWO.Report/ReportRules.cs b/roles/lib/files/FWO.Report/ReportRules.cs index cdd572a12..e61707db2 100644 --- a/roles/lib/files/FWO.Report/ReportRules.cs +++ b/roles/lib/files/FWO.Report/ReportRules.cs @@ -24,7 +24,7 @@ public override async Task Generate(int rulesPerFetch, ApiConnection apiConnecti Query.QueryVariables["offset"] = 0; bool gotNewObjects = true; - List managementsWithRelevantImportId = await getRelevantImportIds(apiConnection); + List managementsWithRelevantImportId = await GetRelevantImportIds(apiConnection); ReportData.ManagementData = []; foreach(var management in managementsWithRelevantImportId) @@ -224,7 +224,7 @@ public override string ExportToCsv() report.Append(ruleDisplayCsv.DisplayEnabledCsv(rule)); report.Append(ruleDisplayCsv.DisplayUidCsv(rule)); report.Append(ruleDisplayCsv.DisplayCommentCsv(rule)); - report = ruleDisplayCsv.RemoveLastChars(report, 1); // remove last chars (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last chars (comma) report.AppendLine(""); // EO rule } else @@ -298,7 +298,7 @@ private string ExportResolvedRulesToJson() report.Append(ruleDisplayJson.DisplayEnabled(rule.Disabled)); report.Append(ruleDisplayJson.DisplayUid(rule.Uid)); report.Append(ruleDisplayJson.DisplayComment(rule.Comment)); - report = ruleDisplayJson.RemoveLastChars(report, 1); // remove last chars (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last chars (comma) } else { @@ -306,18 +306,18 @@ private string ExportResolvedRulesToJson() } report.Append("},"); // EO rule } // rules - report = ruleDisplayJson.RemoveLastChars(report, 1); // remove last char (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last char (comma) report.Append(']'); // EO rules report.Append('}'); // EO gateway internal report.Append("},"); // EO gateway external } } // gateways - report = ruleDisplayJson.RemoveLastChars(report, 1); // remove last char (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last char (comma) report.Append(']'); // EO gateways report.Append('}'); // EO management internal report.Append("},"); // EO management external } // managements - report = ruleDisplayJson.RemoveLastChars(report, 1); // remove last char (comma) + report = RuleDisplayBase.RemoveLastChars(report, 1); // remove last char (comma) report.Append(']'); // EO managements report.Append('}'); // EO top @@ -416,11 +416,11 @@ private void AppendRulesForDeviceHtml(ref StringBuilder report, DeviceReport dev report.AppendLine($"{ruleDisplayHtml.DisplayDestinationZone(rule)}"); report.AppendLine($"{ruleDisplayHtml.DisplayDestination(rule, OutputLocation.export, ReportType)}"); report.AppendLine($"{ruleDisplayHtml.DisplayServices(rule, OutputLocation.export, ReportType)}"); - report.AppendLine($"{ruleDisplayHtml.DisplayAction(rule)}"); - report.AppendLine($"{ruleDisplayHtml.DisplayTrack(rule)}"); + report.AppendLine($"{RuleDisplayBase.DisplayAction(rule)}"); + report.AppendLine($"{RuleDisplayBase.DisplayTrack(rule)}"); report.AppendLine($"{ruleDisplayHtml.DisplayEnabled(rule, OutputLocation.export)}"); - report.AppendLine($"{ruleDisplayHtml.DisplayUid(rule)}"); - report.AppendLine($"{ruleDisplayHtml.DisplayComment(rule)}"); + report.AppendLine($"{RuleDisplayBase.DisplayUid(rule)}"); + report.AppendLine($"{RuleDisplayBase.DisplayComment(rule)}"); report.AppendLine(""); } else diff --git a/roles/lib/files/FWO.Report/ReportStatistics.cs b/roles/lib/files/FWO.Report/ReportStatistics.cs index f1315231c..bbcb9683f 100644 --- a/roles/lib/files/FWO.Report/ReportStatistics.cs +++ b/roles/lib/files/FWO.Report/ReportStatistics.cs @@ -19,7 +19,7 @@ public ReportStatistics(DynGraphqlQuery query, UserConfig userConfig, ReportType public override async Task Generate(int _, ApiConnection apiConnection, Func callback, CancellationToken ct) { - List managementsWithRelevantImportId = await getRelevantImportIds(apiConnection); + List managementsWithRelevantImportId = await GetRelevantImportIds(apiConnection); ReportData.ManagementData = new (); diff --git a/roles/middleware/files/FWO.Middleware.Server/RecertCheck.cs b/roles/middleware/files/FWO.Middleware.Server/RecertCheck.cs index f2e6e0c98..0cc890809 100644 --- a/roles/middleware/files/FWO.Middleware.Server/RecertCheck.cs +++ b/roles/middleware/files/FWO.Middleware.Server/RecertCheck.cs @@ -21,10 +21,10 @@ public class RecertCheck { private readonly ApiConnection apiConnectionMiddlewareServer; private readonly GlobalConfig globalConfig; - private List groups = new (); - private List uiUsers = new (); + private readonly List groups = []; + private List uiUsers = []; private RecertCheckParams? globCheckParams; - private List owners = new (); + private List owners = []; /// /// Constructor for Recertification check class @@ -66,7 +66,7 @@ public async Task CheckRecertifications() { // todo: refine handling List upcomingRecerts = await GenerateRecertificationReport(apiConnectionReporter, owner, false); - List overdueRecerts = new (); // await GenerateRecertificationReport(apiConnectionReporter, owner, true); + List overdueRecerts = []; // await GenerateRecertificationReport(apiConnectionReporter, owner, true); if(upcomingRecerts.Count > 0 || overdueRecerts.Count > 0) { @@ -95,8 +95,8 @@ private async Task InitEnv() groups.AddRange(currentLdap.GetAllInternalGroups()); } } - uiUsers = await apiConnectionMiddlewareServer.SendQueryAsync>(FWO.Api.Client.Queries.AuthQueries.getUsers); - owners = await apiConnectionMiddlewareServer.SendQueryAsync>(FWO.Api.Client.Queries.OwnerQueries.getOwners); + uiUsers = await apiConnectionMiddlewareServer.SendQueryAsync>(AuthQueries.getUsers); + owners = await apiConnectionMiddlewareServer.SendQueryAsync>(OwnerQueries.getOwners); } private bool IsCheckTime(FwoOwner owner) @@ -163,7 +163,7 @@ private bool IsCheckTime(FwoOwner owner) private async Task> GenerateRecertificationReport(ApiConnection apiConnection, FwoOwner owner, bool overdueOnly) { - List rules = new (); + List rules = []; try { CancellationToken token = new (); @@ -179,7 +179,7 @@ private async Task> GenerateRecertificationReport(ApiConnection apiCo { RecertFilter = new() { - RecertOwnerList = new List() { owner.Id }, + RecertOwnerList = [owner.Id], RecertificationDisplayPeriod = globalConfig.RecertificationNoticePeriod } }; @@ -251,10 +251,10 @@ private List CollectEmailAddresses(FwoOwner owner) { if(globalConfig.UseDummyEmailAddress) { - return new() { globalConfig.DummyEmailAddress }; + return [globalConfig.DummyEmailAddress]; } - List tos = new (); - List userDns = new (); + List tos = []; + List userDns = []; if(owner.Dn != "") { userDns.Add(owner.Dn); diff --git a/roles/ui/files/FWO.UI/Pages/Compliance/ZonesChecks.razor b/roles/ui/files/FWO.UI/Pages/Compliance/ZonesChecks.razor index fe4bebc0b..f019ad24e 100644 --- a/roles/ui/files/FWO.UI/Pages/Compliance/ZonesChecks.razor +++ b/roles/ui/files/FWO.UI/Pages/Compliance/ZonesChecks.razor @@ -1,4 +1,4 @@ -@using NetTools; +@using NetTools @page "/compliance/zones/checks" @@ -68,7 +68,7 @@ IPAddressRange? destinationIpRange; bool displayOutput = false; bool compliant = false; - List<(ComplianceNetworkZone, ComplianceNetworkZone)> forbiddenCommunicationsOutput = new List<(ComplianceNetworkZone, ComplianceNetworkZone)>(); + List<(ComplianceNetworkZone, ComplianceNetworkZone)> forbiddenCommunicationsOutput = []; private void CheckIpRangeInputCompliance() { @@ -87,8 +87,8 @@ private bool CheckRuleCompliance(Rule rule, out List<(ComplianceNetworkZone, ComplianceNetworkZone)> forbiddenCommunication) { - List froms = new List(); - List tos = new List(); + List froms = []; + List tos = []; foreach (NetworkLocation networkLocation in rule.Froms) { @@ -112,7 +112,7 @@ // Determine all macthing destination zones List destinationZones = DetermineZones(destination); - forbiddenCommunication = new List<(ComplianceNetworkZone, ComplianceNetworkZone)>(); + forbiddenCommunication = []; foreach (ComplianceNetworkZone sourceZone in sourceZones) { @@ -131,7 +131,7 @@ private List DetermineZones(List ranges) { - List result = new List(); + List result = []; List> unseenIpAddressRanges = new List>(); for (int i = 0; i < ranges.Count; i++) @@ -168,7 +168,7 @@ private List ParseIpRange(NetworkObject networkObject) { - List ranges = new List(); + List ranges = []; if (networkObject.Type == new NetworkObjectType() { Name = ObjectType.IPRange }) { diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/Report.razor b/roles/ui/files/FWO.UI/Pages/Reporting/Report.razor index 4404504f7..68829b0b9 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/Report.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/Report.razor @@ -27,7 +27,7 @@ - @if (actReportFilters.ReportType==ReportType.Recertification) + @if (actReportFilters.ReportType == ReportType.Recertification) { } @@ -35,14 +35,14 @@ { } - else if(actReportFilters.ReportType==ReportType.UnusedRules) + else if(actReportFilters.ReportType == ReportType.UnusedRules) {
@(userConfig.GetText("unused_days"))
} - else + else if(actReportFilters.ReportType != ReportType.AppRules) {
@(userConfig.GetText("report_time"))
@@ -55,7 +55,7 @@ @if (actReportFilters.ReportType.IsDeviceRelatedReport()) { - @if (actReportFilters.ReportType != ReportType.Statistics) + @if (actReportFilters.ReportType != ReportType.Statistics && actReportFilters.ReportType != ReportType.AppRules) { } @@ -112,6 +112,7 @@ case ReportType.Recertification: case ReportType.UnusedRules: case ReportType.NatRules: + case ReportType.AppRules: break; @@ -212,6 +213,8 @@ private string filterFeedbackEnd = ""; private string filterInput = ""; + private bool resetToEmptyDevFilter = false; + private bool tenantFilteringAllowed => authenticationStateTask!.Result.User.IsInRole(Roles.ReporterViewAll) || authenticationStateTask!.Result.User.IsInRole(Roles.Admin) || authenticationStateTask!.Result.User.IsInRole(Roles.FwAdmin) || authenticationStateTask!.Result.User.IsInRole(Roles.Auditor); @@ -271,10 +274,30 @@ { actReportFilters.ReportType = newReportType; actReportFilters.SetDisplayedTimeSelection(); + AdjustDeviceSelection(); ResetReport(); StateHasChanged(); } + private void AdjustDeviceSelection() + { + if(actReportFilters.ReportType == ReportType.AppRules) + { + if(!actReportFilters.DeviceFilter.isAnyDeviceFilterSet()) + { + resetToEmptyDevFilter = true; + actReportFilters.DeviceFilter.applyFullDeviceSelection(true); + actReportFilters.SelectAll = false; + } + } + else if(resetToEmptyDevFilter && actReportFilters.DeviceFilter.areAllDevicesSelected()) + { + resetToEmptyDevFilter = false; + actReportFilters.DeviceFilter.applyFullDeviceSelection(false); + actReportFilters.SelectAll = true; + } + } + private void ResetReport() { // clear report data when switching reportType as we would be missing src/dst/svc information in some cases @@ -333,17 +356,17 @@ try { - if(currentReport.ReportType.IsModellingReport()) + if(currentReport!.ReportType == ReportType.Connections) { await GenerateConnectionsReport(token); } - else if(currentReport.ReportType == ReportType.Statistics) + else if(currentReport!.ReportType == ReportType.Statistics) { await GenerateStatisticsReport(token); } else { - await currentReport.Generate(userConfig.ElementsPerFetch, apiConnection, + await currentReport!.Generate(userConfig.ElementsPerFetch, apiConnection, managementsReportIntermediate => { currentReport.ReportData.ManagementData = managementsReportIntermediate.ManagementData; @@ -557,7 +580,8 @@ ReportType.Recertification, ReportType.Changes, ReportType.ResolvedChanges, ReportType.ResolvedChangesTech, ReportType.Statistics, - ReportType.Connections + ReportType.Connections, + ReportType.AppRules }; foreach (var reportType in orderedReportTypeList) { From 9fed77654087b31efbb04aefc0376145dbebb68c Mon Sep 17 00:00:00 2001 From: abarz722 Date: Sat, 8 Jun 2024 20:05:04 +0200 Subject: [PATCH 02/11] first fixes --- .../Display/RuleChangeDisplayHtml.cs | 33 ++++----- .../FWO.Report/Display/RuleDisplayHtml.cs | 5 +- roles/lib/files/FWO.Report/ReportAppRules.cs | 4 +- roles/lib/files/FWO.Report/ReportBase.cs | 14 ++-- .../lib/files/FWO.Report/ReportDevicesBase.cs | 4 +- roles/test/files/FWO.Test/ExportTest.cs | 68 +++++++++---------- 6 files changed, 69 insertions(+), 59 deletions(-) diff --git a/roles/lib/files/FWO.Report/Display/RuleChangeDisplayHtml.cs b/roles/lib/files/FWO.Report/Display/RuleChangeDisplayHtml.cs index 3d3154a78..bc1495f57 100644 --- a/roles/lib/files/FWO.Report/Display/RuleChangeDisplayHtml.cs +++ b/roles/lib/files/FWO.Report/Display/RuleChangeDisplayHtml.cs @@ -1,5 +1,4 @@ -using FWO.GlobalConstants; -using FWO.Api.Data; +using FWO.Api.Data; using FWO.Logging; using FWO.Config.Api; using FWO.Report; @@ -9,8 +8,8 @@ namespace FWO.Ui.Display { public class RuleChangeDisplayHtml : RuleDisplayHtml { - static string addedStyle = "color: green; text-decoration: bold;"; - static string deletedStyle = "color: red; text-decoration: line-through red;"; + static readonly string addedStyle = "color: green; text-decoration: bold;"; + static readonly string deletedStyle = "color: red; text-decoration: line-through red;"; public RuleChangeDisplayHtml(UserConfig userConfig) : base(userConfig) { } @@ -185,7 +184,9 @@ private string DisplayDiff(string oldElement, string newElement) private string DisplayArrayDiff(string oldElement, string newElement, bool oldNegated, bool newNegated) { if (oldElement == newElement) + { return oldElement; + } else { oldElement = oldElement.Replace("

", ""); @@ -194,18 +195,18 @@ private string DisplayArrayDiff(string oldElement, string newElement, bool oldNe newElement = newElement.Replace("

", ""); newElement = newElement.Replace("

", ""); newElement = newElement.Replace("\r\n", ""); - List unchanged = new List(); - List added = new List(); - List deleted = new List(); + List unchanged = []; + List added = []; + List deleted = []; if(oldNegated != newNegated) { - deleted.Add(setStyle(oldElement, deletedStyle)); - added.Add(setStyle(newElement, addedStyle)); + deleted.Add(SetStyle(oldElement, deletedStyle)); + added.Add(SetStyle(newElement, addedStyle)); } else { - string[] separatingStrings = { "
" }; + string[] separatingStrings = ["
"]; string[] oldAr = oldElement.Split(separatingStrings, System.StringSplitOptions.RemoveEmptyEntries); string[] newAr = newElement.Split(separatingStrings, System.StringSplitOptions.RemoveEmptyEntries); @@ -217,14 +218,14 @@ private string DisplayArrayDiff(string oldElement, string newElement, bool oldNe } else { - deleted.Add(setStyle(item, deletedStyle)); + deleted.Add(SetStyle(item, deletedStyle)); } } foreach (var item in newAr) { if (!oldAr.Contains(item)) { - added.Add(setStyle(item, addedStyle)); + added.Add(SetStyle(item, addedStyle)); } } } @@ -235,22 +236,22 @@ private string DisplayArrayDiff(string oldElement, string newElement, bool oldNe } } - private string OutputHtmlDeleted(string? input) + private static string OutputHtmlDeleted(string? input) { return input != null && input != "" ? $"

{input}

" : ""; } - private string OutputHtmlAdded(string? input) + private static string OutputHtmlAdded(string? input) { return input != null && input != "" ? $"

{input}

" : ""; } - private string setStyle(string input, string style) + private static string SetStyle(string input, string style) { return input.Replace("style=\"\"", $"style=\"{style}\""); } - private void ThrowErrorUnknowChangeAction(char action) + private static void ThrowErrorUnknowChangeAction(char action) { Log.WriteError("Unknown Change Action", $"found an unexpected change action [{action}]"); } diff --git a/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs b/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs index 48b5c53cc..32558b3d0 100644 --- a/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs +++ b/roles/lib/files/FWO.Report/Display/RuleDisplayHtml.cs @@ -82,7 +82,8 @@ public string DisplayLastHit(Rule rule) public string DisplayLastRecertifier(Rule rule) { int count = 0; - return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), recert => GetLastRecertifierDisplayString(CountString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); + return string.Join("", Array.ConvertAll(rule.Metadata.RuleRecertification.ToArray(), + recert => GetLastRecertifierDisplayString(CountString(rule.Metadata.RuleRecertification.Count > 1, ++count), recert).ToString())); } protected static string NetworkLocationToHtml(NetworkLocation networkLocation, int mgmtId, OutputLocation location, string style, ReportType reportType, bool disregarded = false) @@ -93,7 +94,7 @@ protected static string NetworkLocationToHtml(NetworkLocation networkLocation, i reportType.IsResolvedReport() || disregarded ? null : ReportDevicesBase.ConstructLink(ObjCatString.NwObj, ReportBase.GetIconClass(ObjCategory.nobj, networkLocation.Object.Type.Name), networkLocation.Object.Id, networkLocation.Object.Name, location, mgmtId, style) ).ToString(); - return $"{nwLocation}"; + return reportType.IsRuleReport() ? $"{nwLocation}" : nwLocation; } protected static string ServiceToHtml(NetworkService service, int mgmtId, OutputLocation location, string style, ReportType reportType) diff --git a/roles/lib/files/FWO.Report/ReportAppRules.cs b/roles/lib/files/FWO.Report/ReportAppRules.cs index 3fb9e622d..f16cb2e82 100644 --- a/roles/lib/files/FWO.Report/ReportAppRules.cs +++ b/roles/lib/files/FWO.Report/ReportAppRules.cs @@ -26,10 +26,10 @@ private async Task PrepareAppRulesReport(ApiConnection apiConnection) List relevantData = []; foreach(var mgt in ReportData.ManagementData) { - ManagementReport relevantMgt = new(); + ManagementReport relevantMgt = new(){Name = mgt.Name}; foreach(var dev in mgt.Devices) { - DeviceReport relevantDevice = new(); + DeviceReport relevantDevice = new(){Name = dev.Name}; if(dev.Rules != null) { relevantDevice.Rules = []; diff --git a/roles/lib/files/FWO.Report/ReportBase.cs b/roles/lib/files/FWO.Report/ReportBase.cs index 5c30c4413..2ffe6a524 100644 --- a/roles/lib/files/FWO.Report/ReportBase.cs +++ b/roles/lib/files/FWO.Report/ReportBase.cs @@ -74,6 +74,7 @@ public abstract class ReportBase

##Title##

##Date-of-Config##: ##GeneratedFor## (UTC)

##GeneratedOn##: ##Date## (UTC)

+

##OwnerFilters##

##OtherFilters##

##Filter##


@@ -175,13 +176,18 @@ protected string GenerateHtmlFrameBase(string title, string filter, DateTime dat HtmlTemplate = HtmlTemplate.Replace("

##Date-of-Config##: ##GeneratedFor## (UTC)

", ""); } - if(deviceFilter != null) + if (ownerFilter != null) { - HtmlTemplate = HtmlTemplate.Replace("##OtherFilters##", userConfig.GetText("devices") + ": " + deviceFilter); + HtmlTemplate = HtmlTemplate.Replace("##OwnerFilters##", userConfig.GetText("owners") + ": " + ownerFilter); + } + else + { + HtmlTemplate = HtmlTemplate.Replace("

##OwnerFilters##

", ""); } - else if (ownerFilter != null) + + if(deviceFilter != null) { - HtmlTemplate = HtmlTemplate.Replace("##OtherFilters##", userConfig.GetText("owners") + ": " + ownerFilter); + HtmlTemplate = HtmlTemplate.Replace("##OtherFilters##", userConfig.GetText("devices") + ": " + deviceFilter); } else { diff --git a/roles/lib/files/FWO.Report/ReportDevicesBase.cs b/roles/lib/files/FWO.Report/ReportDevicesBase.cs index f82d8de26..13de2f447 100644 --- a/roles/lib/files/FWO.Report/ReportDevicesBase.cs +++ b/roles/lib/files/FWO.Report/ReportDevicesBase.cs @@ -125,7 +125,9 @@ public static string ConstructLink(string type, string symbol, long id, string n protected string GenerateHtmlFrame(string title, string filter, DateTime date, StringBuilder htmlReport) { - return GenerateHtmlFrameBase(title, filter, date, htmlReport, string.Join("; ", Array.ConvertAll(ReportData.ManagementData.Where(mgt => !mgt.Ignore).ToArray(), m => m.NameAndDeviceNames()))); + return GenerateHtmlFrameBase(title, filter, date, htmlReport, + string.Join("; ", Array.ConvertAll(ReportData.ManagementData.Where(mgt => !mgt.Ignore).ToArray(), m => m.NameAndDeviceNames())), + Query.SelectedOwner?.Name); } } } diff --git a/roles/test/files/FWO.Test/ExportTest.cs b/roles/test/files/FWO.Test/ExportTest.cs index 9fe98cfab..f11134281 100644 --- a/roles/test/files/FWO.Test/ExportTest.cs +++ b/roles/test/files/FWO.Test/ExportTest.cs @@ -71,15 +71,15 @@ public void RulesGenerateHtml() "

TestDev

" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "
No.NameSource ZoneSourceDestination ZoneDestinationServicesActionTrackEnabledUidComment
1TestRule1srczn TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)
 TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)
dstzn TestIpRange (1.2.3.4-1.2.3.5) TestIpRange (1.2.3.4-1.2.3.5) TestService1 (443/TCP)acceptnoneYuid1comment1
2TestRule2not
 TestUser1@ TestIp1 (1.2.3.4/32)
 TestUser1@ TestIp2 (127.0.0.1/32)
not
 TestUser1@ TestIp1 (1.2.3.4/32)
 TestUser1@ TestIp2 (127.0.0.1/32)
not
 TestUser2@ TestIpRange (1.2.3.4-1.2.3.5)
not
 TestUser2@ TestIpRange (1.2.3.4-1.2.3.5)
not
 TestService2 (6666-7777/UDP)
denynoneYuid2:123comment2

" + "

Network Objects

" + @@ -122,15 +122,15 @@ public void ResolvedRulesGenerateHtml() "

TestDev

" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "
No.NameSource ZoneSourceDestination ZoneDestinationServicesActionTrackEnabledUidComment
1TestRule1srcznTestIp1 (1.2.3.4/32)
TestIp2 (127.0.0.1/32)
TestIp1 (1.2.3.4/32)
TestIp2 (127.0.0.1/32)
dstznTestIpRange (1.2.3.4-1.2.3.5)TestIpRange (1.2.3.4-1.2.3.5)TestService1 (443/TCP)acceptnoneYuid1comment1
2TestRule2not
TestUser1@TestIp1 (1.2.3.4/32)
TestUser1@TestIp2 (127.0.0.1/32)
not
TestUser1@TestIp1 (1.2.3.4/32)
TestUser1@TestIp2 (127.0.0.1/32)
not
TestUser2@TestIpRange (1.2.3.4-1.2.3.5)
not
TestUser2@TestIpRange (1.2.3.4-1.2.3.5)
not
TestService2 (6666-7777/UDP)
denynoneYuid2:123comment2

" + ""; @@ -158,15 +158,15 @@ public void ResolvedRulesTechGenerateHtml() "

TestDev

" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "
No.NameSource ZoneSourceDestination ZoneDestinationServicesActionTrackEnabledUidComment
1TestRule1srczn1.2.3.4/32
127.0.0.1/32
1.2.3.4/32
127.0.0.1/32
dstzn1.2.3.4-1.2.3.51.2.3.4-1.2.3.5443/TCPacceptnoneYuid1comment1
2TestRule2not
TestUser1@1.2.3.4/32
TestUser1@127.0.0.1/32
not
TestUser1@1.2.3.4/32
TestUser1@127.0.0.1/32
not
TestUser2@1.2.3.4-1.2.3.5
not
TestUser2@1.2.3.4-1.2.3.5
not
6666-7777/UDP
denynoneYuid2:123comment2

" + ""; @@ -194,15 +194,15 @@ public void UnusedRulesGenerateHtml() "

TestDev

" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "" + "" + - "" + + "" + "" + - "" + + "" + "" + "
No.Last HitNameSource ZoneSourceDestination ZoneDestinationServicesActionTrackEnabledUidComment
12022-04-19TestRule1srczn TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)
 TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)
dstzn TestIpRange (1.2.3.4-1.2.3.5) TestIpRange (1.2.3.4-1.2.3.5) TestService1 (443/TCP)acceptnoneYuid1comment1
2TestRule2not
 TestUser1@ TestIp1 (1.2.3.4/32)
 TestUser1@ TestIp2 (127.0.0.1/32)
not
 TestUser1@ TestIp1 (1.2.3.4/32)
 TestUser1@ TestIp2 (127.0.0.1/32)
not
 TestUser2@ TestIpRange (1.2.3.4-1.2.3.5)
not
 TestUser2@ TestIpRange (1.2.3.4-1.2.3.5)
not
 TestService2 (6666-7777/UDP)
denynoneYuid2:123comment2

" + "

Network Objects

" + @@ -251,9 +251,9 @@ public void RecertReportGenerateHtml() "2022-04-19" + "TestRule1" + "srczn" + - " TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)" + + " TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)" + "dstzn" + - " TestIpRange (1.2.3.4-1.2.3.5)" + + " TestIpRange (1.2.3.4-1.2.3.5)" + " TestService1 (443/TCP)" + "accept" + "none" + @@ -267,9 +267,9 @@ public void RecertReportGenerateHtml() "" + "TestRule2" + "" + - "not
 TestUser1@ TestIp1 (1.2.3.4/32)
 TestUser1@ TestIp2 (127.0.0.1/32)" + + "not
 TestUser1@ TestIp1 (1.2.3.4/32)
 TestUser1@ TestIp2 (127.0.0.1/32)" + "" + - "not
 TestUser2@ TestIpRange (1.2.3.4-1.2.3.5)" + + "not
 TestUser2@ TestIpRange (1.2.3.4-1.2.3.5)" + "not
 TestService2 (6666-7777/UDP)" + "deny" + "none" + @@ -315,12 +315,12 @@ public void NatRulesGenerateHtml() "1" + "TestRule1" + "srczn" + - " TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)" + + " TestIp1 (1.2.3.4/32)
 TestIp2 (127.0.0.1/32)" + "dstzn" + - " TestIpRange (1.2.3.4-1.2.3.5)" + + " TestIpRange (1.2.3.4-1.2.3.5)" + " TestService1 (443/TCP)" + - " TestUser2@ TestIp1Changed (2.3.4.5)" + - "not
 TestIp1Changed (2.3.4.5)
 TestIpNew (10.0.6.0/24)" + + " TestUser2@ TestIp1Changed (2.3.4.5)" + + "not
 TestIp1Changed (2.3.4.5)
 TestIpNew (10.0.6.0/24)" + " TestService1 (443/TCP)
 TestService2 (6666-7777/UDP)" + "Y" + "uid1" + @@ -721,7 +721,7 @@ public void RulesGenerateJson() "\"usr\": {\"user_id\": 0,\"user_uid\": \"\",\"user_name\": \"\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"accept\",\"rule_track\": \"none\",\"section_header\": \"\"," + "\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": \"2022-04-19T00:00:00\",\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + - "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []},\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\"}," + + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []},\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []}," + "{\"rule_id\": 0,\"rule_uid\": \"uid2:123\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule2\",\"rule_comment\": \"comment2\",\"rule_disabled\": false," + "\"rule_services\": [{\"service\": {\"svc_id\": 2,\"svc_name\": \"TestService2\",\"svc_uid\": \"\",\"svc_port\": 6666,\"svc_port_end\": 7777,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0," + "\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"UDP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + @@ -735,7 +735,7 @@ public void RulesGenerateJson() "\"usr\": {\"user_id\": 2,\"user_uid\": \"\",\"user_name\": \"TestUser2\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"group\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"deny\",\"rule_track\": \"none\",\"section_header\": \"\"," + "\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + - "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []},\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\"}],\"changelog_rules\": null,\"rules_aggregate\": {\"aggregate\": {\"count\": 0}}}]," + + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []},\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []}],\"changelog_rules\": null,\"rules_aggregate\": {\"aggregate\": {\"count\": 0}}}]," + "\"import\": {\"aggregate\": {\"max\": {\"id\": null}}},\"RelevantImportId\": null," + "\"networkObjects\": [],\"serviceObjects\": [],\"userObjects\": []," + "\"reportNetworkObjects\": [{\"obj_id\": 1,\"obj_name\": \"TestIp1\",\"obj_ip\": \"1.2.3.4/32\",\"obj_ip_end\": \"1.2.3.4/32\",\"obj_uid\": \"\",\"zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"active\": false,\"obj_create\": 0,\"obj_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"obj_last_seen\": 0,\"type\": {\"name\": \"network\"},\"obj_comment\": \"\",\"obj_member_names\": \"\",\"obj_member_refs\": \"\",\"objgrps\": [],\"objgrp_flats\": []}," + @@ -822,7 +822,7 @@ public void ChangesGenerateJson() "\"rule_services\": [],\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_src_neg\": false,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"dst_zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"rule_tos\": [],\"rule_action\": \"\",\"rule_track\": \"\",\"section_header\": \"\"," + "\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 0,\"Certified\": false,\"DeviceName\": \"\"},\"new\": {\"rule_id\": 0,\"rule_uid\": \"uid1\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule1\",\"rule_comment\": \"comment1\",\"rule_disabled\": false," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 0,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"new\": {\"rule_id\": 0,\"rule_uid\": \"uid1\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule1\",\"rule_comment\": \"comment1\",\"rule_disabled\": false," + "\"rule_services\": [{\"service\": {\"svc_id\": 1,\"svc_name\": \"TestService1\",\"svc_uid\": \"\",\"svc_port\": 443,\"svc_port_end\": 443,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"TCP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + "\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_src_neg\": false,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"srczn\"}," + "\"rule_froms\": [{\"object\": {\"obj_id\": 1,\"obj_name\": \"TestIp1\",\"obj_ip\": \"1.2.3.4/32\",\"obj_ip_end\": \"1.2.3.4/32\",\"obj_uid\": \"\",\"zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"active\": false,\"obj_create\": 0,\"obj_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"obj_last_seen\": 0,\"type\": {\"name\": \"network\"},\"obj_comment\": \"\",\"obj_member_names\": \"\",\"obj_member_refs\": \"\",\"objgrps\": [],\"objgrp_flats\": []}," + @@ -833,7 +833,7 @@ public void ChangesGenerateJson() "\"usr\": {\"user_id\": 0,\"user_uid\": \"\",\"user_name\": \"\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"accept\",\"rule_track\": \"none\",\"section_header\": \"\",\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": \"2022-04-19T00:00:00\",\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\"},\"DeviceName\": \"\"}," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"DeviceName\": \"\"}," + "{\"import\": {\"time\": \"2023-04-05T12:00:00\"},\"change_action\": \"C\",\"old\": {\"rule_id\": 0,\"rule_uid\": \"uid1\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule1\",\"rule_comment\": \"comment1\",\"rule_disabled\": false," + "\"rule_services\": [{\"service\": {\"svc_id\": 1,\"svc_name\": \"TestService1\",\"svc_uid\": \"\",\"svc_port\": 443,\"svc_port_end\": 443,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"TCP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + "\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_src_neg\": false,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"srczn\"}," + @@ -844,7 +844,7 @@ public void ChangesGenerateJson() "\"usr\": {\"user_id\": 0,\"user_uid\": \"\",\"user_name\": \"\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"accept\",\"rule_track\": \"none\",\"section_header\": \"\",\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": \"2022-04-19T00:00:00\",\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\"},\"new\": {\"rule_id\": 0,\"rule_uid\": \"\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule1\",\"rule_comment\": \"new comment\",\"rule_disabled\": false," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"new\": {\"rule_id\": 0,\"rule_uid\": \"\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule1\",\"rule_comment\": \"new comment\",\"rule_disabled\": false," + "\"rule_services\": [{\"service\": {\"svc_id\": 1,\"svc_name\": \"TestService1\",\"svc_uid\": \"\",\"svc_port\": 443,\"svc_port_end\": 443,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"TCP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + "\"rule_svc_neg\": true,\"rule_svc\": \"\",\"rule_src_neg\": false,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"srczn\"},\"rule_froms\": [{\"object\": {\"obj_id\": 5,\"obj_name\": \"TestIp1Changed\",\"obj_ip\": \"2.3.4.5/32\",\"obj_ip_end\": \"2.3.4.5/32\",\"obj_uid\": \"\",\"zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"active\": false,\"obj_create\": 0,\"obj_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"obj_last_seen\": 0,\"type\": {\"name\": \"host\"},\"obj_comment\": \"\",\"obj_member_names\": \"\",\"obj_member_refs\": \"\",\"objgrps\": [],\"objgrp_flats\": []}," + "\"usr\": {\"user_id\": 0,\"user_uid\": \"\",\"user_name\": \"\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}},{\"object\": {\"obj_id\": 2,\"obj_name\": \"TestIp2\",\"obj_ip\": \"127.0.0.1/32\",\"obj_ip_end\": \"127.0.0.1/32\",\"obj_uid\": \"\",\"zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"active\": false,\"obj_create\": 0,\"obj_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"obj_last_seen\": 0,\"type\": {\"name\": \"network\"},\"obj_comment\": \"\",\"obj_member_names\": \"\",\"obj_member_refs\": \"\",\"objgrps\": [],\"objgrp_flats\": []}," + @@ -854,7 +854,7 @@ public void ChangesGenerateJson() "\"usr\": {\"user_id\": 0,\"user_uid\": \"\",\"user_name\": \"\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"accept\",\"rule_track\": \"none\",\"section_header\": \"\",\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": \"2022-04-19T00:00:00\",\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\"},\"DeviceName\": \"\"}," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 1,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"DeviceName\": \"\"}," + "{\"import\": {\"time\": \"2023-04-05T12:00:00\"},\"change_action\": \"C\",\"old\": {\"rule_id\": 0,\"rule_uid\": \"uid2:123\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule2\",\"rule_comment\": \"comment2\",\"rule_disabled\": false," + "\"rule_services\": [{\"service\": {\"svc_id\": 2,\"svc_name\": \"TestService2\",\"svc_uid\": \"\",\"svc_port\": 6666,\"svc_port_end\": 7777,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"UDP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + "\"rule_svc_neg\": true,\"rule_svc\": \"\",\"rule_src_neg\": true,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"\"}," + @@ -865,7 +865,7 @@ public void ChangesGenerateJson() "\"usr\": {\"user_id\": 2,\"user_uid\": \"\",\"user_name\": \"TestUser2\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"group\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"deny\",\"rule_track\": \"none\",\"section_header\": \"\",\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\"},\"new\": {\"rule_id\": 0,\"rule_uid\": \"uid2:123\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule2\",\"rule_comment\": \"comment2\",\"rule_disabled\": true," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"new\": {\"rule_id\": 0,\"rule_uid\": \"uid2:123\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule2\",\"rule_comment\": \"comment2\",\"rule_disabled\": true," + "\"rule_services\": [{\"service\": {\"svc_id\": 2,\"svc_name\": \"TestService2\",\"svc_uid\": \"\",\"svc_port\": 6666,\"svc_port_end\": 7777,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"UDP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + "\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_src_neg\": true,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"\"}," + "\"rule_froms\": [{\"object\": {\"obj_id\": 1,\"obj_name\": \"TestIp1\",\"obj_ip\": \"1.2.3.4/32\",\"obj_ip_end\": \"1.2.3.4/32\",\"obj_uid\": \"\",\"zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"active\": false,\"obj_create\": 0,\"obj_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"obj_last_seen\": 0,\"type\": {\"name\": \"network\"},\"obj_comment\": \"\",\"obj_member_names\": \"\",\"obj_member_refs\": \"\",\"objgrps\": [],\"objgrp_flats\": []}," + @@ -875,7 +875,7 @@ public void ChangesGenerateJson() "\"usr\": {\"user_id\": 2,\"user_uid\": \"\",\"user_name\": \"TestUser2\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"group\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"deny\",\"rule_track\": \"none\",\"section_header\": \"\",\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\"},\"DeviceName\": \"\"}," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"DeviceName\": \"\"}," + "{\"import\": {\"time\": \"2023-04-05T12:00:00\"},\"change_action\": \"D\",\"old\": {\"rule_id\": 0,\"rule_uid\": \"uid2:123\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"TestRule2\",\"rule_comment\": \"comment2\",\"rule_disabled\": false," + "\"rule_services\": [{\"service\": {\"svc_id\": 2,\"svc_name\": \"TestService2\",\"svc_uid\": \"\",\"svc_port\": 6666,\"svc_port_end\": 7777,\"svc_source_port\": null,\"svc_source_port_end\": null,\"svc_code\": \"\",\"svc_timeout\": null,\"svc_typ_id\": null,\"active\": false,\"svc_create\": 0,\"svc_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"svc_last_seen\": 0,\"service_type\": {\"name\": \"\"},\"svc_comment\": \"\",\"svc_color_id\": null,\"ip_proto_id\": null,\"protocol_name\": {\"id\": 0,\"name\": \"UDP\"},\"svc_member_names\": \"\",\"svc_member_refs\": \"\",\"svcgrps\": [],\"svcgrp_flats\": []}}]," + "\"rule_svc_neg\": true,\"rule_svc\": \"\",\"rule_src_neg\": true,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"\"}," + @@ -886,11 +886,11 @@ public void ChangesGenerateJson() "\"usr\": {\"user_id\": 2,\"user_uid\": \"\",\"user_name\": \"TestUser2\",\"user_comment\": \"\",\"user_lastname\": \"\",\"user_firstname\": \"\",\"usr_typ_id\": 0,\"type\": {\"usr_typ_name\": \"group\"},\"user_create\": 0,\"user_create_time\": {\"time\": \"0001-01-01T00:00:00\"},\"user_last_seen\": 0,\"user_member_names\": \"\",\"user_member_refs\": \"\",\"usergrps\": [],\"usergrp_flats\": []}}]," + "\"rule_action\": \"deny\",\"rule_track\": \"none\",\"section_header\": \"\",\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\"},\"new\": {\"rule_id\": 0,\"rule_uid\": \"\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"\",\"rule_comment\": \"\",\"rule_disabled\": false," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 2,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"new\": {\"rule_id\": 0,\"rule_uid\": \"\",\"mgm_id\": 0,\"rule_num_numeric\": 0,\"rule_name\": \"\",\"rule_comment\": \"\",\"rule_disabled\": false," + "\"rule_services\": [],\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_src_neg\": false,\"rule_src\": \"\",\"src_zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"dst_zone\": {\"zone_id\": 0,\"zone_name\": \"\"},\"rule_tos\": [],\"rule_action\": \"\",\"rule_track\": \"\",\"section_header\": \"\"," + "\"rule_metadatum\": {\"rule_metadata_id\": 0,\"rule_created\": null,\"rule_last_modified\": null,\"rule_first_hit\": null,\"rule_last_hit\": null,\"rule_last_certified\": null,\"rule_last_certifier_dn\": \"\",\"rule_to_be_removed\": false,\"rule_decert_date\": null,\"rule_recertification_comment\": \"\",\"recertification\": [],\"recert_history\": [],\"dev_id\": 0,\"rule_uid\": \"\",\"NextRecert\": \"0001-01-01T00:00:00\",\"LastCertifierName\": \"\",\"Recert\": false,\"Style\": \"\"}," + "\"translate\": {\"rule_svc_neg\": false,\"rule_svc\": \"\",\"rule_services\": [],\"rule_src_neg\": false,\"rule_src\": \"\",\"rule_froms\": [],\"rule_dst_neg\": false,\"rule_dst\": \"\",\"rule_tos\": []}," + - "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 0,\"Certified\": false,\"DeviceName\": \"\"},\"DeviceName\": \"\"}],\"rules_aggregate\": {\"aggregate\": {\"count\": 0}}}]," + + "\"owner_name\": \"\",\"owner_id\": null,\"matches\": \"\",\"dev_id\": 0,\"rule_custom_fields\": \"\",\"DisplayOrderNumber\": 0,\"Certified\": false,\"DeviceName\": \"\",\"DisregardedFroms\": [],\"DisregardedTos\": []},\"DeviceName\": \"\"}],\"rules_aggregate\": {\"aggregate\": {\"count\": 0}}}]," + "\"import\": {\"aggregate\": {\"max\": {\"id\": null}}},\"RelevantImportId\": null," + "\"networkObjects\": [],\"serviceObjects\": [],\"userObjects\": [],\"reportNetworkObjects\": [],\"reportServiceObjects\": [],\"reportUserObjects\": [],\"ReportedRuleIds\": [],\"ReportedNetworkServiceIds\": [],\"objects_aggregate\": {\"aggregate\": {\"count\": 0}}," + "\"services_aggregate\": {\"aggregate\": {\"count\": 0}},\"usrs_aggregate\": {\"aggregate\": {\"count\": 0}},\"rules_aggregate\": {\"aggregate\": {\"count\": 0}}," + From d0b9c5fe01e888630eadc993bb74b3358449336b Mon Sep 17 00:00:00 2001 From: abarz722 Date: Mon, 10 Jun 2024 13:22:07 +0200 Subject: [PATCH 03/11] fixes --- .../files/sql/idempotent/fworch-api-funcs.sql | 2 +- .../getTenantNetworkObjectDetails.graphql | 2 +- roles/lib/files/FWO.Report/ReportAppRules.cs | 6 +- roles/lib/files/FWO.Report/ReportRules.cs | 21 +++---- .../ui/files/FWO.UI/Shared/ObjectGroup.razor | 46 +++++++-------- .../ui/files/FWO.UI/Shared/RightSidebar.razor | 58 ++++++++----------- 6 files changed, 64 insertions(+), 71 deletions(-) diff --git a/roles/database/files/sql/idempotent/fworch-api-funcs.sql b/roles/database/files/sql/idempotent/fworch-api-funcs.sql index 84ff30a33..94fd59dc8 100644 --- a/roles/database/files/sql/idempotent/fworch-api-funcs.sql +++ b/roles/database/files/sql/idempotent/fworch-api-funcs.sql @@ -580,7 +580,7 @@ AS $function$ END IF; END IF; END; -$function$ +$function$; CREATE OR REPLACE FUNCTION get_rules_for_owner(device_row device, ownerid integer) RETURNS SETOF rule AS $$ diff --git a/roles/lib/files/FWO.Api.Client/APIcalls/networkObject/getTenantNetworkObjectDetails.graphql b/roles/lib/files/FWO.Api.Client/APIcalls/networkObject/getTenantNetworkObjectDetails.graphql index 935149b21..d4caa1d79 100644 --- a/roles/lib/files/FWO.Api.Client/APIcalls/networkObject/getTenantNetworkObjectDetails.graphql +++ b/roles/lib/files/FWO.Api.Client/APIcalls/networkObject/getTenantNetworkObjectDetails.graphql @@ -1,4 +1,4 @@ -query getNetworkObjectDetails( +query getTenantNetworkObjectDetails( $management_id: [Int!] $nwObjTyp: [String!] $nwObjUid: [String!] diff --git a/roles/lib/files/FWO.Report/ReportAppRules.cs b/roles/lib/files/FWO.Report/ReportAppRules.cs index f16cb2e82..b737b8d90 100644 --- a/roles/lib/files/FWO.Report/ReportAppRules.cs +++ b/roles/lib/files/FWO.Report/ReportAppRules.cs @@ -26,10 +26,10 @@ private async Task PrepareAppRulesReport(ApiConnection apiConnection) List relevantData = []; foreach(var mgt in ReportData.ManagementData) { - ManagementReport relevantMgt = new(){Name = mgt.Name}; + ManagementReport relevantMgt = new(){ Name = mgt.Name, Id = mgt.Id, Import = mgt.Import }; foreach(var dev in mgt.Devices) { - DeviceReport relevantDevice = new(){Name = dev.Name}; + DeviceReport relevantDevice = new(){ Name = dev.Name, Id = dev.Id }; if(dev.Rules != null) { relevantDevice.Rules = []; @@ -45,6 +45,7 @@ private async Task PrepareAppRulesReport(ApiConnection apiConnection) rule.DisregardedFroms = [.. disregardedFroms]; rule.DisregardedTos = [.. disregardedTos]; relevantDevice.Rules = [.. relevantDevice.Rules, rule]; + relevantMgt.ReportedRuleIds.Add(rule.Id); } } if(relevantDevice.Rules.Length > 0) @@ -55,6 +56,7 @@ private async Task PrepareAppRulesReport(ApiConnection apiConnection) } if(relevantMgt.Devices.Length > 0) { + relevantMgt.ReportedRuleIds = mgt.ReportedRuleIds.Distinct().ToList(); relevantData.Add(relevantMgt); } } diff --git a/roles/lib/files/FWO.Report/ReportRules.cs b/roles/lib/files/FWO.Report/ReportRules.cs index e61707db2..f9106cb1b 100644 --- a/roles/lib/files/FWO.Report/ReportRules.cs +++ b/roles/lib/files/FWO.Report/ReportRules.cs @@ -29,11 +29,7 @@ public override async Task Generate(int rulesPerFetch, ApiConnection apiConnecti ReportData.ManagementData = []; foreach(var management in managementsWithRelevantImportId) { - Query.QueryVariables["mgmId"] = management.Id; - if (ReportType != ReportType.Recertification) - { - Query.QueryVariables["relevantImportId"] = management.Import.ImportAggregate.ImportAggregateMax.RelevantImportId ?? -1 /* managment was not yet imported at that time */; - } + SetMgtQueryVars(management); ManagementReport managementReport = (await apiConnection.SendQueryAsync>(Query.FullQuery, Query.QueryVariables))[0]; managementReport.Import = management.Import; ReportData.ManagementData.Add(managementReport); @@ -50,11 +46,7 @@ public override async Task Generate(int rulesPerFetch, ApiConnection apiConnecti Query.QueryVariables["offset"] = (int)Query.QueryVariables["offset"] + rulesPerFetch; foreach(var management in managementsWithRelevantImportId) { - Query.QueryVariables["mgmId"] = management.Id; - if (ReportType != ReportType.Recertification) - { - Query.QueryVariables["relevantImportId"] = management.Import.ImportAggregate.ImportAggregateMax.RelevantImportId ?? -1; /* managment was not yet imported at that time */; - } + SetMgtQueryVars(management); ManagementReport? mgtToFill = ReportData.ManagementData.FirstOrDefault(m => m.Id == management.Id); if(mgtToFill != null) { @@ -66,6 +58,15 @@ public override async Task Generate(int rulesPerFetch, ApiConnection apiConnecti SetReportedRuleIds(); } + private void SetMgtQueryVars(ManagementReport management) + { + Query.QueryVariables["mgmId"] = management.Id; + if (ReportType != ReportType.Recertification) + { + Query.QueryVariables["relevantImportId"] = management.Import.ImportAggregate.ImportAggregateMax.RelevantImportId ?? -1; /* managment was not yet imported at that time */; + } + } + public override async Task GetObjectsInReport(int objectsPerFetch, ApiConnection apiConnection, Func callback) // to be called when exporting { bool gotAllObjects = true; //whether the fetch count limit was reached during fetching diff --git a/roles/ui/files/FWO.UI/Shared/ObjectGroup.razor b/roles/ui/files/FWO.UI/Shared/ObjectGroup.razor index 906607f9e..f5b725e2b 100644 --- a/roles/ui/files/FWO.UI/Shared/ObjectGroup.razor +++ b/roles/ui/files/FWO.UI/Shared/ObjectGroup.razor @@ -23,7 +23,7 @@ @if (typeof(InputDataType) == typeof(Rule)) { Rule rule = (Rule)(Object)Content; - @($"{rule.DeviceName} - Rule ") + @($"{rule.DeviceName} - {userConfig.GetText("rule")} ") if (rule.Uid != null) { if (rule.Uid.Length > 5) @@ -283,9 +283,6 @@ [Parameter] public bool Reload { get; set; } = false; - // [Parameter] - // public Func>? AppServerExtractor { get; set; } - // Parameter Variables are being overwritten, because something happens with the component on StateHasChanged (but the Initialize Task does not get called) public InputDataType? Content { get; set; } @@ -393,46 +390,49 @@ { switch (Content) { - case ManagementReport m: + case ManagementReport mgt: await FetchObjects(Tab, objCategory, managementsUpdate => { - int id = m.Id; - ManagementReport? m_updated = managementsUpdate.ManagementData.FirstOrDefault(mgmt => mgmt.Id == m.Id); - if (m_updated != null) + ManagementReport? mgtUpdated = managementsUpdate.ManagementData.FirstOrDefault(m => m.Id == mgt.Id); + if (mgtUpdated != null) { switch (objCategory) { case ObjCategory.all: - m = m_updated; break; + mgt = mgtUpdated; + break; case ObjCategory.nobj: - m.Objects = m_updated.Objects; break; + mgt.Objects = mgtUpdated.Objects; + mgt.ReportObjects = mgtUpdated.ReportObjects; + break; case ObjCategory.nsrv: - m.Services = m_updated.Services; break; + mgt.Services = mgtUpdated.Services; + mgt.ReportServices = mgtUpdated.ReportServices; + break; case ObjCategory.user: - m.Users = m_updated.Users; break; + mgt.Users = mgtUpdated.Users; + mgt.ReportUsers = mgtUpdated.ReportUsers; + break; } - - Content = (InputDataType)(Object)m; + Content = (InputDataType)(Object)mgt; } return InvokeAsync(StateHasChanged); - }, m.Id, false); - + }, mgt.Id, false); break; - case Rule r: + case Rule rule: await FetchObjects(Tab, objCategory, managementsUpdate => { - Rule? r_updated = managementsUpdate.ManagementData.SelectMany(m => m.Devices).SelectMany(d => d.Rules ?? new Rule[0]).FirstOrDefault(); - if (r_updated != null) + Rule? ruleUpdated = managementsUpdate.ManagementData.SelectMany(m => m.Devices).SelectMany(d => d.Rules ?? new Rule[0]).FirstOrDefault(); + if (ruleUpdated != null) { - r_updated.DeviceName = r.DeviceName; - Content = (InputDataType)(Object)r_updated; + ruleUpdated.DeviceName = rule.DeviceName; + Content = (InputDataType)(Object)ruleUpdated; } return InvokeAsync(StateHasChanged); - }, r.Id, !string.IsNullOrEmpty(r.NatData?.TranslatedSource)); - + }, rule.Id, !string.IsNullOrEmpty(rule.NatData?.TranslatedSource)); break; } } diff --git a/roles/ui/files/FWO.UI/Shared/RightSidebar.razor b/roles/ui/files/FWO.UI/Shared/RightSidebar.razor index a83c02463..9b77cdc31 100644 --- a/roles/ui/files/FWO.UI/Shared/RightSidebar.razor +++ b/roles/ui/files/FWO.UI/Shared/RightSidebar.razor @@ -8,7 +8,7 @@ @using FWO.Report.Filter @using FWO.Ui.Data -@inject ApiConnection Connection +@inject ApiConnection apiConnection @inject UserConfig userConfig @@ -68,7 +68,7 @@
} - @if(CurrentReport?.ReportData.OwnerData.Count > 0 && (CurrentReport?.ReportType.IsModellingReport() ?? false)) + @if(CurrentReport?.ReportData.OwnerData.Count > 0 && CurrentReport?.ReportType == ReportType.Connections) {
@@ -112,7 +112,7 @@ public ReportBase? CurrentReport { get; set; } [Parameter] - public List SelectedRules { get; set; } = new List(); + public List SelectedRules { get; set; } = []; [Parameter] public EventCallback> SelectedRulesChanged { get; set; } @@ -123,9 +123,9 @@ [Parameter] public ReportType SelectedReportType { get; set; } = ReportType.Rules; - private CollapseState collapseSidebarAll = new CollapseState(); - private CollapseState collapseSidebarReport = new CollapseState(); - private CollapseState collapseSidebarRule = new CollapseState(); + private CollapseState collapseSidebarAll = new (); + private CollapseState collapseSidebarReport = new (); + private CollapseState collapseSidebarRule = new (); private List managementsAllObjects = new (); private int intWidth { get { return Width; } set { Width = value; WidthChanged.InvokeAsync(Width);}} @@ -140,7 +140,7 @@ if(AllTabVisible) { PaginationVariables paginationVariables = new PaginationVariables() { Limit = 0, Offset = 0 }; - managementsAllObjects = await Connection.SendQueryAsync>(ObjectQueries.getAllObjectDetails, paginationVariables); + managementsAllObjects = await apiConnection.SendQueryAsync>(ObjectQueries.getAllObjectDetails, paginationVariables); await InvokeAsync(StateHasChanged); } } @@ -158,18 +158,17 @@ try { string query = ""; - Dictionary queryVars = new Dictionary(); + Dictionary queryVars = new Dictionary() + { + { "limit", userConfig.ElementsPerFetch }, + { "offset", 0 } + }; bool gotAllObjects = true; switch (rsbTab) { case RsbTab.all: - queryVars = new Dictionary() - { - { "management_id", (int) id }, - { "limit", userConfig.ElementsPerFetch }, - { "offset", 0 } - }; + queryVars.Add("management_id", (int) id); switch (objType) { case ObjCategory.all: @@ -188,33 +187,24 @@ await FetchObjects(query, queryVars, callback); break; case RsbTab.report: - queryVars = new Dictionary() - { - { "mgmIds", (int) id }, - { "limit", userConfig.ElementsPerFetch }, - { "offset", 0 } - }; + queryVars.Add("mgmIds", (int) id); if (CurrentReport != null) - gotAllObjects = await CurrentReport.GetObjectsForManagementInReport(queryVars, objType, userConfig.AutoFillRightSidebar ? int.MaxValue : userConfig.MaxInitialFetchesRightSidebar, Connection, callback); - + { + gotAllObjects = await CurrentReport.GetObjectsForManagementInReport(queryVars, objType, + userConfig.AutoFillRightSidebar ? int.MaxValue : userConfig.MaxInitialFetchesRightSidebar, apiConnection, callback); + } if (!gotAllObjects) + { DisplayMessageInUi(null, userConfig.GetText("object_fetch_warning"), userConfig.GetText("E0021"), true); + } break; case RsbTab.rule: - queryVars = new Dictionary() - { - { "rule_id", id }, - { "limit", userConfig.ElementsPerFetch }, - { "offset", (int)0 } - }; if(objType == ObjCategory.all) { - if (nat) - query = RuleQueries.getNatRuleDetails; - else - query = RuleQueries.getRuleDetails; + queryVars.Add("rule_id", id); + query = nat ? RuleQueries.getNatRuleDetails : RuleQueries.getRuleDetails; + await FetchObjects(query, queryVars, callback); } - await FetchObjects(query, queryVars, callback); break; } } @@ -235,7 +225,7 @@ while (newObjects && (++fetchCount <= userConfig.MaxInitialFetchesRightSidebar || userConfig.AutoFillRightSidebar)) { - List managementsCurrentFetch = await Connection.SendQueryAsync>(query, queryVars); + List managementsCurrentFetch = await apiConnection.SendQueryAsync>(query, queryVars); if (fetchCount == 1) { reportData.ManagementData = managementsCurrentFetch; From 5d3add87e5372cb10e89ea57d27b55e0576a55fc Mon Sep 17 00:00:00 2001 From: abarz722 Date: Wed, 12 Jun 2024 14:46:21 +0200 Subject: [PATCH 04/11] prevent creating reports with invalid owner --- .../files/FWO.Api.Client/Data/ReportFile.cs | 4 +- .../FWO.Api.Client/Data/ReportSchedule.cs | 6 +- .../FWO.Api.Client/Data/ReportTemplate.cs | 2 +- roles/lib/files/FWO.Api.Client/Data/UiUser.cs | 18 ++--- .../FWO.Middleware.Client/MiddlewareClient.cs | 67 +++++++++---------- .../AuthenticationTokenController.cs | 14 ++-- .../files/FWO.Middleware.Server/JwtWriter.cs | 23 ++++--- .../FWO.Middleware.Server/ReportScheduler.cs | 45 +++++++++---- .../FWO.Middleware.Server/UiUserHandler.cs | 5 +- .../FWO.UI/Pages/Reporting/Archive.razor | 4 +- .../Reporting/ReportTemplateComponent.razor | 25 +++---- .../FWO.UI/Pages/Reporting/Schedule.razor | 19 ++++-- .../FWO.UI/Pages/Settings/SettingsUsers.razor | 6 +- 13 files changed, 133 insertions(+), 105 deletions(-) diff --git a/roles/lib/files/FWO.Api.Client/Data/ReportFile.cs b/roles/lib/files/FWO.Api.Client/Data/ReportFile.cs index 6acde08c9..a4027ba28 100644 --- a/roles/lib/files/FWO.Api.Client/Data/ReportFile.cs +++ b/roles/lib/files/FWO.Api.Client/Data/ReportFile.cs @@ -18,13 +18,13 @@ public class ReportFile public DateTime GenerationDateEnd { get; set; } [JsonProperty("report_template"), JsonPropertyName("report_template")] - public ReportTemplate Template { get; set; } = new ReportTemplate(); + public ReportTemplate Template { get; set; } = new (); [JsonProperty("report_template_id"), JsonPropertyName("report_template_id")] public int TemplateId { get; set; } [JsonProperty("uiuser"), JsonPropertyName("uiuser")] - public UiUser Owner { get; set; } = new UiUser(); + public UiUser ReportOwningUser { get; set; } = new (); [JsonProperty("report_owner_id"), JsonPropertyName("report_owner_id")] public int OwnerId { get; set; } diff --git a/roles/lib/files/FWO.Api.Client/Data/ReportSchedule.cs b/roles/lib/files/FWO.Api.Client/Data/ReportSchedule.cs index 48ad3d7cd..5726826c3 100644 --- a/roles/lib/files/FWO.Api.Client/Data/ReportSchedule.cs +++ b/roles/lib/files/FWO.Api.Client/Data/ReportSchedule.cs @@ -12,7 +12,7 @@ public class ReportSchedule public string Name { get; set; } = ""; [JsonProperty("report_schedule_owner_user"), JsonPropertyName("report_schedule_owner_user")] - public UiUser Owner { get; set; } = new UiUser(); + public UiUser ScheduleOwningUser { get; set; } = new (); [JsonProperty("report_schedule_start_time"), JsonPropertyName("report_schedule_start_time")] public DateTime StartTime { get; set; } = DateTime.Now.AddSeconds(-DateTime.Now.Second); @@ -24,10 +24,10 @@ public class ReportSchedule public Interval RepeatInterval { get; set; } [JsonProperty("report_schedule_template"), JsonPropertyName("report_schedule_template")] - public ReportTemplate Template { get; set; } = new ReportTemplate(); + public ReportTemplate Template { get; set; } = new (); [JsonProperty("report_schedule_formats"), JsonPropertyName("report_schedule_formats")] - public List OutputFormat { get; set; } = new List(); + public List OutputFormat { get; set; } = []; [JsonProperty("report_schedule_active"), JsonPropertyName("report_schedule_active")] public bool Active { get; set; } = true; diff --git a/roles/lib/files/FWO.Api.Client/Data/ReportTemplate.cs b/roles/lib/files/FWO.Api.Client/Data/ReportTemplate.cs index f1af001cf..ac7d9c15c 100644 --- a/roles/lib/files/FWO.Api.Client/Data/ReportTemplate.cs +++ b/roles/lib/files/FWO.Api.Client/Data/ReportTemplate.cs @@ -18,7 +18,7 @@ public class ReportTemplate public string Comment { get; set; } = ""; [JsonProperty("report_template_owner"), JsonPropertyName("report_template_owner")] - public int Owner { get; set; } + public int TemplateOwningUserId { get; set; } [JsonProperty("report_filter"), JsonPropertyName("report_filter")] public string Filter { get; set; } = ""; diff --git a/roles/lib/files/FWO.Api.Client/Data/UiUser.cs b/roles/lib/files/FWO.Api.Client/Data/UiUser.cs index 8560fb44b..e9af44460 100644 --- a/roles/lib/files/FWO.Api.Client/Data/UiUser.cs +++ b/roles/lib/files/FWO.Api.Client/Data/UiUser.cs @@ -42,18 +42,18 @@ public class UiUser public bool PasswordMustBeChanged { get; set; } [JsonProperty("ldap_connection"), JsonPropertyName("ldap_connection")] - public UiLdapConnection LdapConnection { get; set;} = new UiLdapConnection(); + public UiLdapConnection LdapConnection { get; set;} = new (); public string Jwt { get; set; } = ""; - public List Roles { get; set; } = new(); - public List Groups { get; set; } = new(); - public List Ownerships { get; set; } = new(); + public List Roles { get; set; } = []; + public List Groups { get; set; } = []; + public List Ownerships { get; set; } = []; public UiUser() { - Tenant = new Tenant(); - LdapConnection = new UiLdapConnection(); + Tenant = new (); + LdapConnection = new (); } public UiUser(UiUser user) @@ -89,16 +89,16 @@ public UiUser(UserGetReturnParameters userGetReturnParameters) Lastname = userGetReturnParameters.Lastname; if (userGetReturnParameters.TenantId != 0) { - Tenant = new Tenant(){Id = userGetReturnParameters.TenantId}; + Tenant = new (){Id = userGetReturnParameters.TenantId}; } Language = userGetReturnParameters.Language; LastLogin = userGetReturnParameters.LastLogin; LastPasswordChange = userGetReturnParameters.LastPasswordChange; PasswordMustBeChanged = userGetReturnParameters.PwChangeRequired; - LdapConnection = new UiLdapConnection(){Id = userGetReturnParameters.LdapId}; + LdapConnection = new (){Id = userGetReturnParameters.LdapId}; } - public bool isInternal() + public bool IsInternal() { return new DistName(Dn).IsInternal(); } diff --git a/roles/lib/files/FWO.Middleware.Client/MiddlewareClient.cs b/roles/lib/files/FWO.Middleware.Client/MiddlewareClient.cs index 5ef6bf368..f0b9b4751 100644 --- a/roles/lib/files/FWO.Middleware.Client/MiddlewareClient.cs +++ b/roles/lib/files/FWO.Middleware.Client/MiddlewareClient.cs @@ -1,13 +1,8 @@ using RestSharp; using FWO.Middleware.RequestParameters; using RestSharp.Authenticators; -using RestSharp.Serializers.SystemTextJson; -using System.Text.Json; using RestSharp.Serializers.NewtonsoftJson; -using Newtonsoft.Json; using RestSharp.Serializers; -using System.Runtime.CompilerServices; -using System.Data; namespace FWO.Middleware.Client { @@ -25,7 +20,7 @@ public MiddlewareClient(string middlewareServerUri) private RestClient CreateRestClient(IAuthenticator? authenticator) { - RestClientOptions restClientOptions = new RestClientOptions(); + RestClientOptions restClientOptions = new (); restClientOptions.RemoteCertificateValidationCallback += (_, _, _, _) => true; restClientOptions.BaseUrl = new Uri(middlewareServerUri + "api/"); restClientOptions.Authenticator = authenticator; @@ -34,7 +29,7 @@ private RestClient CreateRestClient(IAuthenticator? authenticator) private void ConfigureRestClientSerialization(SerializerConfig config) { - JsonNetSerializer serializer = new JsonNetSerializer(); // Case insensivitive is enabled by default + JsonNetSerializer serializer = new (); // Case insensivitive is enabled by default config.UseSerializer(() => serializer); } @@ -45,201 +40,201 @@ public void SetAuthenticationToken(string jwt) public async Task> AuthenticateUser(AuthenticationTokenGetParameters parameters) { - RestRequest request = new RestRequest("AuthenticationToken/Get", Method.Post); + RestRequest request = new ("AuthenticationToken/Get", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> CreateInitialJWT() { - RestRequest request = new RestRequest("AuthenticationToken/Get", Method.Post); + RestRequest request = new ("AuthenticationToken/Get", Method.Post); request.AddJsonBody(new object()); return await restClient.ExecuteAsync(request); } public async Task> TestConnection(LdapGetUpdateParameters parameters) { - RestRequest request = new RestRequest("AuthenticationServer/TestConnection", Method.Get); + RestRequest request = new ("AuthenticationServer/TestConnection", Method.Get); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task>> GetLdaps() { - RestRequest request = new RestRequest("AuthenticationServer", Method.Get); + RestRequest request = new ("AuthenticationServer", Method.Get); request.AddJsonBody(new object()); return await restClient.ExecuteAsync>(request); } public async Task> AddLdap(LdapAddParameters parameters) { - RestRequest request = new RestRequest("AuthenticationServer", Method.Post); + RestRequest request = new ("AuthenticationServer", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> UpdateLdap(LdapGetUpdateParameters parameters) { - RestRequest request = new RestRequest("AuthenticationServer", Method.Put); + RestRequest request = new ("AuthenticationServer", Method.Put); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> DeleteLdap(LdapDeleteParameters parameters) { - RestRequest request = new RestRequest("AuthenticationServer", Method.Delete); + RestRequest request = new ("AuthenticationServer", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> ChangePassword(UserChangePasswordParameters parameters) { - RestRequest request = new RestRequest("User/EditPassword", Method.Patch); + RestRequest request = new ("User/EditPassword", Method.Patch); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task>> GetAllRoles() { - RestRequest request = new RestRequest("Role", Method.Get); + RestRequest request = new ("Role", Method.Get); return await restClient.ExecuteAsync>(request); } public async Task>> GetGroups(GroupGetParameters parameters) { - RestRequest request = new RestRequest("Group/Get", Method.Post); + RestRequest request = new ("Group/Get", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync>(request); } public async Task>> GetInternalGroups() { - RestRequest request = new RestRequest("Group", Method.Get); + RestRequest request = new ("Group", Method.Get); return await restClient.ExecuteAsync>(request); } public async Task>> GetUsers() { - RestRequest request = new RestRequest("User", Method.Get); + RestRequest request = new ("User", Method.Get); request.AddJsonBody(new object()); return await restClient.ExecuteAsync>(request); } public async Task>> GetLdapUsers(LdapUserGetParameters parameters) { - RestRequest request = new RestRequest("User/Get", Method.Post); + RestRequest request = new ("User/Get", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync>(request); } public async Task> AddUser(UserAddParameters parameters) { - RestRequest request = new RestRequest("User", Method.Post); + RestRequest request = new ("User", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> UpdateUser(UserEditParameters parameters) { - RestRequest request = new RestRequest("User", Method.Put); + RestRequest request = new ("User", Method.Put); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> SetPassword(UserResetPasswordParameters parameters) { - RestRequest request = new RestRequest("User/ResetPassword", Method.Patch); + RestRequest request = new ("User/ResetPassword", Method.Patch); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> DeleteUser(UserDeleteParameters parameters) { - RestRequest request = new RestRequest("User", Method.Delete); + RestRequest request = new ("User", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> AddGroup(GroupAddDeleteParameters parameters) { - RestRequest request = new RestRequest("Group", Method.Post); + RestRequest request = new ("Group", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> UpdateGroup(GroupEditParameters parameters) { - RestRequest request = new RestRequest("Group", Method.Put); + RestRequest request = new ("Group", Method.Put); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> DeleteGroup(GroupAddDeleteParameters parameters) { - RestRequest request = new RestRequest("Group", Method.Delete); + RestRequest request = new ("Group", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> AddUserToRole(RoleAddDeleteUserParameters parameters) { - RestRequest request = new RestRequest("Role/User", Method.Post); + RestRequest request = new ("Role/User", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> RemoveUserFromRole(RoleAddDeleteUserParameters parameters) { - RestRequest request = new RestRequest("Role/User", Method.Delete); + RestRequest request = new ("Role/User", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> AddUserToGroup(GroupAddDeleteUserParameters parameters) { - RestRequest request = new RestRequest("Group/User", Method.Post); + RestRequest request = new ("Group/User", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> RemoveUserFromGroup(GroupAddDeleteUserParameters parameters) { - RestRequest request = new RestRequest("Group/User", Method.Delete); + RestRequest request = new ("Group/User", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> RemoveUserFromAllEntries(UserDeleteAllEntriesParameters parameters) { - RestRequest request = new RestRequest("User/AllGroupsAndRoles", Method.Delete); + RestRequest request = new ("User/AllGroupsAndRoles", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task>> GetTenants() { - RestRequest request = new RestRequest("Tenant", Method.Get); + RestRequest request = new ("Tenant", Method.Get); request.AddJsonBody(new object()); return await restClient.ExecuteAsync>(request); } public async Task> AddTenant(TenantAddParameters parameters) { - RestRequest request = new RestRequest("Tenant", Method.Post); + RestRequest request = new ("Tenant", Method.Post); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> UpdateTenant(TenantEditParameters parameters) { - RestRequest request = new RestRequest("Tenant", Method.Put); + RestRequest request = new ("Tenant", Method.Put); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } public async Task> DeleteTenant(TenantDeleteParameters parameters) { - RestRequest request = new RestRequest("Tenant", Method.Delete); + RestRequest request = new ("Tenant", Method.Delete); request.AddJsonBody(parameters); return await restClient.ExecuteAsync(request); } diff --git a/roles/middleware/files/FWO.Middleware.Server/Controllers/AuthenticationTokenController.cs b/roles/middleware/files/FWO.Middleware.Server/Controllers/AuthenticationTokenController.cs index f7fcb3c16..6a5739e9e 100644 --- a/roles/middleware/files/FWO.Middleware.Server/Controllers/AuthenticationTokenController.cs +++ b/roles/middleware/files/FWO.Middleware.Server/Controllers/AuthenticationTokenController.cs @@ -59,7 +59,7 @@ public async Task> GetAsync([FromBody] AuthenticationTokenG user = new UiUser { Name = username, Password = password }; } - AuthManager authManager = new AuthManager(jwtWriter, ldaps, apiConnection); + AuthManager authManager = new (jwtWriter, ldaps, apiConnection); // Authenticate user string jwt = await authManager.AuthorizeUserAsync(user, validatePassword: true); @@ -94,8 +94,8 @@ public async Task> GetAsyncForUser([FromBody] Authenticatio string targetUserName = parameters.TargetUserName; string targetUserDn = parameters.TargetUserDn; - AuthManager authManager = new AuthManager(jwtWriter, ldaps, apiConnection); - UiUser adminUser = new UiUser() { Name = adminUsername, Password = adminPassword }; + AuthManager authManager = new (jwtWriter, ldaps, apiConnection); + UiUser adminUser = new() { Name = adminUsername, Password = adminPassword }; // Check if admin valids are valid try { @@ -112,7 +112,7 @@ public async Task> GetAsyncForUser([FromBody] Authenticatio // Check if username is valid and generate jwt try { - UiUser targetUser = new UiUser { Name = targetUserName, Dn = targetUserDn }; + UiUser targetUser = new() { Name = targetUserName, Dn = targetUserDn }; string jwt = await authManager.AuthorizeUserAsync(targetUser, validatePassword: false, lifetime); return Ok(jwt); } @@ -188,8 +188,8 @@ public async Task> GetGroups(LdapEntry ldapUser, Ldap ldap) List userGroups = ldap.GetGroups(ldapUser); if (!ldap.IsInternal()) { - object groupsLock = new object(); - List ldapRoleRequests = new List(); + object groupsLock = new (); + List ldapRoleRequests = []; foreach (Ldap currentLdap in ldaps) { @@ -198,7 +198,7 @@ public async Task> GetGroups(LdapEntry ldapUser, Ldap ldap) ldapRoleRequests.Add(Task.Run(() => { // Get groups from current Ldap - List currentGroups = currentLdap.GetGroups(new List() {ldapUser.Dn}); + List currentGroups = currentLdap.GetGroups([ldapUser.Dn]); lock (groupsLock) { currentGroups = Array.ConvertAll(currentGroups.ToArray(), x => "cn=" + x + "," + currentLdap.GroupSearchPath).ToList(); diff --git a/roles/middleware/files/FWO.Middleware.Server/JwtWriter.cs b/roles/middleware/files/FWO.Middleware.Server/JwtWriter.cs index 12e1cfdf7..90e779fce 100644 --- a/roles/middleware/files/FWO.Middleware.Server/JwtWriter.cs +++ b/roles/middleware/files/FWO.Middleware.Server/JwtWriter.cs @@ -35,9 +35,9 @@ public async Task CreateJWT(UiUser? user = null, TimeSpan? lifetime = nu else Log.WriteDebug("Jwt generation", "Generating empty JWT (startup)"); - JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); + JwtSecurityTokenHandler tokenHandler = new (); - UiUserHandler uiUserHandler = new UiUserHandler(CreateJWTMiddlewareServer()); + UiUserHandler uiUserHandler = new (CreateJWTMiddlewareServer()); // if lifetime was speciefied use it, otherwise use standard lifetime int jwtMinutesValid = (int)(lifetime?.TotalMinutes ?? await uiUserHandler.GetExpirationTime()); @@ -45,7 +45,7 @@ public async Task CreateJWT(UiUser? user = null, TimeSpan? lifetime = nu if (user != null) subject = SetClaims(await uiUserHandler.HandleUiUserAtLogin(user)); else - subject = SetClaims(new UiUser() { Name = "", Password = "", Dn = Roles.Anonymous, Roles = new List { Roles.Anonymous } }); + subject = SetClaims(new UiUser() { Name = "", Password = "", Dn = Roles.Anonymous, Roles = [Roles.Anonymous] }); // adding uiuser.uiuser_id as x-hasura-user-id to JWT // Create JWToken @@ -91,8 +91,8 @@ public string CreateJWTReporterViewall() private string CreateJWTInternal(string role) { - JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); - ClaimsIdentity subject = new ClaimsIdentity(); + JwtSecurityTokenHandler tokenHandler = new (); + ClaimsIdentity subject = new (); subject.AddClaim(new Claim("unique_name", role)); subject.AddClaim(new Claim("x-hasura-allowed-roles", JsonSerializer.Serialize(new string[] { role }), System.IdentityModel.Tokens.Jwt.JsonClaimValueTypes.JsonArray)); subject.AddClaim(new Claim("x-hasura-default-role", role)); @@ -114,7 +114,7 @@ private string CreateJWTInternal(string role) private static ClaimsIdentity SetClaims(UiUser user) { - ClaimsIdentity claimsIdentity = new ClaimsIdentity(); + ClaimsIdentity claimsIdentity = new (); claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, user.Name)); claimsIdentity.AddClaim(new Claim("x-hasura-user-id", user.DbId.ToString())); if (user.Dn != null && user.Dn.Length > 0) @@ -131,21 +131,22 @@ private static ClaimsIdentity SetClaims(UiUser user) } } claimsIdentity.AddClaim(new Claim("x-hasura-editable-owners", $"{{ {string.Join(",", user.Ownerships)} }}")); + AddRoleClaims(claimsIdentity, user); + return claimsIdentity; + } + private static void AddRoleClaims(ClaimsIdentity claimsIdentity, UiUser user) + { // we need to create an extra list because hasura only accepts an array of roles even if there is only one - List hasuraRolesList = new List(); - + List hasuraRolesList = []; foreach (string role in user.Roles) { claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, role)); // Frontend Roles hasuraRolesList.Add(role); // Hasura Roles } - // add hasura roles claim as array claimsIdentity.AddClaim(new Claim("x-hasura-allowed-roles", JsonSerializer.Serialize(hasuraRolesList.ToArray()), System.IdentityModel.Tokens.Jwt.JsonClaimValueTypes.JsonArray)); // Convert Hasura Roles to Array - claimsIdentity.AddClaim(new Claim("x-hasura-default-role", GetDefaultRole(user, hasuraRolesList))); - return claimsIdentity; } private static string GetDefaultRole(UiUser user, List hasuraRolesList) diff --git a/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs b/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs index 7eb08c1b1..441eed8db 100644 --- a/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs +++ b/roles/middleware/files/FWO.Middleware.Server/ReportScheduler.cs @@ -24,6 +24,8 @@ public class ReportScheduler private readonly string apiServerUri; private readonly ApiConnection apiConnectionScheduler; + private ApiConnection apiConnectionUserContext; + private UserConfig userConfig; private readonly GraphQlApiSubscription scheduledReportsSubscription; private readonly JwtWriter jwtWriter; @@ -64,7 +66,7 @@ private void OnScheduleUpdate(ReportSchedule[] scheduledReports) { lock (scheduledReportsLock) { - this.scheduledReports = scheduledReports.ToList(); + this.scheduledReports = [.. scheduledReports]; } } @@ -76,7 +78,7 @@ private void ApiExceptionHandler(Exception exception) private async void CheckSchedule(object? _, ElapsedEventArgs __) { - List reportGeneratorTasks = new (); + List reportGeneratorTasks = []; DateTime dateTimeNowRounded = RoundDown(DateTime.Now, CheckScheduleInterval); @@ -125,24 +127,22 @@ private Task GenerateReport(ReportSchedule reportSchedule, DateTime dateTimeNowR { try { - Log.WriteInfo("Report Scheduling", $"Generating scheduled report \"{reportSchedule.Name}\" with id \"{reportSchedule.Id}\" for user \"{reportSchedule.Owner.Name}\" with id \"{reportSchedule.Owner.DbId}\" ..."); + Log.WriteInfo("Report Scheduling", $"Generating scheduled report \"{reportSchedule.Name}\" with id \"{reportSchedule.Id}\" for user \"{reportSchedule.ScheduleOwningUser.Name}\" with id \"{reportSchedule.ScheduleOwningUser.DbId}\" ..."); + + if(!await InitUserEnvironment(reportSchedule)) + { + return; + } ReportFile reportFile = new () { Name = $"{reportSchedule.Name}_{dateTimeNowRounded.ToShortDateString()}", GenerationDateStart = DateTime.Now, TemplateId = reportSchedule.Template.Id, - OwnerId = reportSchedule.Owner.DbId, + OwnerId = reportSchedule.ScheduleOwningUser.DbId, Type = reportSchedule.Template.ReportParams.ReportType }; - // get uiuser roles + tenant - AuthManager authManager = new (jwtWriter, connectedLdaps, apiConnectionScheduler); - string jwt = await authManager.AuthorizeUserAsync(reportSchedule.Owner, validatePassword: false, lifetime: TimeSpan.FromDays(365)); - ApiConnection apiConnectionUserContext = new GraphQlApiConnection(apiServerUri, jwt); - GlobalConfig globalConfig = await GlobalConfig.ConstructAsync(jwt); - UserConfig userConfig = await UserConfig.ConstructAsync(globalConfig, apiConnectionUserContext, reportSchedule.Owner.DbId); - await apiConnectionUserContext.SendQueryAsync(ReportQueries.countReportSchedule, new { report_schedule_id = reportSchedule.Id }); await AdaptDeviceFilter(reportSchedule.Template.ReportParams, apiConnectionUserContext); @@ -164,7 +164,7 @@ await report.Generate(int.MaxValue, apiConnectionUserContext, await report.GetObjectsInReport(int.MaxValue, apiConnectionUserContext, _ => Task.CompletedTask); WriteReportFile(report, reportSchedule.OutputFormat, reportFile); await SaveReport(reportFile, report.SetDescription(), apiConnectionUserContext); - Log.WriteInfo("Report Scheduling", $"Scheduled report \"{reportSchedule.Name}\" with id \"{reportSchedule.Id}\" for user \"{reportSchedule.Owner.Name}\" with id \"{reportSchedule.Owner.DbId}\" successfully generated."); + Log.WriteInfo("Report Scheduling", $"Scheduled report \"{reportSchedule.Name}\" with id \"{reportSchedule.Id}\" for user \"{reportSchedule.ScheduleOwningUser.Name}\" with id \"{reportSchedule.ScheduleOwningUser.DbId}\" successfully generated."); } catch (Exception exception) { @@ -173,6 +173,27 @@ await report.Generate(int.MaxValue, apiConnectionUserContext, }, token); } + private async Task InitUserEnvironment(ReportSchedule reportSchedule) + { + AuthManager authManager = new (jwtWriter, connectedLdaps, apiConnectionScheduler); + string jwt = await authManager.AuthorizeUserAsync(reportSchedule.ScheduleOwningUser, validatePassword: false, lifetime: TimeSpan.FromDays(365)); + apiConnectionUserContext = new GraphQlApiConnection(apiServerUri, jwt); + GlobalConfig globalConfig = await GlobalConfig.ConstructAsync(jwt); + userConfig = await UserConfig.ConstructAsync(globalConfig, apiConnectionUserContext, reportSchedule.ScheduleOwningUser.DbId); + + if(((ReportType)reportSchedule.Template.ReportParams.ReportType).IsModellingReport()) + { + userConfig.User.Groups = reportSchedule.ScheduleOwningUser.Groups; + await UiUserHandler.GetOwnerships(apiConnectionUserContext, userConfig.User); + if(!userConfig.User.Ownerships.Contains(reportSchedule.Template.ReportParams.ModellingFilter.SelectedOwner.Id)) + { + Log.WriteDebug("Report Scheduling", "Report not generated as owner is not valid anymore."); + return false; + } + } + return true; + } + private static async Task GenerateConnectionsReport(ReportSchedule reportSchedule, ReportBase report, ApiConnection apiConnectionUser, CancellationToken token) { ModellingAppRole dummyAppRole = new(); diff --git a/roles/middleware/files/FWO.Middleware.Server/UiUserHandler.cs b/roles/middleware/files/FWO.Middleware.Server/UiUserHandler.cs index 0d4d12187..38369b46d 100644 --- a/roles/middleware/files/FWO.Middleware.Server/UiUserHandler.cs +++ b/roles/middleware/files/FWO.Middleware.Server/UiUserHandler.cs @@ -99,7 +99,10 @@ public async Task HandleUiUserAtLogin(UiUser user) return user; } - private static async Task GetOwnerships(ApiConnection apiConn, UiUser user) + /// + /// add the ownerships to the given user + /// + public static async Task GetOwnerships(ApiConnection apiConn, UiUser user) { try { diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor b/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor index c9ec3ca2b..cff6e0e50 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/Archive.razor @@ -19,7 +19,7 @@ @if (!Exporting) { - @if (context.Owner.DbId == userConfig.User.DbId || authenticationStateTask!.Result.User.IsInRole(Roles.Admin)) + @if (context.ReportOwningUser.DbId == userConfig.User.DbId || authenticationStateTask!.Result.User.IsInRole(Roles.Admin)) { } @@ -45,7 +45,7 @@ @(context.GenerationDateStart.ToString("yyyy-MM-dd HH:mm:ssK")) - + diff --git a/roles/ui/files/FWO.UI/Pages/Reporting/ReportTemplateComponent.razor b/roles/ui/files/FWO.UI/Pages/Reporting/ReportTemplateComponent.razor index a9c05d98d..0fd9c5663 100644 --- a/roles/ui/files/FWO.UI/Pages/Reporting/ReportTemplateComponent.razor +++ b/roles/ui/files/FWO.UI/Pages/Reporting/ReportTemplateComponent.razor @@ -15,7 +15,7 @@
@* only display buttons for manipulating a template, when it's the user's template or the user has admin role *@ - @if (template.Owner == userConfig.User.DbId || authenticationStateTask!.Result.User.IsInRole(Roles.Admin)) + @if (template.TemplateOwningUserId == userConfig.User.DbId || authenticationStateTask!.Result.User.IsInRole(Roles.Admin)) { @@ -26,7 +26,7 @@