/mgg/securicad.py
Python | 227 lines | 191 code | 6 blank | 30 comment | 2 complexity | a0667614cabb257edb9b016ed7ad539a MD5 | raw file
- # -*- encoding: utf-8 -*-
- # mgg v0.1.0
- # Generate MAL-based attack graphs
- # Copyright 2021, Giuseppe Nebbione.
- # See /LICENSE for licensing information.
- """
- SecuriCAD interface Module
- :Copyright: 2021, Giuseppe Nebbione.
- :License: GPLv3 (see /LICENSE).
- """
- import os
- import zipfile
- import json
- import configparser
- import xml.etree.ElementTree as ET
- from securicad import enterprise
- from securicad.model.model import Model as securicadModel
- from securicad.enterprise.client import Client as securicadClient
- def enterprise_connect(
- url: str, username: str, password: str, org: str, cacert: str
- ) -> securicadClient:
- """
- Connect to a running SecuriCAD Enterprise instance
- Arguments:
- url - the url of the SecuriCAD Enterprise instance
- username - the username used to login to SecuriCAD Enterprise
- password - the password used to login to SecuriCAD Enterprise
- org - the organization field used to login to SecuriCAD Enterprise
- cacert - the certificate to login to SecuriCAD Enterprise
- Return:
- A securicad enterprise client object that can be
- used to select projects or run scenarios/simulations
- """
- client = enterprise.client(
- base_url=url,
- username=username,
- password=password,
- organization=org,
- cacert=cacert if cacert else False
- )
- return client
- def enterprise_connect_from_config(
- config_file: str
- ) -> securicadClient:
- """
- Connect to a running SecuriCAD Enterprise instance
- Arguments:
- config_file - the path to an ".ini" configuration file
- An example config file may be structured
- like this:
- ```
- [enterprise-client]
- url = https://x.y.z.t
- username = johndoe
- password = examplepassword
- org = myorganization
- cacert =
- ```
- Return:
- A securicad enterprise client object that can be
- used to select projects or run scenarios/simulations
- """
- config = configparser.ConfigParser()
- config.read(config_file)
- client = enterprise.client(
- base_url=config["enterprise-client"]["url"],
- username=config["enterprise-client"]["username"],
- password=config["enterprise-client"]["password"],
- organization=config["enterprise-client"]["org"]
- if config["enterprise-client"]["org"] else None,
- cacert=config["enterprise-client"]["cacert"]
- if config["enterprise-client"]["cacert"] else False)
- return client
- def download_model_to_scad_archive(
- client: securicadClient, project_name: str,
- model_name: str, out_filename: str
- ) -> None:
- """
- Downloads a model from a running securiCAD enterprise
- instance to a ".sCAD" archive
- Arguments:
- client - A securicad enterprise client object that can be
- used to select projects or run scenarios/simulations
- project_name - the name of the project to be selected
- model_name - the name of the model to be selected
- outfilename - the name of the downloaded archive
- """
-
- scad_extension = ".scad"
- project = client.projects.get_project_by_name(project_name)
- models = enterprise.models.Models(client)
- model_info = models.get_model_by_name(project, model_name)
- if out_filename.lower().endswith(scad_extension):
- model_path = out_filename
- else:
- model_path = out_filename + scad_extension
- scad_dump = model_info.get_scad()
- with open(model_path, 'wb') as outfile:
- outfile.write(scad_dump)
- def load_model_from_enterprise(
- client: securicadClient, project_name: str, model_name: str
- ) -> securicadModel:
- """
- Retrieve a securiCAD model from a running securiCAD enterprise
- running instance
- Arguments:
- client - A securicad enterprise client object that can be
- used to select projects or run scenarios/simulations
- project_name - the name of the project to be selected
- model_name - the name of the model to be selected
- Return:
- A securiCAD model represented by a dictionary
- """
- project = client.projects.get_project_by_name(project_name)
- models = enterprise.models.Models(client)
- model_info = models.get_model_by_name(project, model_name)
- return model_info.get_model().model
- def load_language_specification(mar_archive: str) -> dict:
- """
- Reads a ".mar" archive provided by malc and returns a dictionary
- representing a MAL language structure
- Arguments:
- mar_archive - the path to a ".mar" archive
- Return:
- A dictionary representing the language
- """
- with zipfile.ZipFile(mar_archive, 'r') as archive:
- langspec = archive.read('langspec.json')
- return json.loads(langspec)
- def save_mar_to_json(mar_archive: str, json_output: str) -> dict:
- """
- reads a ".mar" archive provided by malc and returns a
- representing a mal language structure
- arguments:
- mar_archive - the path to a ".mar" archive
- return:
- a dictionary representing the language
- """
- json_repr = load_language_specification(mar_archive)
- with open(json_output, 'w', encoding='utf-8') as file:
- json.dump(json_repr, file, indent=4)
- def load_model_from_scad_archive(scad_archive: str) -> dict:
- """
- Reads a ".sCAD" archive generated by securiCAD
- representing an instance model
- Arguments:
- scad_archive - the path to a ".sCAD" archive
- Return:
- A dictionary representing the model
- """
- model = {}
- with zipfile.ZipFile(scad_archive, 'r') as archive:
- filelist = archive.namelist()
- model_file = next(filter(lambda x: ( x[-4:] == '.eom'), filelist))
- meta_file = next(filter(lambda x: (x == 'meta.json'), filelist))
- model["metadata"] = json.loads(archive.read(meta_file))
- scad_model = archive.read(model_file)
- root = ET.fromstring(scad_model)
- objects_dict = {}
- assocs = []
- for child in root.iter("objects"):
- objid = child.attrib["id"]
- objects_dict[objid] = {
- "name": child.attrib['name'],
- "metaconcept": child.attrib['metaConcept'],
- "eid": child.attrib['exportedId']}
- for subchild in child.iter("evidenceAttributes"):
- defense_name = subchild.attrib['metaConcept']
- defense_name = defense_name[0].lower() + defense_name[1:]
- for distrib in subchild.iter("evidenceDistribution"):
- distrib_type = distrib.attrib['type']
- for d in distrib.iter("parameters"):
- if 'value' in d.attrib:
- dist_value = d.attrib['value']
- if 'active_defense' not in objects_dict[objid]:
- objects_dict[objid]['active_defense'] = {}
- objects_dict[objid]['active_defense'][defense_name] = {'distribution': distrib_type, 'value': dist_value}
- for child in root.iter("associations"):
- assocs.append({"id1": child.attrib['sourceObject'],
- "id2": child.attrib['targetObject'],
- "type1": child.attrib['targetProperty'],
- "type2": child.attrib['sourceProperty']})
- model["associations"] = assocs
- model["objects"] = objects_dict
- return model