PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/mgg/securicad.py

https://gitlab.com/gnebbia/mgg
Python | 227 lines | 191 code | 6 blank | 30 comment | 2 complexity | a0667614cabb257edb9b016ed7ad539a MD5 | raw file
  1. # -*- encoding: utf-8 -*-
  2. # mgg v0.1.0
  3. # Generate MAL-based attack graphs
  4. # Copyright 2021, Giuseppe Nebbione.
  5. # See /LICENSE for licensing information.
  6. """
  7. SecuriCAD interface Module
  8. :Copyright: 2021, Giuseppe Nebbione.
  9. :License: GPLv3 (see /LICENSE).
  10. """
  11. import os
  12. import zipfile
  13. import json
  14. import configparser
  15. import xml.etree.ElementTree as ET
  16. from securicad import enterprise
  17. from securicad.model.model import Model as securicadModel
  18. from securicad.enterprise.client import Client as securicadClient
  19. def enterprise_connect(
  20. url: str, username: str, password: str, org: str, cacert: str
  21. ) -> securicadClient:
  22. """
  23. Connect to a running SecuriCAD Enterprise instance
  24. Arguments:
  25. url - the url of the SecuriCAD Enterprise instance
  26. username - the username used to login to SecuriCAD Enterprise
  27. password - the password used to login to SecuriCAD Enterprise
  28. org - the organization field used to login to SecuriCAD Enterprise
  29. cacert - the certificate to login to SecuriCAD Enterprise
  30. Return:
  31. A securicad enterprise client object that can be
  32. used to select projects or run scenarios/simulations
  33. """
  34. client = enterprise.client(
  35. base_url=url,
  36. username=username,
  37. password=password,
  38. organization=org,
  39. cacert=cacert if cacert else False
  40. )
  41. return client
  42. def enterprise_connect_from_config(
  43. config_file: str
  44. ) -> securicadClient:
  45. """
  46. Connect to a running SecuriCAD Enterprise instance
  47. Arguments:
  48. config_file - the path to an ".ini" configuration file
  49. An example config file may be structured
  50. like this:
  51. ```
  52. [enterprise-client]
  53. url = https://x.y.z.t
  54. username = johndoe
  55. password = examplepassword
  56. org = myorganization
  57. cacert =
  58. ```
  59. Return:
  60. A securicad enterprise client object that can be
  61. used to select projects or run scenarios/simulations
  62. """
  63. config = configparser.ConfigParser()
  64. config.read(config_file)
  65. client = enterprise.client(
  66. base_url=config["enterprise-client"]["url"],
  67. username=config["enterprise-client"]["username"],
  68. password=config["enterprise-client"]["password"],
  69. organization=config["enterprise-client"]["org"]
  70. if config["enterprise-client"]["org"] else None,
  71. cacert=config["enterprise-client"]["cacert"]
  72. if config["enterprise-client"]["cacert"] else False)
  73. return client
  74. def download_model_to_scad_archive(
  75. client: securicadClient, project_name: str,
  76. model_name: str, out_filename: str
  77. ) -> None:
  78. """
  79. Downloads a model from a running securiCAD enterprise
  80. instance to a ".sCAD" archive
  81. Arguments:
  82. client - A securicad enterprise client object that can be
  83. used to select projects or run scenarios/simulations
  84. project_name - the name of the project to be selected
  85. model_name - the name of the model to be selected
  86. outfilename - the name of the downloaded archive
  87. """
  88. scad_extension = ".scad"
  89. project = client.projects.get_project_by_name(project_name)
  90. models = enterprise.models.Models(client)
  91. model_info = models.get_model_by_name(project, model_name)
  92. if out_filename.lower().endswith(scad_extension):
  93. model_path = out_filename
  94. else:
  95. model_path = out_filename + scad_extension
  96. scad_dump = model_info.get_scad()
  97. with open(model_path, 'wb') as outfile:
  98. outfile.write(scad_dump)
  99. def load_model_from_enterprise(
  100. client: securicadClient, project_name: str, model_name: str
  101. ) -> securicadModel:
  102. """
  103. Retrieve a securiCAD model from a running securiCAD enterprise
  104. running instance
  105. Arguments:
  106. client - A securicad enterprise client object that can be
  107. used to select projects or run scenarios/simulations
  108. project_name - the name of the project to be selected
  109. model_name - the name of the model to be selected
  110. Return:
  111. A securiCAD model represented by a dictionary
  112. """
  113. project = client.projects.get_project_by_name(project_name)
  114. models = enterprise.models.Models(client)
  115. model_info = models.get_model_by_name(project, model_name)
  116. return model_info.get_model().model
  117. def load_language_specification(mar_archive: str) -> dict:
  118. """
  119. Reads a ".mar" archive provided by malc and returns a dictionary
  120. representing a MAL language structure
  121. Arguments:
  122. mar_archive - the path to a ".mar" archive
  123. Return:
  124. A dictionary representing the language
  125. """
  126. with zipfile.ZipFile(mar_archive, 'r') as archive:
  127. langspec = archive.read('langspec.json')
  128. return json.loads(langspec)
  129. def save_mar_to_json(mar_archive: str, json_output: str) -> dict:
  130. """
  131. reads a ".mar" archive provided by malc and returns a
  132. representing a mal language structure
  133. arguments:
  134. mar_archive - the path to a ".mar" archive
  135. return:
  136. a dictionary representing the language
  137. """
  138. json_repr = load_language_specification(mar_archive)
  139. with open(json_output, 'w', encoding='utf-8') as file:
  140. json.dump(json_repr, file, indent=4)
  141. def load_model_from_scad_archive(scad_archive: str) -> dict:
  142. """
  143. Reads a ".sCAD" archive generated by securiCAD
  144. representing an instance model
  145. Arguments:
  146. scad_archive - the path to a ".sCAD" archive
  147. Return:
  148. A dictionary representing the model
  149. """
  150. model = {}
  151. with zipfile.ZipFile(scad_archive, 'r') as archive:
  152. filelist = archive.namelist()
  153. model_file = next(filter(lambda x: ( x[-4:] == '.eom'), filelist))
  154. meta_file = next(filter(lambda x: (x == 'meta.json'), filelist))
  155. model["metadata"] = json.loads(archive.read(meta_file))
  156. scad_model = archive.read(model_file)
  157. root = ET.fromstring(scad_model)
  158. objects_dict = {}
  159. assocs = []
  160. for child in root.iter("objects"):
  161. objid = child.attrib["id"]
  162. objects_dict[objid] = {
  163. "name": child.attrib['name'],
  164. "metaconcept": child.attrib['metaConcept'],
  165. "eid": child.attrib['exportedId']}
  166. for subchild in child.iter("evidenceAttributes"):
  167. defense_name = subchild.attrib['metaConcept']
  168. defense_name = defense_name[0].lower() + defense_name[1:]
  169. for distrib in subchild.iter("evidenceDistribution"):
  170. distrib_type = distrib.attrib['type']
  171. for d in distrib.iter("parameters"):
  172. if 'value' in d.attrib:
  173. dist_value = d.attrib['value']
  174. if 'active_defense' not in objects_dict[objid]:
  175. objects_dict[objid]['active_defense'] = {}
  176. objects_dict[objid]['active_defense'][defense_name] = {'distribution': distrib_type, 'value': dist_value}
  177. for child in root.iter("associations"):
  178. assocs.append({"id1": child.attrib['sourceObject'],
  179. "id2": child.attrib['targetObject'],
  180. "type1": child.attrib['targetProperty'],
  181. "type2": child.attrib['sourceProperty']})
  182. model["associations"] = assocs
  183. model["objects"] = objects_dict
  184. return model