From 88217297ec6bae4fb4c876631e521c52a5c07419 Mon Sep 17 00:00:00 2001 From: Tim Purschke Date: Mon, 5 Feb 2024 17:55:59 +0100 Subject: [PATCH 01/84] nsx importer start --- documentation/revision-history-develop.md | 3 + inventory/group_vars/all.yml | 2 +- .../files/sql/creation/fworch-fill-stm.sql | 5 + roles/database/files/upgrade/7.3.7.sql | 4 + .../files/importer/vmwareNSX/__init__.py | 0 .../importer/vmwareNSX/discovery_logging.conf | 41 ++++ .../files/importer/vmwareNSX/fwcommon.py | 101 ++++++++++ .../importer/vmwareNSX/nsx_application.py | 37 ++++ .../files/importer/vmwareNSX/nsx_base.py | 2 + .../files/importer/vmwareNSX/nsx_getter.py | 92 +++++++++ .../files/importer/vmwareNSX/nsx_network.py | 175 ++++++++++++++++++ .../files/importer/vmwareNSX/nsx_rule.py | 144 ++++++++++++++ .../files/importer/vmwareNSX/nsx_service.py | 134 ++++++++++++++ .../files/importer/vmwareNSX/nsx_zone.py | 15 ++ .../Pages/Settings/SettingsGateways.razor | 3 +- 15 files changed, 756 insertions(+), 2 deletions(-) create mode 100644 roles/database/files/upgrade/7.3.7.sql create mode 100644 roles/importer/files/importer/vmwareNSX/__init__.py create mode 100644 roles/importer/files/importer/vmwareNSX/discovery_logging.conf create mode 100644 roles/importer/files/importer/vmwareNSX/fwcommon.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_application.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_base.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_getter.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_network.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_rule.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_service.py create mode 100644 roles/importer/files/importer/vmwareNSX/nsx_zone.py diff --git a/documentation/revision-history-develop.md b/documentation/revision-history-develop.md index 3280dfb4d..9bf05abae 100644 --- a/documentation/revision-history-develop.md +++ b/documentation/revision-history-develop.md @@ -175,3 +175,6 @@ bugfix release: - common service handling - fixes credentials when installing without demo data - fix error with pdf creation on debian testing + +# 7.3.7 - 29.02.2024 DEVELOP +- adding firewall importer support for NSX diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml index 1c87fdf27..d2e2b81f5 100644 --- a/inventory/group_vars/all.yml +++ b/inventory/group_vars/all.yml @@ -1,5 +1,5 @@ ### general settings -product_version: "7.3.6" +product_version: "7.3.7" ansible_user: "{{ lookup('env', 'USER') }}" ansible_become_method: sudo ansible_python_interpreter: /usr/bin/python3 diff --git a/roles/database/files/sql/creation/fworch-fill-stm.sql b/roles/database/files/sql/creation/fworch-fill-stm.sql index 062deaeb2..3f0620453 100644 --- a/roles/database/files/sql/creation/fworch-fill-stm.sql +++ b/roles/database/files/sql/creation/fworch-fill-stm.sql @@ -338,6 +338,11 @@ insert into stm_dev_typ (dev_typ_id,dev_typ_name,dev_typ_version,dev_typ_manufac VALUES (24,'FortiOS Management','REST','Fortinet','',false,true,false) ON CONFLICT DO NOTHING; insert into stm_dev_typ (dev_typ_id,dev_typ_name,dev_typ_version,dev_typ_manufacturer,dev_typ_predef_svc,dev_typ_is_multi_mgmt,dev_typ_is_mgmt,is_pure_routing_device) VALUES (25,'Fortinet FortiOS Gateway','REST','Fortinet','',false,false,false) ON CONFLICT DO NOTHING; +insert into stm_dev_typ (dev_typ_id,dev_typ_name,dev_typ_version,dev_typ_manufacturer,dev_typ_predef_svc,dev_typ_is_multi_mgmt,dev_typ_is_mgmt,is_pure_routing_device) + VALUES (26,'NSX','REST','VMWare','',false,true,false) ON CONFLICT DO NOTHING; +insert into stm_dev_typ (dev_typ_id,dev_typ_name,dev_typ_version,dev_typ_manufacturer,dev_typ_predef_svc,dev_typ_is_multi_mgmt,dev_typ_is_mgmt,is_pure_routing_device) + VALUES (27,'NSX DFW Gateway','REST','VMWare','',false,false,false) ON CONFLICT DO NOTHING; + update stm_dev_typ set dev_typ_predef_svc= 'ANY;0;0;65535;1;other;simple diff --git a/roles/database/files/upgrade/7.3.7.sql b/roles/database/files/upgrade/7.3.7.sql new file mode 100644 index 000000000..d85bfaac2 --- /dev/null +++ b/roles/database/files/upgrade/7.3.7.sql @@ -0,0 +1,4 @@ +insert into stm_dev_typ (dev_typ_id,dev_typ_name,dev_typ_version,dev_typ_manufacturer,dev_typ_predef_svc,dev_typ_is_multi_mgmt,dev_typ_is_mgmt,is_pure_routing_device) + VALUES (26,'NSX','4ff','VMWare','',false,true,false) ON CONFLICT DO NOTHING; +insert into stm_dev_typ (dev_typ_id,dev_typ_name,dev_typ_version,dev_typ_manufacturer,dev_typ_predef_svc,dev_typ_is_multi_mgmt,dev_typ_is_mgmt,is_pure_routing_device) + VALUES (27,'NSX DFW Gateway','4ff','VMWare','',false,false,false) ON CONFLICT DO NOTHING; diff --git a/roles/importer/files/importer/vmwareNSX/__init__.py b/roles/importer/files/importer/vmwareNSX/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/roles/importer/files/importer/vmwareNSX/discovery_logging.conf b/roles/importer/files/importer/vmwareNSX/discovery_logging.conf new file mode 100644 index 000000000..139c55a9c --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/discovery_logging.conf @@ -0,0 +1,41 @@ +[loggers] +keys=root,discoveryDebugLogger +#keys=root,__main__ + +[handlers] +keys=consoleHandler,debugFileHandler + +[formatters] +keys=defaultFormatter,debugFileFormatter + +[logger_root] +level=DEBUG +handlers=consoleHandler + +[logger_discoveryDebugLogger] +#[logger___main__] +level=DEBUG +handlers=debugFileHandler +qualname=discoveryDebugLogger +#qualname=__main__ +propagate=0 + +[handler_consoleHandler] +class=StreamHandler +level=DEBUG +formatter=defaultFormatter +args=(sys.stderr,) + +[handler_debugFileHandler] +class=FileHandler +level=DEBUG +formatter=debugFileFormatter +args=('/tmp/fworch_discovery.log',) +# args=('/var/log/fworch/discovery.log',) + +[formatter_defaultFormatter] +format=%(levelname)s:%(name)s:%(message)s + +[formatter_debugFileFormatter] +format=%(asctime)s - %(name)s - %(levelname)s - %(message)s + diff --git a/roles/importer/files/importer/vmwareNSX/fwcommon.py b/roles/importer/files/importer/vmwareNSX/fwcommon.py new file mode 100644 index 000000000..87de87449 --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/fwcommon.py @@ -0,0 +1,101 @@ +import sys +from common import importer_base_dir +sys.path.append(importer_base_dir + "/paloaltomanagement2023ff") +from palo_service import normalize_svcobjects +from palo_application import normalize_application_objects +from palo_rule import normalize_access_rules +from palo_network import normalize_nwobjects +from palo_zone import normalize_zones +from palo_getter import login, update_config_with_palofw_api_call +from fwo_log import getFwoLogger +from palo_base import api_version_str + +def has_config_changed(full_config, mgm_details, force=False): + # dummy - may be filled with real check later on + return True + + +def get_config(config2import, full_config, current_import_id, mgm_details, limit=1000, force=False, jwt=''): + logger = getFwoLogger() + if full_config == {}: # no native config was passed in, so getting it from Azzure + parsing_config_only = False + else: + parsing_config_only = True + + if not parsing_config_only: # no native config was passed in, so getting it from Palo Firewall + apipwd = mgm_details["import_credential"]['secret'] + apiuser = mgm_details["import_credential"]['user'] + apihost = mgm_details["hostname"] + + vsys_objects = ["/Network/Zones", "/Objects/Addresses", "/Objects/Services", "/Objects/AddressGroups", "/Objects/ServiceGroups", "/Objects/Tags"] + predef_objects = ["/Objects/Applications"] + rulebase_names = ["/Policies/SecurityRules", "/Policies/NATRules"] + + for obj_path in vsys_objects: + full_config[obj_path] = [] + + for obj_path in predef_objects: + full_config[obj_path] = [] + + # login + key = login(apiuser, apipwd, apihost) + if key == None or key == "": + logger.error('Did not succeed in logging in to Palo API, no key returned.') + return 1 + + ## get objects: + base_url = "https://{apihost}/restapi/v{api_version_str}".format(apihost=apihost, api_version_str=api_version_str) + + vsys_name = "vsys1" # TODO - automate this hard-coded name + location = "vsys" # alternative: panorama-pushed + + for obj_path in vsys_objects: + update_config_with_palofw_api_call(key, base_url, full_config, obj_path + "?location={location}&vsys={vsys_name}".format(location=location, vsys_name=vsys_name), obj_type=obj_path) + + for obj_path in predef_objects: + update_config_with_palofw_api_call(key, base_url, full_config, obj_path + "?location={location}".format(location="predefined"), obj_type=obj_path) + + # users + + # get rules + full_config.update({'devices': {}}) + for device in mgm_details["devices"]: + dev_id = device['id'] + dev_name = device['local_rulebase_name'] + full_config['devices'].update({ dev_id: {} }) + + for obj_path in rulebase_names: + update_config_with_palofw_api_call( + key, base_url, full_config['devices'][device['id']], + obj_path + "?location={location}&vsys={vsys_name}".format(location="vsys", vsys_name=dev_name), + obj_type=obj_path) + + ################## + # now we normalize relevant parts of the raw config and write the results to config2import dict + + normalize_nwobjects(full_config, config2import, current_import_id, jwt=jwt, mgm_id=mgm_details['id']) + normalize_svcobjects(full_config, config2import, current_import_id) + normalize_application_objects(full_config, config2import, current_import_id) + # normalize_users(full_config, config2import, current_import_id, user_scope) + + # adding default any and predefined objects + any_nw_svc = {"svc_uid": "any_svc_placeholder", "svc_name": "any", "svc_comment": "Placeholder service.", + "svc_typ": "simple", "ip_proto": -1, "svc_port": 0, "svc_port_end": 65535, "control_id": current_import_id} + http_svc = {"svc_uid": "http_predefined_svc", "svc_name": "service-http", "svc_comment": "Predefined service", + "svc_typ": "simple", "ip_proto": 6, "svc_port": 80, "control_id": current_import_id} + https_svc = {"svc_uid": "https_predefined_svc", "svc_name": "service-https", "svc_comment": "Predefined service", + "svc_typ": "simple", "ip_proto": 6, "svc_port": 443, "control_id": current_import_id} + + config2import["service_objects"].append(any_nw_svc) + config2import["service_objects"].append(http_svc) + config2import["service_objects"].append(https_svc) + + any_nw_object = {"obj_uid": "any_obj_placeholder", "obj_name": "any", "obj_comment": "Placeholder object.", + "obj_typ": "network", "obj_ip": "0.0.0.0/0", "control_id": current_import_id} + config2import["network_objects"].append(any_nw_object) + + normalize_zones(full_config, config2import, current_import_id) + normalize_access_rules(full_config, config2import, current_import_id, mgm_details=mgm_details) + # normalize_nat_rules(full_config, config2import, current_import_id, jwt=jwt) + + return 0 diff --git a/roles/importer/files/importer/vmwareNSX/nsx_application.py b/roles/importer/files/importer/vmwareNSX/nsx_application.py new file mode 100644 index 000000000..4652fa0c6 --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_application.py @@ -0,0 +1,37 @@ +from fwo_const import list_delimiter +from fwo_log import getFwoLogger + + +def normalize_application_objects(full_config, config2import, import_id): + app_objects = [] + for app_orig in full_config["/Objects/Applications"]: + app_objects.append(parse_app(app_orig, import_id,config2import)) + config2import['service_objects'] += app_objects + + +def extract_base_app_infos(app_orig, import_id): + app = {} + if "@name" in app_orig: + app["svc_uid"] = app_orig["@name"] + app["svc_name"] = app_orig["@name"] + if "comment" in app_orig: + app["svc_comment"] = app_orig["comment"] + app["control_id"] = import_id + app["svc_typ"] = 'simple' + return app + + +def parse_app(app_orig, import_id,config2import): + svc = extract_base_app_infos(app_orig, import_id) + app_comment = '' + if 'category' in app_orig: + app_comment = "category: " + app_orig['category'] + if 'subcategory' in app_orig: + app_comment += ", " + "subcategory: " + app_orig['subcategory'] + if 'technology' in app_orig: + app_comment += ", " + "technology: " + app_orig['technology'] + if 'svc_comment' in svc: + svc['svc_comment'] += "; " + app_comment + else: + svc['svc_comment'] = app_comment + return svc diff --git a/roles/importer/files/importer/vmwareNSX/nsx_base.py b/roles/importer/files/importer/vmwareNSX/nsx_base.py new file mode 100644 index 000000000..e4a69e545 --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_base.py @@ -0,0 +1,2 @@ + +api_version_str="9.1" diff --git a/roles/importer/files/importer/vmwareNSX/nsx_getter.py b/roles/importer/files/importer/vmwareNSX/nsx_getter.py new file mode 100644 index 000000000..ae2c94b33 --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_getter.py @@ -0,0 +1,92 @@ +# library for API get functions +import base64 +from typing import Dict +from fwo_log import getFwoLogger +import requests.packages +import requests +import xmltodict, json +import fwo_globals +from fwo_exception import FwLoginFailed + + +def api_call(url, params = {}, headers = {}, data = {}, credentials = '', show_progress=False, method='get'): + logger = getFwoLogger() + result_type='xml' + request_headers = {'Content-Type': 'application/json'} + for header_key in headers: + request_headers[header_key] = headers[header_key] + if key != '': + request_headers["Authorization"] = 'Basic ' + '{credentials}'.format(key=key) + result_type='json' + + if method == "post": + response = requests.post(url, params=params, data=data, headers=request_headers, verify=fwo_globals.verify_certs) + elif method == "get": + response = requests.get(url, params=params, headers=request_headers, verify=fwo_globals.verify_certs) + else: + raise Exception("unknown HTTP method found in palo_getter") + + # error handling: + exception_text = '' + if response is None: + if 'password' in json.dumps(data): + exception_text = "error while sending api_call containing credential information to url '" + \ + str(url) + else: + exception_text = "error while sending api_call to url '" + str(url) + "' with payload '" + json.dumps( + data, indent=2) + "' and headers: '" + json.dumps(request_headers, indent=2) + if not response.ok: + exception_text = 'error code: {error_code}, error={error}'.format(error_code=response.status_code, error=response.content) + #logger.error(response.content) + if (len(response.content) == 0): + exception_text = 'empty response content' + + if exception_text != '': + raise Exception(exception_text) + + # no errors found + if result_type=='xml': + r = xmltodict.parse(response.content) + body_json = json.loads(json.dumps(r)) + elif result_type=='json': + body_json = json.loads(response.content) + if 'result' in body_json: + body_json = body_json['result'] + + else: + body_json = None + + return body_json + + +def login(apiuser, apipwd, apihost): + base_url = "https://{apihost}/api/?type=keygen&user={apiuser}&password={apipwd}".format(apihost=apihost, apiuser=apiuser, apipwd=apipwd) + try: + body = api_call(base_url, method="get", headers={}, data={}) + except Exception as e: + raise FwLoginFailed("Palo FW login to firewall=" + str(apihost) + " failed; Message: " + str(e)) from None + + if 'response' in body and 'result' in body['response'] and 'key' in body['response']['result'] and not body['response']['result']['key'] == None: + key = body['response']['result']['key'] + else: + raise FwLoginFailed("Palo FW login to firewall=" + str(apihost) + " failed") from None + + if fwo_globals.debug_level > 2: + logger = getFwoLogger() + logger.debug("Login successful. Received key: " + key) + + return key + + +def update_config_with_palofw_api_call(key, api_base_url, config, api_path, obj_type='generic', parameters={}, payload={}, show_progress=False, limit: int=1000, method="get"): + returned_new_data = True + + full_result = [] + result = api_call(api_base_url + api_path,key=key, params=parameters, data=payload, show_progress=show_progress, method=method) + if "entry" in result: + returned_new_data = len(result['entry'])>0 + else: + returned_new_data = False + if returned_new_data: + full_result.extend(result["entry"]) + config.update({obj_type: full_result}) diff --git a/roles/importer/files/importer/vmwareNSX/nsx_network.py b/roles/importer/files/importer/vmwareNSX/nsx_network.py new file mode 100644 index 000000000..252ba38cf --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_network.py @@ -0,0 +1,175 @@ +from asyncio.log import logger +from fwo_log import getFwoLogger +from fwo_const import list_delimiter +import ipaddress + + +def normalize_nwobjects(full_config, config2import, import_id, jwt=None, mgm_id=None): + logger = getFwoLogger() + nw_objects = [] + nw_tagged_groups = {} + for obj_orig in full_config["/Objects/Addresses"]: + nw_objects.append(parse_object(obj_orig, import_id, config2import, nw_objects)) + if 'tag' in obj_orig and 'member' in obj_orig['tag']: + logger.info("found simple network object with tags: " + obj_orig['@name']) + for t in obj_orig['tag']['member']: + collect_tag_information(nw_tagged_groups, "#"+t, obj_orig['@name']) + + for tag in nw_tagged_groups: + logger.info("handling nw_tagged_group: " + tag + " with members: " + list_delimiter.join(nw_tagged_groups[tag])) + obj = {} + obj["obj_name"] = tag + obj["obj_uid"] = tag + obj["obj_comment"] = 'dynamic group defined by tagging' + obj['control_id'] = import_id + obj['obj_typ'] = 'group' + members = nw_tagged_groups[tag] # parse_dynamic_object_group(obj_grp_orig, nw_tagged_groups) + obj['obj_members'] = list_delimiter.join(members) + obj['obj_member_refs'] = list_delimiter.join(members) + nw_objects.append(obj) + + for obj_grp_orig in full_config["/Objects/AddressGroups"]: + logger.info("found network group: " + obj_grp_orig['@name']) + obj_grp = extract_base_object_infos(obj_grp_orig, import_id, config2import, nw_objects) + obj_grp["obj_typ"] = "group" + if 'static' in obj_grp_orig and 'filter' in obj_grp_orig['static']: + obj_grp["obj_member_refs"], obj_grp["obj_member_names"] = parse_static_obj_group(obj_grp_orig, import_id, nw_objects, config2import) + if 'dynamic' in obj_grp_orig and 'filter' in obj_grp_orig['dynamic']: + members = parse_dynamic_object_group(obj_grp_orig, nw_tagged_groups) + obj_grp["obj_member_refs"] = list_delimiter.join(members) + obj_grp["obj_member_names"] = list_delimiter.join(members) + nw_objects.append(obj_grp) + if 'tag' in obj_grp_orig and 'member' in obj_grp_orig['tag']: + logger.info("found network group with tags: " + obj_grp_orig['@name']) + for t in obj_grp_orig['tag']['member']: + logger.info(" found tag " + t) + collect_tag_information(nw_tagged_groups, "#"+t, obj_grp_orig['@name']) + + config2import['network_objects'] = nw_objects + + +def parse_object(obj_orig, import_id, config2import, nw_objects): + obj = extract_base_object_infos(obj_orig, import_id, config2import, nw_objects) + obj['obj_ip'] = obj_orig['ip-netmask'] + if '/' in obj['obj_ip'] and not '/32' in obj['obj_ip']: + obj['obj_typ'] = 'network' + else: + obj['obj_typ'] = 'host' + return obj + + +def extract_base_object_infos(obj_orig, import_id, config2import, nw_objects): + obj = {} + obj["obj_name"] = obj_orig["@name"] + obj["obj_uid"] = obj_orig["@name"] + if 'description' in obj_orig: + obj["obj_comment"] = obj_orig["description"] + if 'tag' in obj_orig: + tag_list = ",".join(obj_orig["tag"]['member']) + if 'obj_comment' in obj: + obj["obj_comment"] += ("; tags: " + tag_list) + else: + obj["obj_comment"] = tag_list + obj['control_id'] = import_id + return obj + + +def parse_dynamic_object_group(orig_grp, nw_tagged_groups): + if "dynamic" in orig_grp: + if 'filter' in orig_grp['dynamic']: + if ' ' not in orig_grp['dynamic']['filter']: + # just a single tag + # add all nw objects with the tag to this group + tag = "#" + orig_grp['dynamic']['filter'][1:-1] + if tag in nw_tagged_groups: + return nw_tagged_groups[tag] + else: + # later: deal with more complex tagging (and/or) + return [] + return [] + + +def parse_static_obj_group(orig_grp, import_id, nw_objects, config2import, id = None): + refs = [] + names = [] + + if "static" in orig_grp and "member" in orig_grp["static"]: + for m in orig_grp['static']['member']: + names.append(m) + refs.append(m) + return list_delimiter.join(refs), list_delimiter.join(names) + + +def parse_obj_list(nw_obj_list, import_id, obj_list, id, type='network'): + refs = [] + names = [] + for obj_name in nw_obj_list: + names.append(obj_name) + refs.append(lookup_obj_uid(obj_name, obj_list, import_id, type=type)) + return list_delimiter.join(refs), list_delimiter.join(names) + + +def lookup_obj_uid(obj_name, obj_list, import_id, type='network'): + for o in obj_list: + if type=='network' and 'obj_name' in o: + if o['obj_name']==obj_name: + return o['obj_uid'] + elif type=='service' and 'svc_name' in o: + if o['svc_name']==obj_name: + return o['svc_uid'] + else: + logger.warning("could not find object name in object " + str(o)) + + # could not find existing obj in obj list, so creating new one + if type=='network': + refs, names = add_ip_obj([obj_name], obj_list, import_id) + return refs ## assuming only one object here + elif type=='service': + logger.warning("could not find service object " + str(obj_name)) + else: + logger.warning("unknown object type '" + type + "' for object " + str(obj_name)) + return None + + +def add_ip_obj(ip_list, obj_list, import_id): + refs = [] + names = [] + for ip in ip_list: + # TODO: lookup ip in network_objects and re-use + ip_obj = {} + ip_obj['obj_name'] = ip + ip_obj['obj_uid'] = ip_obj['obj_name'] + try: + ipaddress.ip_network(ip) + # valid ip + ip_obj['obj_ip'] = ip + except: + # no valid ip - asusming Tag + ip_obj['obj_ip'] = '0.0.0.0/0' + ip = '0.0.0.0/0' + ip_obj['obj_name'] = "#"+ip_obj['obj_name'] + ip_obj['obj_uid'] = ip_obj['obj_name'] + ip_obj['obj_type'] = 'simple' + ip_obj['obj_typ'] = 'host' + if "/" in ip: + ip_obj['obj_typ'] = 'network' + + if "-" in ip: # ip range + ip_obj['obj_typ'] = 'ip_range' + ip_range = ip.split("-") + ip_obj['obj_ip'] = ip_range[0] + ip_obj['obj_ip_end'] = ip_range[1] + + ip_obj['control_id'] = import_id + + obj_list.append(ip_obj) + refs.append(ip_obj['obj_uid']) + names.append(ip_obj['obj_name']) + return list_delimiter.join(refs), list_delimiter.join(names) + + +def collect_tag_information(tagged_groups, tag, obj_name): + if tag in tagged_groups.keys(): + tagged_groups[tag].append(obj_name) + else: + tagged_groups.update({tag: [obj_name]}) diff --git a/roles/importer/files/importer/vmwareNSX/nsx_rule.py b/roles/importer/files/importer/vmwareNSX/nsx_rule.py new file mode 100644 index 000000000..6071f5ef2 --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_rule.py @@ -0,0 +1,144 @@ +from palo_service import parse_svc_list +from palo_network import parse_obj_list +from fwo_log import getFwoLogger +from fwo_const import list_delimiter +import hashlib +import base64 + + +def make_hash_sha256(o): + hasher = hashlib.sha256() + hasher.update(repr(make_hashable(o)).encode()) + return base64.b64encode(hasher.digest()).decode() + + +def make_hashable(o): + if isinstance(o, (tuple, list)): + return tuple((make_hashable(e) for e in o)) + + if isinstance(o, dict): + return tuple(sorted((k,make_hashable(v)) for k,v in o.items())) + + if isinstance(o, (set, frozenset)): + return tuple(sorted(make_hashable(e) for e in o)) + + return o + + +def normalize_access_rules(full_config, config2import, import_id, mgm_details={}): + rules = [] + logger = getFwoLogger() + + nw_obj_names = [] + for o in config2import['network_objects']: + nw_obj_names.append(o["obj_name"]) + + for device in full_config["devices"]: + rule_number = 0 + for dev_id in full_config['devices'].keys(): + for rulebase in list(full_config['devices'][dev_id].keys()): + for rule_orig in full_config['devices'][dev_id][rulebase]: + rule = {'rule_src': 'any', 'rule_dst': 'any', 'rule_svc': 'any', + 'rule_src_refs': 'any_obj_placeholder', 'rule_dst_refs': 'any_obj_placeholder', + 'rule_src_neg': False, 'rule_dst_neg': False, + 'rule_svc_refs': 'any_svc_placeholder'} + if 'negate-source' in rule_orig and rule_orig['negate-source']=='yes': + rule["rule_src_neg"] = True + if 'negate-destination' in rule_orig and rule_orig['negate-destination']=='yes': + rule["rule_dst_neg"] = True + rule.update({ + "rule_svc_neg": False, # not possible to negate the svc field on Palo + "rulebase_name": rule_orig['@vsys'], + "rule_name": rule_orig['@name'], + 'rule_type': 'access', + 'rule_num': rule_number, + 'rule_installon': rule_orig['@vsys'], + 'parent_rule_id': None, + 'rule_time': None, + 'rule_implied': False, + 'rule_comment': None, + 'rule_track': 'None', + 'rule_uid': rule_orig['@uuid'], + 'rule_disabled': False, + 'control_id': import_id + }) + + if "action" in rule_orig: + if rule_orig['action']=='allow': + rule['rule_action'] = 'accept' + elif rule_orig['action']=='drop': + rule['rule_action'] = 'drop' + elif rule_orig['action']=='deny': + rule['rule_action'] = 'deny' + elif rule_orig['action']=='reset-client': + rule['rule_action'] = 'reject' + else: + logger.warning("found undefined action:" + str(rule_orig)) + else: # NAT rules + rule['rule_action'] = "accept" + rule['rule_type'] = 'nat' + + # TODO: should either duplicate the rule for each zone to zone pair + # or much better allow for n:m rule:zone mappings --> change of DB necessary + # instead we are just picking the last one!!! + for z in rule_orig['from']['member']: + rule.update({'rule_from_zone': z}) + for z in rule_orig['to']['member']: + rule.update({'rule_to_zone': z}) + + if 'disabled' in rule_orig and rule_orig['disabled']=='yes': + rule['rule_disabled'] = True + if 'log-start' in rule_orig: + if rule_orig['log-start']=='yes': + rule['rule_track'] = 'all start' + elif rule_orig['log-start']=='no': + rule['rule_track'] = 'None' + else: + logger.warning ("found undefined track:" + str(rule_orig)) + rule['rule_track'] = 'None' + else: + rule['rule_track'] = 'None' + + if "source" in rule_orig: + if 'member' in rule_orig["source"]: + source_objects = rule_orig["source"]["member"] + else: + source_objects = [rule_orig["service"]] + rule['rule_src_refs'], rule["rule_src"] = parse_obj_list(source_objects, import_id, config2import['network_objects'], rule["rule_uid"]) + else: + logger.warning("found undefined source in rule: " + str(rule_orig)) + + if "destination" in rule_orig: + if 'member' in rule_orig["destination"]: + destination_objects = rule_orig["destination"]["member"] + else: + destination_objects = [rule_orig["destination"]] + rule['rule_dst_refs'], rule["rule_dst"] = parse_obj_list(destination_objects, import_id, config2import['network_objects'], rule["rule_uid"]) + else: + logger.warning("found undefined destination in rule: " + str(rule_orig)) + + services = [] + if "service" in rule_orig: + if 'member' in rule_orig['service']: + services = rule_orig["service"]["member"] + else: + services = [rule_orig["service"]] + if services[0] == 'application-default' or services[0] == 'any': + services = [] + apps = [] + if 'application' in rule_orig: + # no services given but applications - parse apps + if 'member' in rule_orig['application']: + # apps = ['any'] ## TEMP before app parsing + apps = rule_orig["application"]["member"] + else: + apps = [rule_orig["application"]] + if apps[0] == 'any': + apps = [] + + rule['rule_svc_refs'], rule["rule_svc"] = parse_svc_list(apps + services, import_id, config2import['service_objects'], rule["rule_uid"], type='service') + + rule_number += 1 + rules.append(rule) + + config2import['rules'] += rules diff --git a/roles/importer/files/importer/vmwareNSX/nsx_service.py b/roles/importer/files/importer/vmwareNSX/nsx_service.py new file mode 100644 index 000000000..c8d932f7b --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_service.py @@ -0,0 +1,134 @@ +from fwo_const import list_delimiter +from fwo_log import getFwoLogger + + +def normalize_svcobjects(full_config, config2import, import_id): + svc_objects = [] + for svc_orig in full_config["/Objects/Services"]: + svc_objects.append(parse_svc(svc_orig, import_id,config2import)) + for svc_grp_orig in full_config["/Objects/ServiceGroups"]: + svc_grp = extract_base_svc_infos(svc_grp_orig, import_id) + svc_grp["svc_typ"] = "group" + svc_grp["svc_member_refs"] , svc_grp["svc_member_names"] = parse_svc_group(svc_grp_orig,config2import) + svc_objects.append(svc_grp) + config2import['service_objects'] += svc_objects + + +def parse_svc_group(orig_grp,config2import): + refs = [] + names = [] + if "dynamic" in orig_grp: + pass + if "static" in orig_grp and "member" in orig_grp["static"]: + for m in orig_grp['static']['member']: + names.append(m) + refs.append(m) + return list_delimiter.join(refs), list_delimiter.join(names) + + +def extract_base_svc_infos(svc_orig, import_id): + svc = {} + if "@name" in svc_orig: + svc["svc_uid"] = svc_orig["@name"] + svc["svc_name"] = svc_orig["@name"] + if "comment" in svc_orig: + svc["svc_comment"] = svc_orig["comment"] + svc["svc_timeout"] = None + svc["svc_color"] = None + svc["control_id"] = import_id + svc["svc_typ"] = 'simple' + return svc + + +def parse_svc(svc_orig, import_id,config2import): + svc = extract_base_svc_infos(svc_orig, import_id) + if 'protocol' in svc_orig: + proto_string = 'undefined' + if 'tcp' in svc_orig['protocol']: + svc["ip_proto"] = 6 + proto_string = 'tcp' + svc["svc_port"] = svc_orig['protocol']['tcp']['port'] + elif 'udp' in svc_orig['protocol']: + svc["ip_proto"] = 17 + proto_string = 'udp' + + if proto_string=='undefined': + svc["svc_name"] += " [Protocol \"" + str(svc_orig["protocol"]) + "\" not supported]" + else: + port_string = svc_orig['protocol'][proto_string]['port'] + if ',' in port_string: + svc["svc_typ"] = "group" + svc["svc_port"] = None + members = [] + for p in port_string.split(","): + hlp_svc = create_helper_service(p, proto_string, svc["svc_name"], import_id) + add_service(hlp_svc, config2import) + members.append(hlp_svc['svc_uid']) + svc["svc_members"] = list_delimiter.join(members) + svc["svc_member_refs"] = list_delimiter.join(members) + else: # just a single port (range) + extract_port_for_service(port_string, svc) + return svc + + +def add_service(svc, config2import): + config2import['service_objects'].append(svc) + + +def extract_port_for_service(port_string, svc): + if '-' in port_string: + port_range = port_string.split("-") + if len(port_range)==2: + svc["svc_port"] = port_range[0] + svc["svc_port_end"] = port_range[1] + else: + logger = getFwoLogger() + logger.warning("found strange port range with more than one hyphen: " + str(port_string)) + else: + svc["svc_port"] = port_string + + +def create_helper_service(ports, proto_string, parent_svc_name, import_id): + svc = { + "svc_name": parent_svc_name + "_" + proto_string + "_" + ports, + "svc_uid": parent_svc_name + "_" + proto_string + "_" + ports, + "svc_comment": "helper service for Palo Alto multiple port range object: " + parent_svc_name, + "control_id": import_id, + "svc_typ": 'simple' + } + + extract_port_for_service(ports, svc) + return svc + + +def parse_svc_list(nw_obj_list, import_id, obj_list, id, type='network'): + refs = [] + names = [] + for obj_name in nw_obj_list: + names.append(obj_name) + refs.append(lookup_svc_obj_uid(obj_name, obj_list, import_id, type=type)) + return list_delimiter.join(refs), list_delimiter.join(names) + + +def lookup_svc_obj_uid(obj_name, obj_list, import_id, type='network'): + logger = getFwoLogger() + for o in obj_list: + if type=='service' and 'svc_name' in o: + if o['svc_name']==obj_name: + return o['svc_uid'] + else: + logger.warning("could not find object name in object " + str(o)) + + # could not find existing obj in obj list, so creating new one + return add_svc_obj(obj_name, obj_list, import_id) + + +def add_svc_obj(svc_in, svc_list, import_id): + svc_obj = {} + svc_obj['svc_name'] = "#" + svc_in + svc_obj['svc_uid'] = "#" + svc_in + svc_obj['control_id'] = import_id + svc_obj['svc_typ'] = 'simple' + + svc_list.append(svc_obj) + return svc_obj['svc_name'] diff --git a/roles/importer/files/importer/vmwareNSX/nsx_zone.py b/roles/importer/files/importer/vmwareNSX/nsx_zone.py new file mode 100644 index 000000000..a55f86dc9 --- /dev/null +++ b/roles/importer/files/importer/vmwareNSX/nsx_zone.py @@ -0,0 +1,15 @@ +from asyncio.log import logger +from fwo_log import getFwoLogger +from fwo_const import list_delimiter + + +def normalize_zones(full_config, config2import, import_id): + zones = [] + for zone_orig in full_config["/Network/Zones"]: + zones.append({ + "zone_name": zone_orig["@name"], + "zone_uid": zone_orig["@name"], + "control_id": import_id + }) + + config2import['zone_objects'] = zones diff --git a/roles/ui/files/FWO.UI/Pages/Settings/SettingsGateways.razor b/roles/ui/files/FWO.UI/Pages/Settings/SettingsGateways.razor index 0c3ae32a2..91a1a512c 100644 --- a/roles/ui/files/FWO.UI/Pages/Settings/SettingsGateways.razor +++ b/roles/ui/files/FWO.UI/Pages/Settings/SettingsGateways.razor @@ -104,7 +104,8 @@ actDevice.DeviceType.Manufacturer == "Fortinet" || actDevice.DeviceType.Manufacturer == "Cisco" || actDevice.DeviceType.Manufacturer == "Palo Alto" || - actDevice.DeviceType.Manufacturer == "Microsoft") + actDevice.DeviceType.Manufacturer == "Microsoft" || + actDevice.DeviceType.Manufacturer == "VMWare") { @if (actDevice.DeviceType.Manufacturer == "Fortinet" && actDevice.Management.DeviceType.IsLegacyDevType()) { From 34c55a94420213e61b41c85957d79e0620babbb6 Mon Sep 17 00:00:00 2001 From: abarz722 Date: Tue, 20 Feb 2024 14:35:12 +0100 Subject: [PATCH 02/84] iconify modelling --- .../files/sql/creation/fworch-fill-stm.sql | 18 ++++ .../files/sql/idempotent/fworch-texts.sql | 39 +++++++-- roles/database/files/upgrade/8.0.1.sql | 17 ++++ .../files/FWO.Config.Api/Data/ConfigData.cs | 3 + .../files/FWO.Config.Api/GlobalConstants.cs | 10 +++ .../Pages/Help/HelpSettingsModelling.cshtml | 3 +- .../Help/HelpSettingsModellingPers.cshtml | 22 +++++ .../Pages/Help/HelpSettingsSidebar.cshtml | 3 + roles/ui/files/FWO.UI/Pages/Help/Index.cshtml | 3 + .../NetworkModelling/ConnectionTable.razor | 6 +- .../EditAppRoleLeftSide.razor | 2 +- .../Pages/NetworkModelling/EditConn.razor | 2 +- .../NetworkModelling/EditConnLeftSide.razor | 54 ++++++++---- .../EditServiceGroupLeftSide.razor | 8 +- .../NetworkModelling/ManualAppServer.razor | 21 +++-- .../NetworkModelling/NetworkModelling.razor | 8 +- .../FWO.UI/Pages/Settings/SearchUser.razor | 2 +- .../Pages/Settings/SettingsModelling.razor | 16 ++-- .../Settings/SettingsModellingPers.razor | 85 +++++++++++++++++++ .../FWO.UI/Services/ModellingHandlerBase.cs | 8 ++ .../files/FWO.UI/Shared/SettingsLayout.razor | 7 ++ 21 files changed, 284 insertions(+), 53 deletions(-) create mode 100644 roles/database/files/upgrade/8.0.1.sql create mode 100644 roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModellingPers.cshtml create mode 100644 roles/ui/files/FWO.UI/Pages/Settings/SettingsModellingPers.razor diff --git a/roles/database/files/sql/creation/fworch-fill-stm.sql b/roles/database/files/sql/creation/fworch-fill-stm.sql index 062deaeb2..eb47e43a4 100644 --- a/roles/database/files/sql/creation/fworch-fill-stm.sql +++ b/roles/database/files/sql/creation/fworch-fill-stm.sql @@ -32,6 +32,7 @@ insert into config (config_key, config_value, config_user) VALUES ('recCheckActi insert into config (config_key, config_value, config_user) VALUES ('recCheckEmailSubject', 'Upcoming rule recertifications', 0); insert into config (config_key, config_value, config_user) VALUES ('recCheckEmailUpcomingText', 'The following rules are upcoming to be recertified:', 0); insert into config (config_key, config_value, config_user) VALUES ('recCheckEmailOverdueText', 'The following rules are overdue to be recertified:', 0); +insert into config (config_key, config_value, config_user) VALUES ('recCheckParams', '{"check_interval":2,"check_offset":1,"check_weekday":null,"check_dayofmonth":null}', 0); insert into config (config_key, config_value, config_user) VALUES ('recRefreshStartup', 'False', 0); insert into config (config_key, config_value, config_user) VALUES ('recRefreshDaily', 'False', 0); insert into config (config_key, config_value, config_user) VALUES ('messageViewTime', '7', 0); @@ -80,6 +81,23 @@ insert into config (config_key, config_value, config_user) VALUES ('importSubnet insert into config (config_key, config_value, config_user) VALUES ('importAppDataPath', '[]', 0); insert into config (config_key, config_value, config_user) VALUES ('importSubnetDataPath', '', 0); insert into config (config_key, config_value, config_user) VALUES ('modNamingConvention', '{"networkAreaRequired":false,"fixedPartLength":0,"freePartLength":0,"networkAreaPattern":"","appRolePattern":""}', 0); +insert into config (config_key, config_value, config_user) VALUES ('modIconify', 'True', 0); +insert into config (config_key, config_value, config_user) VALUES ('reducedProtocolSet', 'True', 0); +insert into config (config_key, config_value, config_user) VALUES ('overviewDisplayLines', '3', 0); +insert into config (config_key, config_value, config_user) VALUES ('emailServerAddress', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('emailPort', '0', 0); +insert into config (config_key, config_value, config_user) VALUES ('emailTls', 'None', 0); +insert into config (config_key, config_value, config_user) VALUES ('emailUser', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('emailPassword', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('emailSenderAddress', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyRecipients', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifySubject', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyBody', '', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyActive', 'False', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyType', '0', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifySleepTime', '0', 0); +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyStartAt', '00:00:00', 0); + INSERT INTO "report_format" ("report_format_name") VALUES ('json'); INSERT INTO "report_format" ("report_format_name") VALUES ('pdf'); diff --git a/roles/database/files/sql/idempotent/fworch-texts.sql b/roles/database/files/sql/idempotent/fworch-texts.sql index 8ecfd3980..3f634659d 100644 --- a/roles/database/files/sql/idempotent/fworch-texts.sql +++ b/roles/database/files/sql/idempotent/fworch-texts.sql @@ -530,6 +530,8 @@ INSERT INTO txt VALUES ('no_rules_gtw', 'German', 'Anzahl Regeln pro Gatew INSERT INTO txt VALUES ('no_rules_gtw', 'English', 'Number of Rules per Gateway'); INSERT INTO txt VALUES ('negated', 'German', 'nicht'); INSERT INTO txt VALUES ('negated', 'English', 'not'); +INSERT INTO txt VALUES ('network_object', 'German', 'Netzwerkobjekt'); +INSERT INTO txt VALUES ('network_object', 'English', 'Network Object'); INSERT INTO txt VALUES ('network_objects', 'German', 'Netzwerkobjekte'); INSERT INTO txt VALUES ('network_objects', 'English', 'Network Objects'); INSERT INTO txt VALUES ('network_services', 'German', 'Netzwerkdienste'); @@ -1770,6 +1772,10 @@ INSERT INTO txt VALUES ('appRolePattern', 'German', 'Muster App Rolle'); INSERT INTO txt VALUES ('appRolePattern', 'English', 'App Role Pattern'); INSERT INTO txt VALUES ('import_source', 'German', 'Importquelle'); INSERT INTO txt VALUES ('import_source', 'English', 'Import Source'); +INSERT INTO txt VALUES ('modelling_settings', 'German', 'Modellierungseinstellungen'); +INSERT INTO txt VALUES ('modelling_settings', 'English', 'Modelling Settings'); +INSERT INTO txt VALUES ('modIconify', 'German', 'Nutzung von Piktogrammen'); +INSERT INTO txt VALUES ('modIconify', 'English', 'Prefer use of Icons'); -- monitoring INSERT INTO txt VALUES ('open_alerts', 'German', 'Offene Alarme'); @@ -2167,6 +2173,8 @@ INSERT INTO txt VALUES ('U5413', 'German', 'Anpassung der persönlichen Rep INSERT INTO txt VALUES ('U5413', 'English', 'Adapt your personal reporting settings'); INSERT INTO txt VALUES ('U5414', 'German', 'Anpassung der persönlichen Rezertifizierungseinstellungen'); INSERT INTO txt VALUES ('U5414', 'English', 'Adapt your personal recertification settings'); +INSERT INTO txt VALUES ('U5415', 'German', 'Anpassung der persönlichen Modellierungseinstellungen'); +INSERT INTO txt VALUES ('U5415', 'English', 'Adapt your personal modelling settings'); INSERT INTO txt VALUES ('U5501', 'German', 'Sind sie sicher, dass sie folgenden Status löschen wollen: '); INSERT INTO txt VALUES ('U5501', 'English', 'Are you sure you want to delete state: '); @@ -3398,16 +3406,18 @@ INSERT INTO txt VALUES ('H5013', 'German', 'Im Kapitel "Voreinstellungen" kann Allgemeinen Rezertifizierungs- und Modellierungseinstellungen. '); INSERT INTO txt VALUES ('H5013', 'English', 'In the "Defaults" chapter the administrator can define Default Values applicable to all users - and define email-, importer- and Password Policy settings. + and define email-, importer- and Password Policy settings. Additionally there are the module specific General Recertification and Modelling Settings. '); INSERT INTO txt VALUES ('H5014', 'German', 'Das Kapitel "Persönlich" ist für alle Nutzer zugänglich. Hier können das individuelle Password, die bevorzugte Sprache und Reporting-Einstellungen gesetzt werden. Nutzer mit Rezertifizierer-Rolle können auch ihre Rezertifizierungseinstellungen anpassen. + Das gleiche gilt für Modellierer in den Modellierungseinstellungen. '); INSERT INTO txt VALUES ('H5014', 'English', 'The "Personal" chapter is accessible by all users, where they can set their individual Password, Language and Reporting preferences. Users with recertifier role have also the possibility to adjust their Recertification Setting. + Same for modellers in the Modelling Settings. '); INSERT INTO txt VALUES ('H5015', 'German', 'Das Kapitel "Workflow" dient dem Administrator, einen Workflow aufzusetzen. Dazu gehört die Definition der angebotenen Aktionen, der verwendeten Stati und den Statusübergängen in den zentralen Status-Matrizen. @@ -4310,8 +4320,12 @@ INSERT INTO txt VALUES ('H5603', 'German', 'Server in Verbindung erlauben: Steu INSERT INTO txt VALUES ('H5603', 'English', 'Allow Servers in Connection: Controls, if App Servers are offered in the Library besides the App Roles for direct use in the connections.'); INSERT INTO txt VALUES ('H5604', 'German', 'Einfache Dienste in Verbindung erlauben: Steuert, ob in der Bibliothek neben den Servicegruppen auch einfache Services zur direkten Verwendung in den Verbindungen angeboten werden.'); INSERT INTO txt VALUES ('H5604', 'English', 'Allow Simple Services in Connection: Controls, if simple Services are offered in the Library besides the Service Groups for direct use in the connections.'); -INSERT INTO txt VALUES ('H5605', 'German', 'Max. Anzahl Zeilen in Übersicht: Definiert die Zeilenzahl innerhalb eines Eintrags in der Übersichtstabelle der Verbindungen, ab der die Elemente eingeklappt dargestellt werden.'); -INSERT INTO txt VALUES ('H5605', 'English', 'Max. Number of Rows in Overview: Defines the number of rows inside an entry of the connections overview table, from which the elements are displayed retracted.'); +INSERT INTO txt VALUES ('H5605', 'German', 'Max. Anzahl Zeilen in Übersicht: Definiert die Zeilenzahl innerhalb eines Eintrags in der Übersichtstabelle der Verbindungen, ab der die Elemente eingeklappt dargestellt werden. + Wird vom Administrator allgemein vorausgewählt, kann aber vom Nutzer in den persönlichen Einstellungen überschrieben werden. +'); +INSERT INTO txt VALUES ('H5605', 'English', 'Max. Number of Rows in Overview: Defines the number of rows inside an entry of the connections overview table, from which the elements are displayed retracted. + Generally set by the administrator but can be overwritten in the personal settings of the user. +'); INSERT INTO txt VALUES ('H5606', 'German', 'Netzwerkarea vorgeschrieben: Wenn dieses Flag gesetzt ist, müssen die auszuwählenden App Server einer festen Area zugeordnet sein. Es werden dann beim Zusammenstellen einer App Rolle in der Bibliothek nur die der aktuell ausgewählten Area zugehörigen App Server angeboten. Für die Namensgebung der App Rolle wird dann die in den folgenden Punkten definierte Namenskonvention angewendet. @@ -4373,6 +4387,15 @@ INSERT INTO txt VALUES ('H5616', 'German', 'Import Subnetzdaten-Start: Legt ein INSERT INTO txt VALUES ('H5616', 'English', 'Import Subnet data start at: Import App data start at: Defines a referential time from which the Subnte data import intervals are calculated.'); INSERT INTO txt VALUES ('H5617', 'German', 'Reduzierten Protokollset darstellen: Nur eine begrenzte Zahl von Protokollen wird zur Auswahl angeboten (TCP, UDP, ICMP).'); INSERT INTO txt VALUES ('H5617', 'English', 'Display reduced Protocol set: Offer only a reduced number of protocols for selection (TCP, UDP, ICMP).'); +INSERT INTO txt VALUES ('H5618', 'German', 'Nutzung von Piktogrammen: Vorzugsweise Nutzung von Piktogrammen wo sinnvoll. Wird vom Administrator allgemein vorausgewählt, kann aber vom Nutzer in den persönlichen Einstellungen überschrieben werden.'); +INSERT INTO txt VALUES ('H5618', 'English', 'Prefer use of Icons: Use icons where reasonnable. Generally set by the administrator but can be overwritten in the personal settings of the user.'); +INSERT INTO txt VALUES ('H5621', 'German', 'Ein Modellierer kann einige persönliche Voreinstellungen für die Darstellung der Modellierung überschreiben. + Ausgangswert ist der vom Admin in den Modellierungseinstellungen gesetzte Wert. +'); +INSERT INTO txt VALUES ('H5621', 'English', 'A modeller can overwrite some personal settings for the modelling layout. + The default value is set by the admin in the Modelling Settings. +'); + INSERT INTO txt VALUES ('H5701', 'German', 'Die in der Datenbank hinterlegten sprachabhängigen Texte können individuell überschrieben werden. Dabei werden die vom System vorgegebenen Texte nicht geändert, sondern nur durch die hier definierten Texte - falls vorhanden - überblendet. Die hier gemachten Änderungen werden in der UI beim nächsten Login sichtbar, bei Hilfetexten erst nach dem nächsten Restart. @@ -4489,7 +4512,7 @@ INSERT INTO txt VALUES ('H6906', 'German', 'Anmelden zur Generierung eines g&uu INSERT INTO txt VALUES ('H6906', 'English', 'Login to get a JWT for the steps further below'); INSERT INTO txt VALUES ('H6907', 'German', 'Auflisten bereits vorhandener Reports im Archiv (hier der letzte generierte zum Schedule)'); INSERT INTO txt VALUES ('H6907', 'English', 'List generated reports in archive (here we get the last one generated for the respective schedule)'); -INSERT INTO txt VALUES ('H6921', 'German', 'Der Import von Applikationsdaten wird aus einer oder mehreren .json-Dateien mit den in den Modellierungs-Einstellungen definierten Pfaden und Namen gespeist. +INSERT INTO txt VALUES ('H6921', 'German', 'Der Import von Applikationsdaten wird aus einer oder mehreren .json-Dateien mit den in den Modellierungseinstellungen definierten Pfaden und Namen gespeist. Dort kann auch jeweils ein gleichnamiges Python-Skript (mit der Endung .py) zur Erzeugung eben dieser Dateien hinterlegt werden. Die .json-Datei hat die folgende Struktur: '); INSERT INTO txt VALUES ('H6921', 'English', 'The import of application data is fed from one or several .json files with paths and names defined in the Modelling Settings. @@ -4531,7 +4554,7 @@ INSERT INTO txt VALUES ('H6922', 'English', 'These fields have the following mea '); -INSERT INTO txt VALUES ('H6931', 'German', 'Der Import von Subnetzdaten wird aus einer .json-Datei mit dem in den Modellierungs-Einstellungen definierten Pfad und Namen gespeist. +INSERT INTO txt VALUES ('H6931', 'German', 'Der Import von Subnetzdaten wird aus einer .json-Datei mit dem in den Modellierungseinstellungen definierten Pfad und Namen gespeist. Dort kann auch ein gleichnamiges Python-Skript (mit der Endung .py) zur Erzeugung eben dieser Datei hinterlegt werden. Die .json-Datei hat die folgende Struktur: '); INSERT INTO txt VALUES ('H6931', 'English', 'The import of subnet data is fed from a .json file with path and name defined in the Modelling Settings. @@ -5422,7 +5445,7 @@ INSERT INTO txt VALUES ('H9001', 'German', 'Insbesondere in grösseren Netz und ihre Elemente nach vorgegebenen Kriterien zu verknüpfen. Dadurch wird ein Kommunikationsprofil erzeugt, bestehend aus einem Satz von Verbindungen und Schnittstellen.
Zur Definition der Schnittstellen und Verbindungen wird auf der linken Seite eine Bibliothek bereitgestellt, in der zunächst die zur Applikation zugeordneten (in der Regel aus Fremdsystemen importierten) Host-Adressen (App-Server) angeboten werden. Diese können im ersten Schritt zu App-Rollen gebündelt werden (sh. Netzwerkobjekte). - Die App-Rollen (und je nach Modellierungs-Einstellungen auch die App-Server selbst) können dann als Quelle oder Ziel in die zu erstellende Verbindung übertragen werden. + Die App-Rollen (und je nach Modellierungseinstellungen auch die App-Server selbst) können dann als Quelle oder Ziel in die zu erstellende Verbindung übertragen werden. Hinzu können noch weitere Objekte (z. B. Netzwerke) kommen, und es können (interne und externe) Schnittstellen eingebunden werden.
Desweiteren werden in der Bibliothek vordefinierte (vom Administrator eingestellte) Dienste angeboten. Diese können durch selbst definierte Dienste ergänzt, als Dienstgruppen gebündelt und dann in den zu definierenden Verbindungen verwendet werden. @@ -5502,7 +5525,7 @@ INSERT INTO txt VALUES ('H9032', 'English', 'App Server: Elementary components ( (Import Settings, Import Interface), but can also be created manually by the administrator. Depending on the settings (according to company requirements) App Servers can be used directly in the connections or have to be bundled in App Roles first. '); -INSERT INTO txt VALUES ('H9033', 'German', 'App-Rollen: Dienen der Bündelung von App-Servern. Falls in den Modellierungs-Einstellungen so vorgesehen, +INSERT INTO txt VALUES ('H9033', 'German', 'App-Rollen: Dienen der Bündelung von App-Servern. Falls in den Modellierungseinstellungen so vorgesehen, müssen sie einer Netzwerkarea zugehören. Beim Erstellen der App-Rolle muss dann zunächst eine Area ausgewählt werden, nur von dieser werden dann die App-Server in der Bibliothek angeboten. Die Namen der App-Rollen müssen dann einer ebenfalls in den Einstellungen vorgegebenen Namenskonvention folgen. '); @@ -5516,7 +5539,7 @@ INSERT INTO txt VALUES ('H9034', 'German', 'Netzwerkareas: Werden über die INSERT INTO txt VALUES ('H9034', 'English', 'Network Areas: Are imported via the Subnet Data Import Interface (Import Settings, Import Interface). They can be searched an selected from the library and then used for source and destination of the connections. '); -INSERT INTO txt VALUES ('H9041', 'German', 'Es wird zwischen einfachen Diensten und Dienstgruppen unterschieden. In den Modellierungs-Einstellungen +INSERT INTO txt VALUES ('H9041', 'German', 'Es wird zwischen einfachen Diensten und Dienstgruppen unterschieden. In den Modellierungseinstellungen kann festgelegt werden, dass nur Dienstgruppen in der Definition von Verbindungen genutzt werden können, ansonsten sind auch einfache Dienste zugelassen. '); INSERT INTO txt VALUES ('H9041', 'English', 'There is a differentiation between simple services and Service Groups. It can be defined in the Modelling Settings, diff --git a/roles/database/files/upgrade/8.0.1.sql b/roles/database/files/upgrade/8.0.1.sql new file mode 100644 index 000000000..d21147e47 --- /dev/null +++ b/roles/database/files/upgrade/8.0.1.sql @@ -0,0 +1,17 @@ +insert into config (config_key, config_value, config_user) VALUES ('modIconify', 'True', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('reducedProtocolSet', 'True', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('overviewDisplayLines', '3', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('emailServerAddress', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('emailPort', '0', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('emailTls', 'None', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('emailUser', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('emailPassword', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('emailSenderAddress', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyRecipients', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifySubject', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyBody', '', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyActive', 'False', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyType', '0', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifySleepTime', '0', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('impChangeNotifyStartAt', '00:00:00', 0) ON CONFLICT DO NOTHING; +insert into config (config_key, config_value, config_user) VALUES ('recCheckParams', '{"check_interval":2,"check_offset":1,"check_weekday":null,"check_dayofmonth":null}', 0) ON CONFLICT DO NOTHING; diff --git a/roles/lib/files/FWO.Config.Api/Data/ConfigData.cs b/roles/lib/files/FWO.Config.Api/Data/ConfigData.cs index cb9b3fde3..004020017 100644 --- a/roles/lib/files/FWO.Config.Api/Data/ConfigData.cs +++ b/roles/lib/files/FWO.Config.Api/Data/ConfigData.cs @@ -243,6 +243,9 @@ public class ConfigData : ICloneable [JsonProperty("modNamingConvention"), JsonPropertyName("modNamingConvention")] public string ModNamingConvention { get; set; } = ""; + [JsonProperty("modIconify"), JsonPropertyName("modIconify")] + public bool ModIconify { get; set; } = true; + public ConfigData(bool editable = false) { diff --git a/roles/lib/files/FWO.Config.Api/GlobalConstants.cs b/roles/lib/files/FWO.Config.Api/GlobalConstants.cs index d47e7fcd7..117a17e6d 100644 --- a/roles/lib/files/FWO.Config.Api/GlobalConstants.cs +++ b/roles/lib/files/FWO.Config.Api/GlobalConstants.cs @@ -39,4 +39,14 @@ public struct GlobalConst public const string kImplementer = "implementer"; public const string kReviewer = "reviewer"; } + + public struct Icons + { + public const string Add = "oi-plus"; + public const string Edit = "oi-wrench"; + public const string Delete = "oi-trash"; + public const string Search = "oi-magnifying-glass"; + public const string Use = "oi-arrow-thick-right"; + public const string Unuse = "oi-arrow-thick-left"; + } } diff --git a/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModelling.cshtml b/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModelling.cshtml index 2e8702bb6..b945455d8 100644 --- a/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModelling.cshtml +++ b/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModelling.cshtml @@ -12,7 +12,7 @@ @inject UserConfig userConfig
-

@(userConfig.GetText("modelling"))

+

@(userConfig.GetText("modelling_settings"))

@(Html.Raw(userConfig.GetText("H5601")))

@(Html.Raw(userConfig.GetText("general"))) @@ -21,6 +21,7 @@
  • @(Html.Raw(userConfig.GetText("H5603")))
  • @(Html.Raw(userConfig.GetText("H5604")))
  • @(Html.Raw(userConfig.GetText("H5605")))
  • +
  • @(Html.Raw(userConfig.GetText("H5618")))
  • @(Html.Raw(userConfig.GetText("H5617")))
  • @(Html.Raw(userConfig.GetText("naming_convention"))) diff --git a/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModellingPers.cshtml b/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModellingPers.cshtml new file mode 100644 index 000000000..05b87a3d7 --- /dev/null +++ b/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsModellingPers.cshtml @@ -0,0 +1,22 @@ +@page "/help/settings/modellingpersonal" +@model FWO.Ui.Pages.Help.MainModel +@{ + Layout = "HelpLayout"; +} +@section sidebar{ + @{ + await Html.RenderPartialAsync("HelpSettingsSidebar.cshtml"); + } +} +@using FWO.Config.Api +@inject UserConfig userConfig + +
    +

    @(userConfig.GetText("modelling_settings"))

    + @(Html.Raw(userConfig.GetText("H5621"))) +

    +
      +
    • @(Html.Raw(userConfig.GetText("H5605")))
    • +
    • @(Html.Raw(userConfig.GetText("H5618")))
    • +
    +
    diff --git a/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsSidebar.cshtml b/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsSidebar.cshtml index 72db3d069..a5b788f14 100644 --- a/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsSidebar.cshtml +++ b/roles/ui/files/FWO.UI/Pages/Help/HelpSettingsSidebar.cshtml @@ -87,6 +87,9 @@ @(userConfig.GetText("recertification")) + + @(userConfig.GetText("modelling")) +
    diff --git a/roles/ui/files/FWO.UI/Pages/Help/Index.cshtml b/roles/ui/files/FWO.UI/Pages/Help/Index.cshtml index d0336c036..d780971f8 100644 --- a/roles/ui/files/FWO.UI/Pages/Help/Index.cshtml +++ b/roles/ui/files/FWO.UI/Pages/Help/Index.cshtml @@ -201,6 +201,9 @@ +