From 6e5d68fcaa4e7c6d51015068215d2d4a46fb1b98 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Tue, 24 May 2022 14:18:50 -0400 Subject: [PATCH 01/27] Integrating API data into new Aspen Summary page --- controls/urls.py | 3 +- controls/views.py | 186 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 1 deletion(-) diff --git a/controls/urls.py b/controls/urls.py index b8d4df27f..189d57578 100644 --- a/controls/urls.py +++ b/controls/urls.py @@ -43,7 +43,8 @@ url(r'^statement_history/(?P.*)/$', views.statement_history, name="statement_history"), url(r'^restore_to/(?P.*)/(?P.*)/$', views.restore_to_history, name="restore_to"), - url(r'^(?P.*)/aspen/summary$', views.system_summary_1, name="system_summary_1"), + url(r'^(?P.*)/aspen/summary/fake$', views.system_summary_1, name="system_summary_1"), + url(r'^(?P.*)/aspen/summary$', views.system_summary_csam, name="system_summary_csam"), url(r'^(?P.*)/aspen/integrations$', views.system_integrations, name="system_integrations"), # url(r'^(?P.*)/aspen/summary/poams$', views.system_summary_poams, name="system_summary_poams"), url(r'^import-poams$', views.import_poams_xlsx, name="import_poams_xlsx"), diff --git a/controls/views.py b/controls/views.py index 298b1956a..8bc2fa3b2 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3714,6 +3714,192 @@ def system_summary_1(request, system_id): # User does not have permission to this system raise Http404 + +@login_required +def system_summary_csam(request, system_id): + """System Summary page experiment 2 live data""" + + # Retrieve identified System + # system = System.objects.get(id=system_id) + system = System.objects.get(id=system_id) + # Retrieve related selected controls if user has permission on system + # if request.user.has_perm('view_system', system): + if True: + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + + # Retrieve list of deployments for the system + # deployments = system.deployments.all().order_by(Lower('name')) + # controls = system.root_element.controls.all() + # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') + + import random + from django.utils import timezone + + system_name = system.root_element.name + csam_system_id = system.info.get('csam_system_id', None) + if csam_system_id is not None: + from integrations.models import Endpoint + endpoints = Endpoint.objects.filter(endpoint_path=f"/v1/systems/{csam_system_id}") + if len(endpoints) == 1: + # found cached csam data + csam_data = endpoints[0].data + # {'id': 111, + # 'externalId': 'string', + # 'name': 'System A', + # 'description': 'This is a simple test system', + # 'acronym': 'string', + # 'organization': 'string', + # 'subOrganization': 'string', + # 'operationalStatus': 'string', + # 'systemType': 'string', + # 'financialSystem': 'string', + # 'classification': 'string', + # 'contractorSystem': True, + # 'fismaReportable': True, + # 'criticalInfrastructure': True, + # 'missionCritical': True, + # 'purpose': 'string', + # 'ombExhibit': 'string', + # 'uiiCode': 'string', + # 'investmentName': 'string', + # 'portfolio': 'string', + # 'priorFyFunding': 0, + # 'currentFyFunding': 0, + # 'nextFyFunding': 0, + # 'categorization': 'string', + # 'fundingImportStatus': 'string'} + purpose = f"{csam_data['purpose']}" + organization_name = f"{csam_data['organization']} {csam_data['subOrganization']}" + other_id = f"{csam_data['id']}" + system_type = f"{csam_data['systemType']}" + status = f"{csam_data['operationalStatus']}" + impact = f"{csam_data['categorization']}" + else: + # retreive fresh data from CSAM + pass + else: + # Couldn't find CSAM system + + # Sample systems from DHS SORNs + dhs_sorns = [ + { "name": "DHS/ALL-037 E-Authentication Records System of Records", "purpose": """This system collects information in order to authenticate an individual's identity for the purpose of obtaining a credential to electronically access a DHS program or application. This system includes DHS programs or applications that use a third-party identity service provider to provide any of the following credential services: Registration, including identity proofing, issuance, authentication, authorization, and maintenance. This system collects information that allows DHS to track the use of programs and applications for system maintenance and troubleshooting. The system also enables DHS to allow an individual to reuse a credential received when applicable and available."""}, + { "name": "DHS/ALL-032 Official Passport Application and Maintenance Records", "purpose": """The purpose of this system is to collect and maintain a copy of an official passport application or maintenance record on DHS employees and former employees, including political appointees, civilian, and military personnel (and dependents and family members that accompany military members assigned outside the continental United States) assigned or detailed to the Department, individuals who are formally or informally associated with the Department, including advisory committee members, employees of other agencies and departments in the federal government, and other individuals in the private and public sector who are on official business with the Department, who in their official capacity, are applying for an official passport or updating their official passport records where a copy is maintained by the Department."""}, + { "name": "DHS/ALL-034 Emergency Care Medical Records", "purpose": """The purpose of this system is to support MQM oversight to ensure consistent quality medical care and standardize the documentation of care rendered by DHS EMS medical care providers in diverse environments.""" }, + { "name": "DHS/ALL-035 Common Entity Index Prototype (CEI Prototype)", "purpose": """The purpose of this prototype is to determine the feasibility of establishing a centralized index of select biographic information that will allow DHS to provide a consolidated and correlated identity, thereby facilitating and improving DHS's ability to carry out its national security, homeland security, law enforcement, and benefits missions.""" }, + { "name": "DHS/ALL-042 Personnel Networking and Collaboration System of Records.", "purpose": """The purpose of this system is to permit DHS's collection of biographical and professional information of current DHS employees, contractors, and grantees to facilitate connections and collaboration among individuals supporting the Department's mission; aid in the identification of individuals within an organization; and to ensure efficient collaboration within the Department.""" }, + { "name": "DHS/ALL-044 eRulemaking", "purpose": """The purpose of this system is to permit members of the public to review and comment on DHS rulemakings and notices. DHS will use any submitted contact information to seek clarification of a comment, respond to a comment when warranted, and for such other needs as may be associated with the rule making or notice process.""" }, + { "name": "DHS/FEMA-006 Citizen Corps Program", "url": "http://www.gpo.gov/fdsys/pkg/FR-2013-07-22/html/2013-17456.htm", "purpose": "The purpose of this system is to allow state, local, tribal, and territorial communities to setup and register Citizen Corps Councils and CERT programs. Also, this system provides a way for individuals to locate and contact Councils, CERTs, and other Citizen Corps partners for more information regarding volunteer programs and opportunities nation-wide. Additionally, this system uses surveys to assess and enhance communities' preparedness and to improve the effectiveness of the Citizen Corps Program."} + # { "name": "", "purpose": """ """ }, + ] + + random.seed(system_id) + other_id = random.randint(1,2000) + impact = random.choice(["Low Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "High Impact"]) + status = random.choice(["Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Under Development", "Planned"]) + system_from_sorn = random.choice(dhs_sorns) + + # Fix purpose + if "purpose" not in system_from_sorn: + purpose = "Missing" + elif len(system_from_sorn['purpose']) > 750: + purpose = system_from_sorn['purpose'][0:500] + else: + purpose = system_from_sorn['purpose'] + system_name = system_from_sorn['name'].strip(" ").strip(",") + if re.search(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", system_name): + system_name = re.sub(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", '', system_name) + + # Organization + if re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")): + organization_name = "DHS " + re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")).group(1).strip() + else: + organization_name = "DHS" + + # Acronym + if "(" in system_name: + acronym = re.search(r"\((.*)\)", system_name).group(1).strip() + system_name = re.sub(r" \(.*\)", '', system_name) + else: + acronym = "".join([word[0].upper() for word in system_name.replace("(","").replace(")","").split(" ")]) + if len(acronym) > 5: + acronym = acronym[0:3] + if len(acronym) == 1: + acronym = system_name + aka = [acronym] + if len(system_name.split(" ")) > 7: + short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" + aka.append(short_name) + + system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) + hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) + # Dates + from datetime import datetime, date, timedelta, timezone + date1, date2 = datetime(2014, 6, 3, tzinfo=timezone.utc), datetime(2022, 2, 1, tzinfo=timezone.utc) + dates_between = date2 - date1 + total_days = dates_between.days + created = date1 + timedelta(days=random.randrange(total_days)) + next_audit = datetime.now().date() + timedelta(random.randint(40,600)) + next_scan = datetime.combine(datetime.now().date() + timedelta(random.randint(2,12)), datetime.min.time()).replace(tzinfo=timezone.utc) + + # datetime.combine(date.today(), datetime.min.time()) + # next_scan = next_scan.replace(tzinfo=timezone.utc) + dates_between_created = created - date1 + pen_test = created + timedelta(days=random.randrange(dates_between_created.days)) + + # Fake data for System + system = { + "id": system_id, + "other_id": other_id, + "name": system_name, + "organization_name": organization_name, + "aka": aka, + "impact": impact, + "status": status, + "type": system_type, + "created": created, + "hosting_facility": hosting_facility, + "next_audit": next_audit, + "next_scan": next_scan, #"05/01/22", + "security_scan": "Last known-04/20/22 @ 1:23pm", + "pen_test": pen_test, #"Scheduled for 05/05/22", + "config_scan": "Last known-01/17/20 @ 4:32pm", + "purpose": purpose, + "vuln_new_30days": random.randint(0,12), + "vuln_new_rslvd_30days": random.randint(0,20), + "vuln_90days": random.randint(0,15), + "risk_score": random.randint(6,10) + round(random.random(), 1), + "score_1": random.randint(6,10) + round(random.random(), 1), + "score_2": random.randint(6,10) + round(random.random(), 1), + "score_3": random.randint(6,10) + round(random.random(), 1), + "score_4": random.randint(6,10) + round(random.random(), 1), + "score_5": random.randint(6,10) + round(random.random(), 1), + } + + system_events = [ + { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, + { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, + { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} + ] + + # Fix menu data + project.system.root_element.name = system['name'] + project.root_task.title_override = system['name'] + # Return the controls + + context = { + "system": system, + #"project": project, + "system_events": system_events, + # "deployments": deployments, + "display_urls": project_context(project) + } + return render(request, "systems/system_summary_1.html", context) + else: + # User does not have permission to this system + raise Http404 + @login_required def system_integrations(request, system_id): """System Integrations page experiment 1""" From 455579c6b1a2d4a7f16027f93bbd28976d9b9cf0 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Tue, 24 May 2022 16:19:53 -0400 Subject: [PATCH 02/27] Display Aspen description output safe with html --- controls/views.py | 5 +++-- templates/systems/system_summary_1.html | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/controls/views.py b/controls/views.py index 8bc2fa3b2..44d54bb4a 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3770,7 +3770,7 @@ def system_summary_csam(request, system_id): # 'nextFyFunding': 0, # 'categorization': 'string', # 'fundingImportStatus': 'string'} - purpose = f"{csam_data['purpose']}" + purpose = f"{csam_data['description']}" organization_name = f"{csam_data['organization']} {csam_data['subOrganization']}" other_id = f"{csam_data['id']}" system_type = f"{csam_data['systemType']}" @@ -3817,6 +3817,8 @@ def system_summary_csam(request, system_id): else: organization_name = "DHS" + system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) + # Acronym if "(" in system_name: acronym = re.search(r"\((.*)\)", system_name).group(1).strip() @@ -3832,7 +3834,6 @@ def system_summary_csam(request, system_id): short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" aka.append(short_name) - system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) # Dates from datetime import datetime, date, timedelta, timezone diff --git a/templates/systems/system_summary_1.html b/templates/systems/system_summary_1.html index 8b2d0ebd4..db6009078 100644 --- a/templates/systems/system_summary_1.html +++ b/templates/systems/system_summary_1.html @@ -165,7 +165,7 @@

Recent System Related Events

System Summary

-

{{ system.purpose }}

+

{{ system.purpose|safe }}


From dba72a07722146f4d9a07b6ab34773e9eb8de4dd Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Tue, 24 May 2022 16:43:26 -0400 Subject: [PATCH 03/27] Fix Aspen CSAM purpose field --- controls/views.py | 2 +- integrations/csam/mock.py | 8 +++----- templates/systems/system_summary_1.html | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/controls/views.py b/controls/views.py index 44d54bb4a..71f25ed02 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3770,7 +3770,7 @@ def system_summary_csam(request, system_id): # 'nextFyFunding': 0, # 'categorization': 'string', # 'fundingImportStatus': 'string'} - purpose = f"{csam_data['description']}" + purpose = f"{csam_data['purpose']}" organization_name = f"{csam_data['organization']} {csam_data['subOrganization']}" other_id = f"{csam_data['id']}" system_type = f"{csam_data['systemType']}" diff --git a/integrations/csam/mock.py b/integrations/csam/mock.py index eaf88f2e1..6f248113d 100644 --- a/integrations/csam/mock.py +++ b/integrations/csam/mock.py @@ -51,7 +51,6 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): SYSTEMS = { "111": {"id": 111, "externalId": "string", "name": "System A", - "description": "This is a simple test system", "acronym": "string", "organization": "string", "subOrganization": "string", @@ -63,7 +62,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): "fismaReportable": True, "criticalInfrastructure": True, "missionCritical": True, - "purpose": "string", + "purpose": "This is a system with a purpose, a

heading 2> and a

paragraph new

", "ombExhibit": "string", "uiiCode": "string", "investmentName": "string", @@ -77,7 +76,6 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): "222": {"id": 222, "externalId": "string", "name": "System B", - "description": "This is another simple test system", "acronym": "string", "organization": "string", "subOrganization": "string", @@ -89,7 +87,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): "fismaReportable": True, "criticalInfrastructure": True, "missionCritical": True, - "purpose": "string", + "purpose": "This is a system with a purpose, a

heading 2> and a

paragraph new

", "ombExhibit": "string", "uiiCode": "string", "investmentName": "string", @@ -242,7 +240,7 @@ def do_POST(self): elif '222' in request.path: system_id = '222' self.SYSTEMS[system_id]['name'] = self.post_data_json.get('name', self.SYSTEM['name']) - self.SYSTEM[system_id]['description'] = self.post_data_json.get('description', self.SYSTEM['description']) + self.SYSTEM[system_id]['purpose'] = self.post_data_json.get('purpose', "MISSING CONTENT") # Send response self.send_response(200) self.send_header('Content-Type', 'application/json') diff --git a/templates/systems/system_summary_1.html b/templates/systems/system_summary_1.html index db6009078..8aa775ec7 100644 --- a/templates/systems/system_summary_1.html +++ b/templates/systems/system_summary_1.html @@ -39,7 +39,7 @@ .system-heading { font-size:.7em; font-weight:bold; color:#4D4D4D; font-family:Helvetica Neue,"Helvetica","Roboto","Arial",sans-serif;} -.sys-summary-content { font-size:1em; padding-bottom:1em; line-height:1.4em; font-family:Helvetica Neue,"Helvetica","Roboto","Arial",sans-serif; color:#333333;} +.sys-summary-content { font-size:0.9em; padding-bottom:1em; line-height:1.4em; font-family:Helvetica Neue,"Helvetica","Roboto","Arial",sans-serif; color:#333333;} .sys-ownership-details { font-size:.8em; padding:0;} .sys-wide-status { font-size:.7em;} #sys-wide-status td { padding-bottom:4px; } From 063f4e2fa789545fd385287e4c32f5fb520b0940 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Tue, 24 May 2022 17:05:03 -0400 Subject: [PATCH 04/27] Truncate Aspen summary system purpose text --- templates/systems/system_summary_1.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/systems/system_summary_1.html b/templates/systems/system_summary_1.html index 8aa775ec7..6a033df3f 100644 --- a/templates/systems/system_summary_1.html +++ b/templates/systems/system_summary_1.html @@ -165,7 +165,7 @@

Recent System Related Events

System Summary

-

{{ system.purpose|safe }}

+

{{ system.purpose|safe|truncatewords:75 }}


From 5f43ea273281322e3ff50431840c6410d8333054 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Wed, 25 May 2022 02:18:46 -0400 Subject: [PATCH 05/27] Code linting --- controls/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controls/views.py b/controls/views.py index 71f25ed02..cf79baa09 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3810,7 +3810,7 @@ def system_summary_csam(request, system_id): system_name = system_from_sorn['name'].strip(" ").strip(",") if re.search(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", system_name): system_name = re.sub(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", '', system_name) - + # Organization if re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")): organization_name = "DHS " + re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")).group(1).strip() @@ -3888,7 +3888,7 @@ def system_summary_csam(request, system_id): project.system.root_element.name = system['name'] project.root_task.title_override = system['name'] # Return the controls - + context = { "system": system, #"project": project, From 196cf268d5425c81f3c196eedacaa62a510378e3 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Wed, 25 May 2022 03:55:25 -0400 Subject: [PATCH 06/27] Refactor retrieving integrations data DRY Add DRY method system_integrations_aspen to controls/views.py to make DRY retrieving integrations data. --- controls/urls.py | 6 +- controls/views.py | 623 ++++++------------ templates/systems/deployments_list_aspen.html | 8 +- .../systems/system_integrations_aspen.html | 8 +- templates/systems/system_summary_1.html | 2 +- 5 files changed, 224 insertions(+), 423 deletions(-) diff --git a/controls/urls.py b/controls/urls.py index 189d57578..b316c9b4e 100644 --- a/controls/urls.py +++ b/controls/urls.py @@ -43,9 +43,9 @@ url(r'^statement_history/(?P.*)/$', views.statement_history, name="statement_history"), url(r'^restore_to/(?P.*)/(?P.*)/$', views.restore_to_history, name="restore_to"), - url(r'^(?P.*)/aspen/summary/fake$', views.system_summary_1, name="system_summary_1"), - url(r'^(?P.*)/aspen/summary$', views.system_summary_csam, name="system_summary_csam"), - url(r'^(?P.*)/aspen/integrations$', views.system_integrations, name="system_integrations"), + url(r'^(?P.*)/aspen/summary/fake$', views.system_summary_1_aspen, name="system_summary_1"), + url(r'^(?P.*)/aspen/summary$', views.system_summary_aspen, name="system_summary"), + url(r'^(?P.*)/aspen/integrations$', views.system_integrations_aspen, name="system_integrations"), # url(r'^(?P.*)/aspen/summary/poams$', views.system_summary_poams, name="system_summary_poams"), url(r'^import-poams$', views.import_poams_xlsx, name="import_poams_xlsx"), diff --git a/controls/views.py b/controls/views.py index cf79baa09..e6d43f116 100644 --- a/controls/views.py +++ b/controls/views.py @@ -2,6 +2,7 @@ import logging import operator import pathlib +import random import shutil import tempfile from collections import defaultdict @@ -27,6 +28,7 @@ from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils.text import slugify +from django.utils import timezone from django.views import View from django.views.generic import ListView from django.urls import reverse @@ -3576,24 +3578,59 @@ def system_profile_oscal_json(request, system_id): # System Summaries @login_required -def system_summary_1(request, system_id): - """System Summary page experiment 1""" - - # Retrieve identified System - # system = System.objects.get(id=system_id) - system = System.objects.get(id=1) - # Retrieve related selected controls if user has permission on system - # if request.user.has_perm('view_system', system): - if True: - # Retrieve primary system Project - # Temporarily assume only one project and get first project - project = system.projects.all()[0] - - # Retrieve list of deployments for the system - # deployments = system.deployments.all().order_by(Lower('name')) - # controls = system.root_element.controls.all() - # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') +def get_integrations_system_info(request, system_id): + """Returns Integrations info for system""" + system = System.objects.get(id=system_id) + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + system_name = system.root_element.name + + # Retrieve info from integrations + csam_system_id = system.info.get('csam_system_id', None) + if csam_system_id is not None: + from integrations.models import Endpoint + endpoints = Endpoint.objects.filter(endpoint_path=f"/v1/systems/{csam_system_id}") + if len(endpoints) == 1: + # found cached csam data + csam_data = endpoints[0].data + # {'id': 111, + # 'externalId': 'string', + # 'name': 'System A', + # 'description': 'This is a simple test system', + # 'acronym': 'string', + # 'organization': 'string', + # 'subOrganization': 'string', + # 'operationalStatus': 'string', + # 'systemType': 'string', + # 'financialSystem': 'string', + # 'classification': 'string', + # 'contractorSystem': True, + # 'fismaReportable': True, + # 'criticalInfrastructure': True, + # 'missionCritical': True, + # 'purpose': 'string', + # 'ombExhibit': 'string', + # 'uiiCode': 'string', + # 'investmentName': 'string', + # 'portfolio': 'string', + # 'priorFyFunding': 0, + # 'currentFyFunding': 0, + # 'nextFyFunding': 0, + # 'categorization': 'string', + # 'fundingImportStatus': 'string'} + purpose = f"{csam_data['purpose']}" + organization_name = f"{csam_data['organization']} {csam_data['subOrganization']}" + other_id = f"{csam_data['id']}" + system_type = f"{csam_data['systemType']}" + status = f"{csam_data['operationalStatus']}" + impact = f"{csam_data['categorization']}" + else: + # retreive fresh data from CSAM + pass + else: + # Couldn't find CSAM system # Sample systems from DHS SORNs dhs_sorns = [ { "name": "DHS/ALL-037 E-Authentication Records System of Records", "purpose": """This system collects information in order to authenticate an individual's identity for the purpose of obtaining a credential to electronically access a DHS program or application. This system includes DHS programs or applications that use a third-party identity service provider to provide any of the following credential services: Registration, including identity proofing, issuance, authentication, authorization, and maintenance. This system collects information that allows DHS to track the use of programs and applications for system maintenance and troubleshooting. The system also enables DHS to allow an individual to reuse a credential received when applicable and available."""}, @@ -3606,9 +3643,6 @@ def system_summary_1(request, system_id): # { "name": "", "purpose": """ """ }, ] - import random - from django.utils import timezone - random.seed(system_id) other_id = random.randint(1,2000) impact = random.choice(["Low Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "High Impact"]) @@ -3617,11 +3651,13 @@ def system_summary_1(request, system_id): # Fix purpose if "purpose" not in system_from_sorn: - system_from_sorn['purpose'] = "Missing" + purpose = "Missing" elif len(system_from_sorn['purpose']) > 750: - system_from_sorn['purpose'] = system_from_sorn['purpose'][0:500] - # System name - system_name = system_from_sorn['name'].strip(" ").strip(",") + purpose = system_from_sorn['purpose'][0:500] + else: + purpose = system_from_sorn['purpose'] + + # system_name = system_from_sorn['name'].strip(" ").strip(",") if re.search(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", system_name): system_name = re.sub(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", '', system_name) @@ -3631,421 +3667,187 @@ def system_summary_1(request, system_id): else: organization_name = "DHS" - # Acronym - if "(" in system_name: - acronym = re.search(r"\((.*)\)", system_name).group(1).strip() - system_name = re.sub(r" \(.*\)", '', system_name) - else: - acronym = "".join([word[0].upper() for word in system_name.replace("(","").replace(")","").split(" ")]) - if len(acronym) > 5: - acronym = acronym[0:3] - if len(acronym) == 1: - acronym = system_name - aka = [acronym] - if len(system_name.split(" ")) > 7: - short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" - aka.append(short_name) - system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) - hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) - # Dates - from datetime import datetime, date, timedelta, timezone - date1, date2 = datetime(2014, 6, 3, tzinfo=timezone.utc), datetime(2022, 2, 1, tzinfo=timezone.utc) - dates_between = date2 - date1 - total_days = dates_between.days - created = date1 + timedelta(days=random.randrange(total_days)) - next_audit = datetime.now().date() + timedelta(random.randint(40,600)) - next_scan = datetime.combine(datetime.now().date() + timedelta(random.randint(2,12)), datetime.min.time()).replace(tzinfo=timezone.utc) - - # datetime.combine(date.today(), datetime.min.time()) - # next_scan = next_scan.replace(tzinfo=timezone.utc) - dates_between_created = created - date1 - pen_test = created + timedelta(days=random.randrange(dates_between_created.days)) - - # Fake data for System - system = { - "id": system_id, - "other_id": other_id, - "name": system_name, - "organization_name": organization_name, - "aka": aka, - "impact": impact, - "status": status, - "type": system_type, - "created": created, - "hosting_facility": hosting_facility, - "next_audit": next_audit, - "next_scan": next_scan, #"05/01/22", - "security_scan": "Last known-04/20/22 @ 1:23pm", - "pen_test": pen_test, #"Scheduled for 05/05/22", - "config_scan": "Last known-01/17/20 @ 4:32pm", - "purpose": system_from_sorn['purpose'], - "vuln_new_30days": random.randint(0,12), - "vuln_new_rslvd_30days": random.randint(0,20), - "vuln_90days": random.randint(0,15), - "risk_score": random.randint(6,10) + round(random.random(), 1), - "score_1": random.randint(6,10) + round(random.random(), 1), - "score_2": random.randint(6,10) + round(random.random(), 1), - "score_3": random.randint(6,10) + round(random.random(), 1), - "score_4": random.randint(6,10) + round(random.random(), 1), - "score_5": random.randint(6,10) + round(random.random(), 1), - } - - system_events = [ - { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} - ] - # Fix menu data - project.system.root_element.name = system['name'] - project.root_task.title_override = system['name'] - # Return the controls - - context = { - "system": system, - #"project": project, - "system_events": system_events, - # "deployments": deployments, - "display_urls": project_context(project) - } - return render(request, "systems/system_summary_1.html", context) + # Acronym + if "(" in system_name: + acronym = re.search(r"\((.*)\)", system_name).group(1).strip() + system_name = re.sub(r" \(.*\)", '', system_name) else: - # User does not have permission to this system - raise Http404 - + acronym = "".join([word[0].upper() for word in system_name.replace("(","").replace(")","").split(" ")]) + if len(acronym) > 5: + acronym = acronym[0:3] + if len(acronym) == 1: + acronym = system_name + aka = [acronym] + if len(system_name.split(" ")) > 7: + short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" + aka.append(short_name) + + hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) + # Dates + from datetime import datetime, date, timedelta, timezone + date1, date2 = datetime(2014, 6, 3, tzinfo=timezone.utc), datetime(2022, 2, 1, tzinfo=timezone.utc) + dates_between = date2 - date1 + total_days = dates_between.days + created = date1 + timedelta(days=random.randrange(total_days)) + next_audit = datetime.now().date() + timedelta(random.randint(40,600)) + next_scan = datetime.combine(datetime.now().date() + timedelta(random.randint(2,12)), datetime.min.time()).replace(tzinfo=timezone.utc) + + # datetime.combine(date.today(), datetime.min.time()) + # next_scan = next_scan.replace(tzinfo=timezone.utc) + dates_between_created = created - date1 + pen_test = created + timedelta(days=random.randrange(dates_between_created.days)) + + # Data for System + system = { + "id": system_id, + "other_id": other_id, + "name": system_name, + "organization_name": organization_name, + "aka": aka, + "impact": impact, + "status": status, + "type": system_type, + "created": created, + "hosting_facility": hosting_facility, + "next_audit": next_audit, + "next_scan": next_scan, #"05/01/22", + "security_scan": "Last known-04/20/22 @ 1:23pm", + "pen_test": pen_test, #"Scheduled for 05/05/22", + "config_scan": "Last known-01/17/20 @ 4:32pm", + "purpose": purpose, + "vuln_new_30days": random.randint(0,12), + "vuln_new_rslvd_30days": random.randint(0,20), + "vuln_90days": random.randint(0,15), + "risk_score": random.randint(6,10) + round(random.random(), 1), + "score_1": random.randint(6,10) + round(random.random(), 1), + "score_2": random.randint(6,10) + round(random.random(), 1), + "score_3": random.randint(6,10) + round(random.random(), 1), + "score_4": random.randint(6,10) + round(random.random(), 1), + "score_5": random.randint(6,10) + round(random.random(), 1), + } + return system @login_required -def system_summary_csam(request, system_id): - """System Summary page experiment 2 live data""" +def get_integrations_system_events(request, system_id): + """Returns CSAM info for system""" - # Retrieve identified System - # system = System.objects.get(id=system_id) system = System.objects.get(id=system_id) - # Retrieve related selected controls if user has permission on system - # if request.user.has_perm('view_system', system): - if True: - # Retrieve primary system Project - # Temporarily assume only one project and get first project - project = system.projects.all()[0] - - # Retrieve list of deployments for the system - # deployments = system.deployments.all().order_by(Lower('name')) - # controls = system.root_element.controls.all() - # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') - - import random - from django.utils import timezone - - system_name = system.root_element.name - csam_system_id = system.info.get('csam_system_id', None) - if csam_system_id is not None: - from integrations.models import Endpoint - endpoints = Endpoint.objects.filter(endpoint_path=f"/v1/systems/{csam_system_id}") - if len(endpoints) == 1: - # found cached csam data - csam_data = endpoints[0].data - # {'id': 111, - # 'externalId': 'string', - # 'name': 'System A', - # 'description': 'This is a simple test system', - # 'acronym': 'string', - # 'organization': 'string', - # 'subOrganization': 'string', - # 'operationalStatus': 'string', - # 'systemType': 'string', - # 'financialSystem': 'string', - # 'classification': 'string', - # 'contractorSystem': True, - # 'fismaReportable': True, - # 'criticalInfrastructure': True, - # 'missionCritical': True, - # 'purpose': 'string', - # 'ombExhibit': 'string', - # 'uiiCode': 'string', - # 'investmentName': 'string', - # 'portfolio': 'string', - # 'priorFyFunding': 0, - # 'currentFyFunding': 0, - # 'nextFyFunding': 0, - # 'categorization': 'string', - # 'fundingImportStatus': 'string'} - purpose = f"{csam_data['purpose']}" - organization_name = f"{csam_data['organization']} {csam_data['subOrganization']}" - other_id = f"{csam_data['id']}" - system_type = f"{csam_data['systemType']}" - status = f"{csam_data['operationalStatus']}" - impact = f"{csam_data['categorization']}" - else: - # retreive fresh data from CSAM - pass - else: - # Couldn't find CSAM system - - # Sample systems from DHS SORNs - dhs_sorns = [ - { "name": "DHS/ALL-037 E-Authentication Records System of Records", "purpose": """This system collects information in order to authenticate an individual's identity for the purpose of obtaining a credential to electronically access a DHS program or application. This system includes DHS programs or applications that use a third-party identity service provider to provide any of the following credential services: Registration, including identity proofing, issuance, authentication, authorization, and maintenance. This system collects information that allows DHS to track the use of programs and applications for system maintenance and troubleshooting. The system also enables DHS to allow an individual to reuse a credential received when applicable and available."""}, - { "name": "DHS/ALL-032 Official Passport Application and Maintenance Records", "purpose": """The purpose of this system is to collect and maintain a copy of an official passport application or maintenance record on DHS employees and former employees, including political appointees, civilian, and military personnel (and dependents and family members that accompany military members assigned outside the continental United States) assigned or detailed to the Department, individuals who are formally or informally associated with the Department, including advisory committee members, employees of other agencies and departments in the federal government, and other individuals in the private and public sector who are on official business with the Department, who in their official capacity, are applying for an official passport or updating their official passport records where a copy is maintained by the Department."""}, - { "name": "DHS/ALL-034 Emergency Care Medical Records", "purpose": """The purpose of this system is to support MQM oversight to ensure consistent quality medical care and standardize the documentation of care rendered by DHS EMS medical care providers in diverse environments.""" }, - { "name": "DHS/ALL-035 Common Entity Index Prototype (CEI Prototype)", "purpose": """The purpose of this prototype is to determine the feasibility of establishing a centralized index of select biographic information that will allow DHS to provide a consolidated and correlated identity, thereby facilitating and improving DHS's ability to carry out its national security, homeland security, law enforcement, and benefits missions.""" }, - { "name": "DHS/ALL-042 Personnel Networking and Collaboration System of Records.", "purpose": """The purpose of this system is to permit DHS's collection of biographical and professional information of current DHS employees, contractors, and grantees to facilitate connections and collaboration among individuals supporting the Department's mission; aid in the identification of individuals within an organization; and to ensure efficient collaboration within the Department.""" }, - { "name": "DHS/ALL-044 eRulemaking", "purpose": """The purpose of this system is to permit members of the public to review and comment on DHS rulemakings and notices. DHS will use any submitted contact information to seek clarification of a comment, respond to a comment when warranted, and for such other needs as may be associated with the rule making or notice process.""" }, - { "name": "DHS/FEMA-006 Citizen Corps Program", "url": "http://www.gpo.gov/fdsys/pkg/FR-2013-07-22/html/2013-17456.htm", "purpose": "The purpose of this system is to allow state, local, tribal, and territorial communities to setup and register Citizen Corps Councils and CERT programs. Also, this system provides a way for individuals to locate and contact Councils, CERTs, and other Citizen Corps partners for more information regarding volunteer programs and opportunities nation-wide. Additionally, this system uses surveys to assess and enhance communities' preparedness and to improve the effectiveness of the Citizen Corps Program."} - # { "name": "", "purpose": """ """ }, - ] - - random.seed(system_id) - other_id = random.randint(1,2000) - impact = random.choice(["Low Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "High Impact"]) - status = random.choice(["Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Under Development", "Planned"]) - system_from_sorn = random.choice(dhs_sorns) - - # Fix purpose - if "purpose" not in system_from_sorn: - purpose = "Missing" - elif len(system_from_sorn['purpose']) > 750: - purpose = system_from_sorn['purpose'][0:500] - else: - purpose = system_from_sorn['purpose'] - system_name = system_from_sorn['name'].strip(" ").strip(",") - if re.search(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", system_name): - system_name = re.sub(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", '', system_name) - - # Organization - if re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")): - organization_name = "DHS " + re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")).group(1).strip() - else: - organization_name = "DHS" - - system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + system_name = system.root_element.name - # Acronym - if "(" in system_name: - acronym = re.search(r"\((.*)\)", system_name).group(1).strip() - system_name = re.sub(r" \(.*\)", '', system_name) - else: - acronym = "".join([word[0].upper() for word in system_name.replace("(","").replace(")","").split(" ")]) - if len(acronym) > 5: - acronym = acronym[0:3] - if len(acronym) == 1: - acronym = system_name - aka = [acronym] - if len(system_name.split(" ")) > 7: - short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" - aka.append(short_name) + # Retrieve events from integrations + csam_system_id = system.info.get('csam_system_id', None) + system_events = [ + { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, + { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, + { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} + ] + return system_events - hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) - # Dates - from datetime import datetime, date, timedelta, timezone - date1, date2 = datetime(2014, 6, 3, tzinfo=timezone.utc), datetime(2022, 2, 1, tzinfo=timezone.utc) - dates_between = date2 - date1 - total_days = dates_between.days - created = date1 + timedelta(days=random.randrange(total_days)) - next_audit = datetime.now().date() + timedelta(random.randint(40,600)) - next_scan = datetime.combine(datetime.now().date() + timedelta(random.randint(2,12)), datetime.min.time()).replace(tzinfo=timezone.utc) +@login_required +def system_summary_1_aspen(request, system_id): + """System Summary page experiment 1""" - # datetime.combine(date.today(), datetime.min.time()) - # next_scan = next_scan.replace(tzinfo=timezone.utc) - dates_between_created = created - date1 - pen_test = created + timedelta(days=random.randrange(dates_between_created.days)) + system = System.objects.get(id=system_id) + if not request.user.has_perm('view_system', system): + raise Http404 - # Fake data for System - system = { - "id": system_id, - "other_id": other_id, - "name": system_name, - "organization_name": organization_name, - "aka": aka, - "impact": impact, - "status": status, - "type": system_type, - "created": created, - "hosting_facility": hosting_facility, - "next_audit": next_audit, - "next_scan": next_scan, #"05/01/22", - "security_scan": "Last known-04/20/22 @ 1:23pm", - "pen_test": pen_test, #"Scheduled for 05/05/22", - "config_scan": "Last known-01/17/20 @ 4:32pm", - "purpose": purpose, - "vuln_new_30days": random.randint(0,12), - "vuln_new_rslvd_30days": random.randint(0,20), - "vuln_90days": random.randint(0,15), - "risk_score": random.randint(6,10) + round(random.random(), 1), - "score_1": random.randint(6,10) + round(random.random(), 1), - "score_2": random.randint(6,10) + round(random.random(), 1), - "score_3": random.randint(6,10) + round(random.random(), 1), - "score_4": random.randint(6,10) + round(random.random(), 1), - "score_5": random.randint(6,10) + round(random.random(), 1), - } + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] - system_events = [ - { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} - ] + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) - # Fix menu data - project.system.root_element.name = system['name'] - project.root_task.title_override = system['name'] - # Return the controls + # Fix menu data for old vertical menu + project.system.root_element.name = system_summary['name'] + project.root_task.title_override = system_summary['name'] - context = { - "system": system, - #"project": project, - "system_events": system_events, - # "deployments": deployments, - "display_urls": project_context(project) - } - return render(request, "systems/system_summary_1.html", context) - else: - # User does not have permission to this system - raise Http404 + context = { + "system": system_summary, + #"project": project, + "system_events": system_events, + # "deployments": deployments, + "display_urls": project_context(project) + } + return render(request, "systems/system_summary_1.html", context) @login_required -def system_integrations(request, system_id): - """System Integrations page experiment 1""" - - # Retrieve identified System - # system = System.objects.get(id=system_id) - system = System.objects.get(id=1) - - # Retrieve related selected controls if user has permission on system - # if request.user.has_perm('view_system', system): - if True: - # Retrieve primary system Project - # Temporarily assume only one project and get first project - project = system.projects.all()[0] +def system_summary_aspen(request, system_id): + """System Summary page experiment 2 live data""" - # Retrieve list of deployments for the system - # deployments = system.deployments.all().order_by(Lower('name')) - # controls = system.root_element.controls.all() - # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') + system = System.objects.get(id=system_id) + if not request.user.has_perm('view_system', system): + raise Http404 - # Sample systems from DHS SORNs - dhs_sorns = [ - { "name": "DHS/ALL-037 E-Authentication Records System of Records", "purpose": """This system collects information in order to authenticate an individual's identity for the purpose of obtaining a credential to electronically access a DHS program or application. This system includes DHS programs or applications that use a third-party identity service provider to provide any of the following credential services: Registration, including identity proofing, issuance, authentication, authorization, and maintenance. This system collects information that allows DHS to track the use of programs and applications for system maintenance and troubleshooting. The system also enables DHS to allow an individual to reuse a credential received when applicable and available."""}, - { "name": "DHS/ALL-032 Official Passport Application and Maintenance Records", "purpose": """The purpose of this system is to collect and maintain a copy of an official passport application or maintenance record on DHS employees and former employees, including political appointees, civilian, and military personnel (and dependents and family members that accompany military members assigned outside the continental United States) assigned or detailed to the Department, individuals who are formally or informally associated with the Department, including advisory committee members, employees of other agencies and departments in the federal government, and other individuals in the private and public sector who are on official business with the Department, who in their official capacity, are applying for an official passport or updating their official passport records where a copy is maintained by the Department."""}, - { "name": "DHS/ALL-034 Emergency Care Medical Records", "purpose": """The purpose of this system is to support MQM oversight to ensure consistent quality medical care and standardize the documentation of care rendered by DHS EMS medical care providers in diverse environments.""" }, - { "name": "DHS/ALL-035 Common Entity Index Prototype (CEI Prototype)", "purpose": """The purpose of this prototype is to determine the feasibility of establishing a centralized index of select biographic information that will allow DHS to provide a consolidated and correlated identity, thereby facilitating and improving DHS's ability to carry out its national security, homeland security, law enforcement, and benefits missions.""" }, - { "name": "DHS/ALL-042 Personnel Networking and Collaboration System of Records.", "purpose": """The purpose of this system is to permit DHS's collection of biographical and professional information of current DHS employees, contractors, and grantees to facilitate connections and collaboration among individuals supporting the Department's mission; aid in the identification of individuals within an organization; and to ensure efficient collaboration within the Department.""" }, - { "name": "DHS/ALL-044 eRulemaking", "purpose": """The purpose of this system is to permit members of the public to review and comment on DHS rulemakings and notices. DHS will use any submitted contact information to seek clarification of a comment, respond to a comment when warranted, and for such other needs as may be associated with the rule making or notice process.""" }, - { "name": "DHS/FEMA-006 Citizen Corps Program", "url": "http://www.gpo.gov/fdsys/pkg/FR-2013-07-22/html/2013-17456.htm", "purpose": "The purpose of this system is to allow state, local, tribal, and territorial communities to setup and register Citizen Corps Councils and CERT programs. Also, this system provides a way for individuals to locate and contact Councils, CERTs, and other Citizen Corps partners for more information regarding volunteer programs and opportunities nation-wide. Additionally, this system uses surveys to assess and enhance communities' preparedness and to improve the effectiveness of the Citizen Corps Program."} - # { "name": "", "purpose": """ """ }, - ] + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] - import random - from django.utils import timezone + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) - random.seed(system_id) - other_id = random.randint(1,2000) - impact = random.choice(["Low Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "High Impact"]) - status = random.choice(["Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Under Development", "Planned"]) - system_from_sorn = random.choice(dhs_sorns) + # Fix menu data for old vertical menu + project.system.root_element.name = system_summary['name'] + project.root_task.title_override = system_summary['name'] - # Fix purpose - if "purpose" not in system_from_sorn: - system_from_sorn['purpose'] = "Missing" - elif len(system_from_sorn['purpose']) > 750: - system_from_sorn['purpose'] = system_from_sorn['purpose'][0:500] - # System name - system_name = system_from_sorn['name'].strip(" ").strip(",") - if re.search(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", system_name): - system_name = re.sub(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", '', system_name) + context = { + "system": system_summary, + #"project": project, + "system_events": system_events, + # "deployments": deployments, + "display_urls": project_context(project) + } + return render(request, "systems/system_summary_1.html", context) - # Organization - if re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")): - organization_name = "DHS " + re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")).group(1).strip() - else: - organization_name = "DHS" +@login_required +def system_integrations_aspen(request, system_id): + """System Integrations page experiment 1""" - # Acronym - if "(" in system_name: - acronym = re.search(r"\((.*)\)", system_name).group(1).strip() - system_name = re.sub(r" \(.*\)", '', system_name) - else: - acronym = "".join([word[0].upper() for word in system_name.replace("(","").replace(")","").split(" ")]) - if len(acronym) > 5: - acronym = acronym[0:3] - if len(acronym) == 1: - acronym = system_name - aka = [acronym] - if len(system_name.split(" ")) > 7: - short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" - aka.append(short_name) + system = System.objects.get(id=system_id) + if not request.user.has_perm('view_system', system): + raise Http404 - system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) - hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) - # Dates - from datetime import datetime, date, timedelta, timezone - date1, date2 = datetime(2014, 6, 3, tzinfo=timezone.utc), datetime(2022, 2, 1, tzinfo=timezone.utc) - dates_between = date2 - date1 - total_days = dates_between.days - created = date1 + timedelta(days=random.randrange(total_days)) - next_audit = datetime.now().date() + timedelta(random.randint(40,600)) - next_scan = datetime.combine(datetime.now().date() + timedelta(random.randint(2,12)), datetime.min.time()).replace(tzinfo=timezone.utc) + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] - # datetime.combine(date.today(), datetime.min.time()) - # next_scan = next_scan.replace(tzinfo=timezone.utc) - dates_between_created = created - date1 - pen_test = created + timedelta(days=random.randrange(dates_between_created.days)) + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) - # Fake data for System - system = { - "id": system_id, - "other_id": other_id, - "name": system_name, - "organization_name": organization_name, - "aka": aka, - "impact": impact, - "status": status, - "type": system_type, - "created": created, - "hosting_facility": hosting_facility, - "next_audit": next_audit, - "next_scan": next_scan, #"05/01/22", - "security_scan": "Last known-04/20/22 @ 1:23pm", - "pen_test": pen_test, #"Scheduled for 05/05/22", - "config_scan": "Last known-01/17/20 @ 4:32pm", - "purpose": system_from_sorn['purpose'] - } + # Fix menu data for old vertical menu + project.system.root_element.name = system_summary['name'] + project.root_task.title_override = system_summary['name'] - system_events = [ - { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} - ] + # Get integrations + general_integrations = [] + integrations = Integration.objects.all() + for integration in integrations: + general_integration = { + "integration_name": integration.name, + "integration_summary": integration.description + } + general_integrations.append(general_integration) - general_integrations = [] - integrations = Integration.objects.all() - for integration in integrations: - general_integration = { - "integration_name": integration.name, - "integration_summary": integration.description - } - general_integrations.append(general_integration) - - # system_integrations = [ - # { "integration_name": "CSAM", "integration_summary": "Provides access to system information stored in CSAM"}, - # { "integration_name": "GITHUB", "integration_summary": "Includes recent developer changes to source code"}, - # # { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} - # ] + # system_integrations = [ + # { "integration_name": "CSAM", "integration_summary": "Provides access to system information stored in CSAM"}, + # { "integration_name": "GITHUB", "integration_summary": "Includes recent developer changes to source code"}, + # # { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} + # ] - # Fix menu data - project.system.root_element.name = system['name'] - project.root_task.title_override = system['name'] - # Return the controls - context = { - "system": system, - #"project": project, - "system_events": system_events, - "system_integrations": general_integrations, - # "deployments": deployments, - "display_urls": project_context(project) - } - return render(request, "systems/system_integrations_aspen.html", context) - else: - # User does not have permission to this system - raise Http404 + context = { + "system": system_summary, + #"project": project, + "system_events": system_events, + "system_integrations": general_integrations, + # "deployments": deployments, + "display_urls": project_context(project) + } + return render(request, "systems/system_integrations_aspen.html", context) @login_required def system_summary_poams(request, system_id): @@ -4255,7 +4057,6 @@ def import_poams_xlsx(request): messages.add_message(request, messages.ERROR, f"POA&Ms spreadsheet file required.") return JsonResponse({ "status": "ok", "redirect": redirect_url }) - # System Deployments @login_required def system_deployments(request, system_id): diff --git a/templates/systems/deployments_list_aspen.html b/templates/systems/deployments_list_aspen.html index 6e4d6a857..2fae65d3d 100644 --- a/templates/systems/deployments_list_aspen.html +++ b/templates/systems/deployments_list_aspen.html @@ -6,7 +6,7 @@ {% load system_tags %} {% block title %} -Deployments List +System {% endblock %} {% block head %} @@ -46,11 +46,11 @@

A.K.A. {% for aka in
-
+ +
--> -
+

Deployments Overview

diff --git a/templates/systems/system_integrations_aspen.html b/templates/systems/system_integrations_aspen.html index 67fb144ff..3bad4f918 100644 --- a/templates/systems/system_integrations_aspen.html +++ b/templates/systems/system_integrations_aspen.html @@ -6,7 +6,7 @@ {% load system_tags %} {% block title %} -Deployments List +System {% endblock %} {% block head %} @@ -45,11 +45,11 @@

A.K.A. {% for aka in
-
+ +
--> -
+
diff --git a/templates/systems/system_summary_1.html b/templates/systems/system_summary_1.html index 6a033df3f..b59404702 100644 --- a/templates/systems/system_summary_1.html +++ b/templates/systems/system_summary_1.html @@ -6,7 +6,7 @@ {% load system_tags %} {% block title %} -Deployments List +System {% endblock %} {% block head %} From 791f9e0d07795f5248ed5f6d77a9a5affe998bee Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Wed, 25 May 2022 09:12:31 -0400 Subject: [PATCH 07/27] Replace lorem static txt in system_events --- controls/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/controls/views.py b/controls/views.py index e6d43f116..57689a362 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3742,9 +3742,9 @@ def get_integrations_system_events(request, system_id): # Retrieve events from integrations csam_system_id = system.info.get('csam_system_id', None) system_events = [ - { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} + { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Automated penetration test run by SOC"}, + { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Automated weekly security scan will occur Sunday, June 9"}, + { "event_tag": "SYS", "event_summary": "ISSO appointed - Janice Avery (contracor) has been appointed as ISSO for System"} ] return system_events From a6a87bdf3753e0c64431313f88bcd95aa85153eb Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Wed, 25 May 2022 21:13:41 -0400 Subject: [PATCH 08/27] Small fixes to csam integration --- integrations/csam/communicate.py | 2 +- integrations/csam/views.py | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/integrations/csam/communicate.py b/integrations/csam/communicate.py index c8e59ab9b..d215890d2 100644 --- a/integrations/csam/communicate.py +++ b/integrations/csam/communicate.py @@ -22,7 +22,7 @@ class CSAMCommunication(Communication): def __init__(self, **kwargs): self.status_code = None - self.integration_name = self.DESCRIPTION['name'] + self.integration_name = self.DESCRIPTION.get('name', "Description missing") self.integration = get_object_or_404(Integration, name=self.integration_name) self.description = self.integration.description self.config = self.integration.config diff --git a/integrations/csam/views.py b/integrations/csam/views.py index 7d402d27a..0a4ad1e02 100644 --- a/integrations/csam/views.py +++ b/integrations/csam/views.py @@ -115,17 +115,16 @@ def get_system_info(request, system_id=2): def system_info(request, system_id=2): """Retrieve the system information from CSAM""" - system = get_object_or_404(System, pk=system_id) - try: - # system = System.objects.get(pk=system_id) - system = get_object_or_404(System, pk=system_id) - except: - return HttpResponse( - f"" - f"

now: {datetime.now()}

" - f"

System '{system_id}' does not exist.

" - f"") + # try: + # # system = System.objects.get(pk=system_id) + # system = get_object_or_404(System, pk=system_id) + # except: + # return HttpResponse( + # f"" + # f"

now: {datetime.now()}

" + # f"

System '{system_id}' does not exist.

" + # f"") # TODO: Check user permission to view communication = set_integration() From c6e8441d63890111eda9167c796c289d26798989 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Wed, 25 May 2022 22:01:50 -0400 Subject: [PATCH 09/27] Display each integrations base_url on Aspen integrations page --- controls/views.py | 3 ++- templates/systems/system_integrations_aspen.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/controls/views.py b/controls/views.py index 57689a362..f75863568 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3829,7 +3829,8 @@ def system_integrations_aspen(request, system_id): for integration in integrations: general_integration = { "integration_name": integration.name, - "integration_summary": integration.description + "integration_summary": integration.description, + "integration_base_url": integration.config.get('base_url', None) } general_integrations.append(general_integration) diff --git a/templates/systems/system_integrations_aspen.html b/templates/systems/system_integrations_aspen.html index 3bad4f918..0b3a4a722 100644 --- a/templates/systems/system_integrations_aspen.html +++ b/templates/systems/system_integrations_aspen.html @@ -66,7 +66,7 @@

A.K.A. {% for aka in {% for si in system_integrations %} - + {% endfor %}
{{ si.integration_name }}
{{ si.integration_summary }}[configure]
{{ si.integration_name }}
{{ si.integration_summary }}{{ si.integration_base_url }}[configure]
From 0d60ab23f9a7587a4da7a15cc67807839ff3e57f Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Thu, 26 May 2022 03:19:19 -0400 Subject: [PATCH 10/27] Start adding Aspen Components, POA&Ms pages --- controls/urls.py | 7 +- controls/views.py | 297 +++++++----------- templates/summary-horizontal-nav.html | 4 +- .../systems/components_selected_aspen.html | 151 +++++++++ templates/systems/deployments_list_aspen.html | 6 +- 5 files changed, 278 insertions(+), 187 deletions(-) create mode 100644 templates/systems/components_selected_aspen.html diff --git a/controls/urls.py b/controls/urls.py index b316c9b4e..75c77c466 100644 --- a/controls/urls.py +++ b/controls/urls.py @@ -46,8 +46,6 @@ url(r'^(?P.*)/aspen/summary/fake$', views.system_summary_1_aspen, name="system_summary_1"), url(r'^(?P.*)/aspen/summary$', views.system_summary_aspen, name="system_summary"), url(r'^(?P.*)/aspen/integrations$', views.system_integrations_aspen, name="system_integrations"), - # url(r'^(?P.*)/aspen/summary/poams$', views.system_summary_poams, name="system_summary_poams"), - url(r'^import-poams$', views.import_poams_xlsx, name="import_poams_xlsx"), # Systems Assessment Results url(r'^(?P.*)/assessments$', views.system_assessment_results_list, name="system_assessment_results_list"), @@ -70,6 +68,7 @@ url(r'^smt/_update_smt_prototype/$', views.update_smt_prototype), # System Components/Elements + url(r'^(?P.*)/aspen/components/selected$', views.SelectedComponentsListAspen.as_view(), name="components_selected_aspen"), url(r'^(?P.*)/components/selected$', views.SelectedComponentsList.as_view(), name="components_selected"), url(r'^(?P.*)/components/selected/export/opencontrol$', views.export_system_opencontrol, name="export_system_opencontrol"), url(r'^(?P.*)/component/(?P.*)/download/oscal/json$', @@ -82,7 +81,6 @@ url(r'^(?P.*)/controls/updated$', views.controls_updated, name="controls_updated"), # Component Library - url(r'^components$', views.component_library, name="component_library"), url(r'^components/compare$', views.compare_components, name="compare_components"), url(r'^components/new$', views.new_element, name="new_element"), @@ -113,6 +111,9 @@ url(r'^(?P.*)/controls/baseline/(?P.*)/(?P.*)/_assign$', views.assign_baseline, name="assign_baseline"), # Poams + url(r'^(?P.*)/aspen/poams$', views.system_poams_aspen, name="system_poams_aspen"), + url(r'^import-poams$', views.import_poams_xlsx, name="import_poams_xlsx"), + url(r'^(?P.*)/poams$', views.poams_list, name="poams_list"), url(r'^(?P.*)/poams/new$', views.new_poam, name="new_poam"), url(r'^(?P.*)/poams/(?P.*)/edit$', views.edit_poam, name="edit_poam"), diff --git a/controls/views.py b/controls/views.py index f75863568..6a270c842 100644 --- a/controls/views.py +++ b/controls/views.py @@ -371,7 +371,6 @@ def controls_updated(request, system_id): # User does not have permission to this system raise Http404 - @login_required def edit_element(request, element_id): """ @@ -451,6 +450,53 @@ def get_context_data(self, **kwargs): # User does not have permission to this system raise Http404 +class SelectedComponentsListAspen(ListView): + """ + Display System's selected components view + """ + model = Element + template_name = 'systems/components_selected_aspen.html' + context_object_name = 'system_elements' + ordering = ['name'] + paginate_by = 25 + + def get_queryset(self): + """ + Return the systems producer elements. + """ + system = System.objects.get(id=self.kwargs['system_id']) + return [element for element in system.producer_elements if element.element_type != "system"] + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + # Retrieve identified System + + system = System.objects.get(id=self.kwargs['system_id']) + system_summary = get_integrations_system_info(self.request, self.kwargs['system_id']) + + system_proposals = [] + system_proposal_elements = [] + for proposal in system.proposals.all(): + system_proposals.append(proposal) + system_proposal_elements.append(proposal.requested_element) + # Retrieve related selected controls if user has permission on system + if self.request.user.has_perm('view_system', system): + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.first() + context['project'] = project + context['system'] = system_summary + # context['system'] = system + context['system_proposals'] = system_proposals + context['system_proposal_elements'] = system_proposal_elements + context['elements'] = Element.objects.all().exclude(element_type='system') + context["display_urls"] = project_context(project) + return context + else: + # User does not have permission to this system + raise Http404 + + @login_required def component_library(request): """Display the library of components""" @@ -798,7 +844,6 @@ def as_json(self): oscal_string = json.dumps(of, sort_keys=False, indent=2) return oscal_string - class ComponentSerializer(object): def __init__(self, element, impl_smts): @@ -1660,7 +1705,6 @@ def import_component(request): result = ComponentImporter().import_components_as_json(import_name, oscal_component_json, request) return component_library(request) - def raise_404_if_not_permitted_to_statement(request, statement, system_permission='view_system'): """Raises a 404 if the user doesn't have the statement system permission""" while True: @@ -2621,7 +2665,6 @@ def request_message(request, system_id, element_id): @login_required def add_system_component(request, system_id): """Add an existing element and its statements to a system""" -# Setting a breakpoint in the code. if request.method != "POST": return HttpResponseNotAllowed(["POST"]) @@ -2667,8 +2710,7 @@ def add_system_component(request, system_id): # this issue may be best addressed elsewhere. # Component already added to system. Do not add the component (element) to the system again. - - + if producer_element.id in elements_selected_ids: messages.add_message(request, messages.ERROR, f'Component "{producer_element.name}" already exists in selected components.') @@ -2713,8 +2755,7 @@ def add_system_component(request, system_id): return HttpResponseRedirect(form_values['redirect_url']) else: return HttpResponseRedirect("/systems/{}/components/selected".format(system_id)) - - + @login_required def search_system_component(request): """Add an existing element and its statements to a system""" @@ -3576,7 +3617,6 @@ def system_profile_oscal_json(request, system_id): return response # System Summaries - @login_required def get_integrations_system_info(request, system_id): """Returns Integrations info for system""" @@ -3851,163 +3891,61 @@ def system_integrations_aspen(request, system_id): return render(request, "systems/system_integrations_aspen.html", context) @login_required -def system_summary_poams(request, system_id): +def system_poams_aspen(request, system_id): """System Summary page experiment POA&Ms""" - # Retrieve identified System system = System.objects.get(id=system_id) - # system = System.objects.get(id=1) - # Retrieve related selected controls if user has permission on system - # if request.user.has_perm('view_system', system): - if True: - # Retrieve primary system Project - # Temporarily assume only one project and get first project - project = system.projects.all()[0] - - # Retrieve list of deployments for the system - # deployments = system.deployments.all().order_by(Lower('name')) - # controls = system.root_element.controls.all() - # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') - - # Sample systems from DHS SORNs - dhs_sorns = [ - { "name": "DHS/ALL-037 E-Authentication Records System of Records", "purpose": """This system collects information in order to authenticate an individual's identity for the purpose of obtaining a credential to electronically access a DHS program or application. This system includes DHS programs or applications that use a third-party identity service provider to provide any of the following credential services: Registration, including identity proofing, issuance, authentication, authorization, and maintenance. This system collects information that allows DHS to track the use of programs and applications for system maintenance and troubleshooting. The system also enables DHS to allow an individual to reuse a credential received when applicable and available."""}, - { "name": "DHS/ALL-032 Official Passport Application and Maintenance Records", "purpose": """The purpose of this system is to collect and maintain a copy of an official passport application or maintenance record on DHS employees and former employees, including political appointees, civilian, and military personnel (and dependents and family members that accompany military members assigned outside the continental United States) assigned or detailed to the Department, individuals who are formally or informally associated with the Department, including advisory committee members, employees of other agencies and departments in the federal government, and other individuals in the private and public sector who are on official business with the Department, who in their official capacity, are applying for an official passport or updating their official passport records where a copy is maintained by the Department."""}, - { "name": "DHS/ALL-034 Emergency Care Medical Records", "purpose": """The purpose of this system is to support MQM oversight to ensure consistent quality medical care and standardize the documentation of care rendered by DHS EMS medical care providers in diverse environments.""" }, - { "name": "DHS/ALL-035 Common Entity Index Prototype (CEI Prototype)", "purpose": """The purpose of this prototype is to determine the feasibility of establishing a centralized index of select biographic information that will allow DHS to provide a consolidated and correlated identity, thereby facilitating and improving DHS's ability to carry out its national security, homeland security, law enforcement, and benefits missions.""" }, - { "name": "DHS/ALL-042 Personnel Networking and Collaboration System of Records.", "purpose": """The purpose of this system is to permit DHS's collection of biographical and professional information of current DHS employees, contractors, and grantees to facilitate connections and collaboration among individuals supporting the Department's mission; aid in the identification of individuals within an organization; and to ensure efficient collaboration within the Department.""" }, - { "name": "DHS/ALL-044 eRulemaking", "purpose": """The purpose of this system is to permit members of the public to review and comment on DHS rulemakings and notices. DHS will use any submitted contact information to seek clarification of a comment, respond to a comment when warranted, and for such other needs as may be associated with the rule making or notice process.""" }, - { "name": "DHS/FEMA-006 Citizen Corps Program", "url": "http://www.gpo.gov/fdsys/pkg/FR-2013-07-22/html/2013-17456.htm", "purpose": "The purpose of this system is to allow state, local, tribal, and territorial communities to setup and register Citizen Corps Councils and CERT programs. Also, this system provides a way for individuals to locate and contact Councils, CERTs, and other Citizen Corps partners for more information regarding volunteer programs and opportunities nation-wide. Additionally, this system uses surveys to assess and enhance communities' preparedness and to improve the effectiveness of the Citizen Corps Program."} - # { "name": "", "purpose": """ """ }, - ] - - import random - from django.utils import timezone - - random.seed(system_id) - other_id = random.randint(1,2000) - impact = random.choice(["Low Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "Moderate Impact", "High Impact"]) - status = random.choice(["Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Operational", "Under Development", "Planned"]) - system_from_sorn = random.choice(dhs_sorns) - - # Fix purpose - if "purpose" not in system_from_sorn: - system_from_sorn['purpose'] = "Missing" - elif len(system_from_sorn['purpose']) > 750: - system_from_sorn['purpose'] = system_from_sorn['purpose'][0:500] - # System name - system_name = system_from_sorn['name'].strip(" ").strip(",") - if re.search(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", system_name): - system_name = re.sub(r"DHS/[A-Za-z/&0-9-]+[0-9]{0,4} ", '', system_name) - - # Organization - if re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")): - organization_name = "DHS " + re.search(r"DHS/([A-Za-z]{0,4})", system_from_sorn['name'].strip(" ").strip(",")).group(1).strip() - else: - organization_name = "DHS" - - # Acronym - if "(" in system_name: - acronym = re.search(r"\((.*)\)", system_name).group(1).strip() - system_name = re.sub(r" \(.*\)", '', system_name) - else: - acronym = "".join([word[0].upper() for word in system_name.replace("(","").replace(")","").split(" ")]) - if len(acronym) > 5: - acronym = acronym[0:3] - if len(acronym) == 1: - acronym = system_name - aka = [acronym] - if len(system_name.split(" ")) > 7: - short_name = " ".join([word for word in system_name.split(" ")[0:2]]) + " System" - aka.append(short_name) + if not request.user.has_perm('view_system', system): + raise Http404 - system_type = random.choice(["General Support System", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Major Application", "Minor Application", ]) - hosting_facility = random.choice(["DISC", "AWS", "AWS","AWS", "AWS", "DC-1", "AWS", "AWS", "Azure", "AWS", "AWS", "AWS", "DC-1", ]) - # Dates - from datetime import datetime, date, timedelta, timezone - date1, date2 = datetime(2014, 6, 3, tzinfo=timezone.utc), datetime(2022, 2, 1, tzinfo=timezone.utc) - dates_between = date2 - date1 - total_days = dates_between.days - created = date1 + timedelta(days=random.randrange(total_days)) - next_audit = datetime.now().date() + timedelta(random.randint(40,600)) - next_scan = datetime.combine(datetime.now().date() + timedelta(random.randint(2,12)), datetime.min.time()).replace(tzinfo=timezone.utc) - - # datetime.combine(date.today(), datetime.min.time()) - # next_scan = next_scan.replace(tzinfo=timezone.utc) - dates_between_created = created - date1 - pen_test = created + timedelta(days=random.randrange(dates_between_created.days)) - - # Fake data for System - system = { - "id": system_id, - "other_id": other_id, - "name": system_name, - "organization_name": organization_name, - "aka": aka, - "impact": impact, - "status": status, - "type": system_type, - "created": created, - "hosting_facility": hosting_facility, - "next_audit": next_audit, - "next_scan": next_scan, #"05/01/22", - "security_scan": "Last known-04/20/22 @ 1:23pm", - "pen_test": pen_test, #"Scheduled for 05/05/22", - "config_scan": "Last known-01/17/20 @ 4:32pm", - "purpose": system_from_sorn['purpose'] - } + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] - system_events = [ - { "event_tag": "TEST", "event_summary": "Penetration test scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SCAN", "event_summary": "Security scan scheduled - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do..."}, - { "event_tag": "SYS", "event_summary": "Isso appointed - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..."} - ] + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) - # Fix menu data - project.system.root_element.name = system['name'] - project.root_task.title_override = system['name'] - # Return the controls + # Fix menu data for old vertical menu + project.system.root_element.name = system_summary['name'] + project.root_task.title_override = system_summary['name'] - # Example reading POA&Ms from xlsx file using Pandas - # This is to just demonstrate reading POA&Ms from imported spreadsheet - # TODO: Move to a serializer and filter for one sysyem only - # import pandas - # poams_list = [] - # fn = "local/poams_list.xlsx" - # if pathlib.Path(fn).is_file(): - # try: - # df_dict = pandas.read_excel(fn, header=1) - # for index, row in df_dict.iterrows(): - # poam_dict = { - # "id": row.get('CSAM ID', ""), - # "CSAM_ID": row.get('CSAM ID', "" ), - # "Org": row.get('Org', "" ), - # "Sub_Org": row.get('Sub Org', "" ), - # "System_Name": row.get('System Name', "" ), - # "POAM_ID": row.get('POAM ID', "" ), - # "POAM_Title": row.get('POAM Title', "" ), - # "System_Type": row.get('System Type', "" ), - # "Detailed_Weakness_Description": row.get('Detailed Weakness Description', "" ), - # "Status": row.get('Status', "" ) - # } - # poams_list.append(poam_dict) - # except FileNotFoundError as e: - # logger.error(f"Error reading file {fn}: {e}") - # except Exception as e: - # logger.error(f"Other Error reading file {fn}: {e}") + poams_list = [] + + # Example reading POA&Ms from xlsx file using Pandas + # This is to just demonstrate reading POA&Ms from imported spreadsheet + # TODO: Move to a serializer and filter for one sysyem only + # import pandas + # poams_list = [] + # fn = "local/poams_list.xlsx" + # if pathlib.Path(fn).is_file(): + # try: + # df_dict = pandas.read_excel(fn, header=1) + # for index, row in df_dict.iterrows(): + # poam_dict = { + # "id": row.get('CSAM ID', ""), + # "CSAM_ID": row.get('CSAM ID', "" ), + # "Org": row.get('Org', "" ), + # "Sub_Org": row.get('Sub Org', "" ), + # "System_Name": row.get('System Name', "" ), + # "POAM_ID": row.get('POAM ID', "" ), + # "POAM_Title": row.get('POAM Title', "" ), + # "System_Type": row.get('System Type', "" ), + # "Detailed_Weakness_Description": row.get('Detailed Weakness Description', "" ), + # "Status": row.get('Status', "" ) + # } + # poams_list.append(poam_dict) + # except FileNotFoundError as e: + # logger.error(f"Error reading file {fn}: {e}") + # except Exception as e: + # logger.error(f"Other Error reading file {fn}: {e}") - context = { - "system": system, - #"project": project, - "system_events": system_events, - # "deployments": deployments, - # "poams_list": poams_list, - "display_urls": project_context(project) - } - return render(request, "systems/system_summary_2.html", context) - else: - # User does not have permission to this system - raise Http404 + context = { + "system": system, + "system_events": system_events, + "poams_list": poams_list, + "display_urls": project_context(project) + } + return render(request, "systems/system_summary_2.html", context) @login_required @transaction.atomic @@ -4065,29 +4003,30 @@ def system_deployments(request, system_id): # Retrieve identified System system = System.objects.get(id=system_id) - # Retrieve related selected controls if user has permission on system - if request.user.has_perm('view_system', system): - # Retrieve primary system Project - # Temporarily assume only one project and get first project - project = system.projects.all()[0] + if not request.user.has_perm('view_system', system): + raise Http404 - # Retrieve list of deployments for the system - deployments = system.deployments.all().order_by(Lower('name')) - # controls = system.root_element.controls.all() - # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] - # Return the controls - context = { - "system": system, - "project": project, - "deployments": deployments, - "display_urls": project_context(project) - } - # return render(request, "systems/deployments_list.html", context) - return render(request, "systems/deployments_list_aspen.html", context) - else: - # User does not have permission to this system - raise Http404 + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) + + # Retrieve list of deployments for the system + deployments = system.deployments.all().order_by(Lower('name')) + # controls = system.root_element.controls.all() + # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') + + # Return the controls + context = { + "system": system_summary, + "project": project, + "deployments": deployments, + "display_urls": project_context(project) + } + # return render(request, "systems/deployments_list.html", context) + return render(request, "systems/deployments_list_aspen.html", context) @login_required def manage_system_deployment(request, system_id, deployment_id=None): diff --git a/templates/summary-horizontal-nav.html b/templates/summary-horizontal-nav.html index fa67ff513..f570b2441 100644 --- a/templates/summary-horizontal-nav.html +++ b/templates/summary-horizontal-nav.html @@ -28,10 +28,10 @@

diff --git a/templates/systems/components_selected_aspen.html b/templates/systems/components_selected_aspen.html new file mode 100644 index 000000000..6183527ac --- /dev/null +++ b/templates/systems/components_selected_aspen.html @@ -0,0 +1,151 @@ +{% extends "summary-base.html" %} +{% load humanize %} +{% load guardian_tags %} +{% load static %} +{% load q %} +{% load system_tags %} + +{% block title %} +System +{% endblock %} + +{% block head %} +{{block.super}} +{% include "controls/_style-controls.html" %} +{% endblock %} + + + + +{% block body_content %} + + + +
+
+
+

{{ system.impact }}

+

{{ system.name }}

+

A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

+
+ +
Organization-wide Initiative Status
+
+ + + + +
 
800-53 rev5 migration
 
Log4J remediation solution (updated 4/21/22)
 
Q3 Audit
+
+
+
+ +{% include "summary-horizontal-nav.html" %} +
+
+
+ + + +
+ +
+

Components Overview

+ +
+

+ Deployments are instances of your system installed and operating in your organization. +

+
+ +
+

Deployment Details

+
+
+ + + + + + +
Location: {{ system.other_id }}Chicago, IL
Hosting Facility: {{ system.hosting_facility }}Data Center 1
Status: {{ system.status }}Production
Deployment Type: {{ system.type }}Automated
+
+
+ + + + + +
Recent Deployment: {{ system.created|naturaltime }}
Deployment Fequency: {{ system.next_audit }}bi-weekly
Next Scan: {{ system.next_scan|naturaltime }}
Approx. Assets: {{ system.security_scan }}5
+
+
+ +
+ +
+ + +
+
+ + + + + {% if deployments|length < 1 %} +
+
+

No Deployments are currently identified for this system.

+
+
+ {% else %} + {% for deployment in deployments %} + +
+
+ {{ deployment.name }} + {{ deployment.description }}
Updated {{ deployment.updated|timesince}} ago + +   + + +
+
+
+ {% endfor %} + {% endif %} + + +
+
+ + +
+ + + + + + +
+
+ + + + + +{% endblock %} + +{% block scripts %} + {{ block.super }} + + +{% endblock %} diff --git a/templates/systems/deployments_list_aspen.html b/templates/systems/deployments_list_aspen.html index 2fae65d3d..c6534d149 100644 --- a/templates/systems/deployments_list_aspen.html +++ b/templates/systems/deployments_list_aspen.html @@ -25,9 +25,9 @@
-

{{ system.impact }}Moderate Impact

-

{{ system.name }}eRulemaking

-

A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"eRulemaking

+

{{ system.impact }}

+

{{ system.name }}

+

A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

Organization-wide Initiative Status
From 8d71cea6a715160afdbd74abd9884aa1fcbae1c5 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Thu, 26 May 2022 04:01:11 -0400 Subject: [PATCH 11/27] Continuing to build out Aspen summary pages --- controls/urls.py | 1 + controls/views.py | 149 ++++++++++++++---------- templates/summary-horizontal-nav.html | 4 +- templates/systems/poams_list_aspen.html | 127 ++++++++++++++++++++ templates/systems/system_summary_1.html | 82 +------------ 5 files changed, 223 insertions(+), 140 deletions(-) create mode 100644 templates/systems/poams_list_aspen.html diff --git a/controls/urls.py b/controls/urls.py index 75c77c466..90133c082 100644 --- a/controls/urls.py +++ b/controls/urls.py @@ -56,6 +56,7 @@ url(r'^(?P.*)/sar/(?P.*)/history$', views.system_assessment_result_history, name="system_assessment_result_history"), # Systems Inventory and Deployments + url(r'^(?P.*)/aspen/deployments$', views.system_deployments_aspen, name="system_deployments_aspen"), url(r'^(?P.*)/deployments$', views.system_deployments, name="system_deployments"), url(r'^(?P.*)/deployment/new$', views.manage_system_deployment, name="new_system_deployment"), url(r'^(?P.*)/deployment/(?P.*)/edit$', views.manage_system_deployment, name="manage_system_deployment"), diff --git a/controls/views.py b/controls/views.py index 6a270c842..9ee0c1cf1 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3151,7 +3151,64 @@ def export_system_opencontrol(request, system_id): # User does not have permission to this system raise Http404 -# PoamS +# Poams +@login_required +def system_poams_aspen(request, system_id): + """System Summary page experiment POA&Ms""" + + system = System.objects.get(id=system_id) + if not request.user.has_perm('view_system', system): + raise Http404 + + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) + + # Fix menu data for old vertical menu + project.system.root_element.name = system_summary['name'] + project.root_task.title_override = system_summary['name'] + + controls = system.root_element.controls.all() + poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') + + # Example reading POA&Ms from xlsx file using Pandas + # This is to just demonstrate reading POA&Ms from imported spreadsheet + # TODO: Move to a serializer and filter for one sysyem only + # import pandas + # poams_list = [] + # fn = "local/poams_list.xlsx" + # if pathlib.Path(fn).is_file(): + # try: + # df_dict = pandas.read_excel(fn, header=1) + # for index, row in df_dict.iterrows(): + # poam_dict = { + # "id": row.get('CSAM ID', ""), + # "CSAM_ID": row.get('CSAM ID', "" ), + # "Org": row.get('Org', "" ), + # "Sub_Org": row.get('Sub Org', "" ), + # "System_Name": row.get('System Name', "" ), + # "POAM_ID": row.get('POAM ID', "" ), + # "POAM_Title": row.get('POAM Title', "" ), + # "System_Type": row.get('System Type', "" ), + # "Detailed_Weakness_Description": row.get('Detailed Weakness Description', "" ), + # "Status": row.get('Status', "" ) + # } + # poams_list.append(poam_dict) + # except FileNotFoundError as e: + # logger.error(f"Error reading file {fn}: {e}") + # except Exception as e: + # logger.error(f"Other Error reading file {fn}: {e}") + + context = { + "system": system_summary, + "poam_smts": poam_smts, + "display_urls": project_context(project) + } + return render(request, "systems/poams_list_aspen.html", context) + @login_required def poams_list(request, system_id): """List Poams for a system""" @@ -3890,63 +3947,6 @@ def system_integrations_aspen(request, system_id): } return render(request, "systems/system_integrations_aspen.html", context) -@login_required -def system_poams_aspen(request, system_id): - """System Summary page experiment POA&Ms""" - - system = System.objects.get(id=system_id) - if not request.user.has_perm('view_system', system): - raise Http404 - - # Retrieve primary system Project - # Temporarily assume only one project and get first project - project = system.projects.all()[0] - - system_summary = get_integrations_system_info(request, system_id) - system_events = get_integrations_system_events(request, system_id) - - # Fix menu data for old vertical menu - project.system.root_element.name = system_summary['name'] - project.root_task.title_override = system_summary['name'] - - poams_list = [] - - # Example reading POA&Ms from xlsx file using Pandas - # This is to just demonstrate reading POA&Ms from imported spreadsheet - # TODO: Move to a serializer and filter for one sysyem only - # import pandas - # poams_list = [] - # fn = "local/poams_list.xlsx" - # if pathlib.Path(fn).is_file(): - # try: - # df_dict = pandas.read_excel(fn, header=1) - # for index, row in df_dict.iterrows(): - # poam_dict = { - # "id": row.get('CSAM ID', ""), - # "CSAM_ID": row.get('CSAM ID', "" ), - # "Org": row.get('Org', "" ), - # "Sub_Org": row.get('Sub Org', "" ), - # "System_Name": row.get('System Name', "" ), - # "POAM_ID": row.get('POAM ID', "" ), - # "POAM_Title": row.get('POAM Title', "" ), - # "System_Type": row.get('System Type', "" ), - # "Detailed_Weakness_Description": row.get('Detailed Weakness Description', "" ), - # "Status": row.get('Status', "" ) - # } - # poams_list.append(poam_dict) - # except FileNotFoundError as e: - # logger.error(f"Error reading file {fn}: {e}") - # except Exception as e: - # logger.error(f"Other Error reading file {fn}: {e}") - - context = { - "system": system, - "system_events": system_events, - "poams_list": poams_list, - "display_urls": project_context(project) - } - return render(request, "systems/system_summary_2.html", context) - @login_required @transaction.atomic def import_poams_xlsx(request): @@ -3998,7 +3998,7 @@ def import_poams_xlsx(request): # System Deployments @login_required -def system_deployments(request, system_id): +def system_deployments_aspen(request, system_id): """List deployments for a system""" # Retrieve identified System @@ -4028,6 +4028,37 @@ def system_deployments(request, system_id): # return render(request, "systems/deployments_list.html", context) return render(request, "systems/deployments_list_aspen.html", context) +@login_required +def system_deployments(request, system_id): + """List deployments for a system""" + + # Retrieve identified System + system = System.objects.get(id=system_id) + if not request.user.has_perm('view_system', system): + raise Http404 + + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + + system_summary = get_integrations_system_info(request, system_id) + system_events = get_integrations_system_events(request, system_id) + + # Retrieve list of deployments for the system + deployments = system.deployments.all().order_by(Lower('name')) + # controls = system.root_element.controls.all() + # poam_smts = system.root_element.statements_consumed.filter(statement_type="POAM").order_by('-updated') + + # Return the controls + context = { + "system": system_summary, + "project": project, + "deployments": deployments, + "display_urls": project_context(project) + } + # return render(request, "systems/deployments_list.html", context) + return render(request, "systems/deployments_list.html", context) + @login_required def manage_system_deployment(request, system_id, deployment_id=None): """Form to create or edit system deployment""" diff --git a/templates/summary-horizontal-nav.html b/templates/summary-horizontal-nav.html index f570b2441..3c78c6ac1 100644 --- a/templates/summary-horizontal-nav.html +++ b/templates/summary-horizontal-nav.html @@ -29,8 +29,8 @@
  • homeSystem
  • listControls
  • settings_input_componentComponents
  • -
  • check_boxPOA&Ms
  • -
  • hubDeployments
  • +
  • check_boxPOA&Ms
  • +
  • hubDeployments
  • hubIntegrations
  • diff --git a/templates/systems/poams_list_aspen.html b/templates/systems/poams_list_aspen.html new file mode 100644 index 000000000..539bc35d5 --- /dev/null +++ b/templates/systems/poams_list_aspen.html @@ -0,0 +1,127 @@ +{% extends "summary-base.html" %} +{% load humanize %} +{% load guardian_tags %} +{% load static %} +{% load q %} +{% load system_tags %} + +{% block title %} + POA&Ms +{% endblock %} + +{% block head %} +{{block.super}} +{% include "controls/_style-controls.html" %} +{% endblock %} + + + + +{% block body_content %} + +
    +
    +
    +

    {{ system.impact }}

    +

    {{ system.name }}

    +

    A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

    +
    + +
    Organization-wide Initiative Status
    +
    + + + + +
     
    800-53 rev5 migration
     
    Log4J remediation solution (updated 4/21/22)
     
    Q3 Audit
    +
    +
    +
    + +{% include "summary-horizontal-nav.html" %} +
    +
    +
    + + + +
    + +
    +

    POA&Ms Overview

    + +
    +

    + POA&Ms (Plan of Action & Milestones) are risk findings and/or corrective action plans. +

    + +
    +
    POA&Ms
    +
     
    +
    + New POA&M + +
    +
    + {% if poam_smts|length < 1 %} +
    +
    +

    No POA&Ms are currently identified for this system.

    +
    +
    + {% else %} + {% for poam_smt in poam_smts %} +
    + +
    + {{ poam_smt.poam.weakness_name }} +
    +
    + {{ poam_smt.status }} +
    +
    + {{ poam_smt.updated|timesince}} ago +
    +
    + {% endfor %} + {% endif %} +
    + +
    +
    + + +{% endblock %} + +{% block scripts %} + {{ block.super }} + + +{% endblock %} diff --git a/templates/systems/system_summary_1.html b/templates/systems/system_summary_1.html index b59404702..69106457c 100644 --- a/templates/systems/system_summary_1.html +++ b/templates/systems/system_summary_1.html @@ -20,78 +20,14 @@ {% block body_content %} +

    {{ system.impact }}

    {{ system.name }}

    -

    A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}

    +

    A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

    Organization-wide Initiative Status
    @@ -105,19 +41,7 @@

    A.K.A. {% for aka in

    -
    -
    - -
    -
    +{% include "summary-horizontal-nav.html" %}
    From e17de422c239530a5ea58e770b7ccd9bddc12e48 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Thu, 26 May 2022 04:36:32 -0400 Subject: [PATCH 12/27] Components Aspen summary page working --- controls/views.py | 4 +- .../systems/components_selected_aspen.html | 211 ++++++++++++------ 2 files changed, 145 insertions(+), 70 deletions(-) diff --git a/controls/views.py b/controls/views.py index 9ee0c1cf1..6c8e9ebe8 100644 --- a/controls/views.py +++ b/controls/views.py @@ -485,8 +485,8 @@ def get_context_data(self, **kwargs): # Temporarily assume only one project and get first project project = system.projects.first() context['project'] = project - context['system'] = system_summary - # context['system'] = system + context['system_summary'] = system_summary + context['system'] = system context['system_proposals'] = system_proposals context['system_proposal_elements'] = system_proposal_elements context['elements'] = Element.objects.all().exclude(element_type='system') diff --git a/templates/systems/components_selected_aspen.html b/templates/systems/components_selected_aspen.html index 6183527ac..70f934c5f 100644 --- a/templates/systems/components_selected_aspen.html +++ b/templates/systems/components_selected_aspen.html @@ -25,9 +25,9 @@
    -

    {{ system.impact }}

    -

    {{ system.name }}

    -

    A.K.A. {% for aka in system.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

    +

    {{ system_summary.impact }}

    +

    {{ system_summary.name }}

    +

    A.K.A. {% for aka in system_summary.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

    Organization-wide Initiative Status
    @@ -55,78 +55,130 @@

    A.K.A. {% for aka in

    Components Overview

    -
    -

    - Deployments are instances of your system installed and operating in your organization. -

    -
    +
    +

    + Components are the various constituent software, hardware, and process that compose your system. +

    + + +
    +
    +
    Selected components
    +
     
    +
    +
    + {% csrf_token %} +
    +    + + +
    +
    +
    +
    + + +
    + + {% for component in system_elements %} + {# Each "component" is a Element model object. #} +
    + +
    + {{ component.component_type }} + {{ component.component_state }} +
    +
    + {% if component.description %}{{ component.description }}{% else %}No description provided.{% endif %} +
    {% for tag in component.tags.all %}{{ tag.label }} {% endfor %}
    +
    + {% with ctl_count=component.get_control_impl_smts_prototype_count %} +
    + {% if ctl_count %}{{ ctl_count }} control{{ ctl_count|pluralize }}{% else %}None{% endif %} +
    + {% endwith %} + {% get_obj_perms request.user for system as "system_perms" %} + {% if "change_system" in system_perms %} + + {% endif %} +
    + {% endfor %} -
    -

    Deployment Details

    -
    -
    - - - - - - -
    Location: {{ system.other_id }}Chicago, IL
    Hosting Facility: {{ system.hosting_facility }}Data Center 1
    Status: {{ system.status }}Production
    Deployment Type: {{ system.type }}Automated
    -
    -
    - - - - - -
    Recent Deployment: {{ system.created|naturaltime }}
    Deployment Fequency: {{ system.next_audit }}bi-weekly
    Next Scan: {{ system.next_scan|naturaltime }}
    Approx. Assets: {{ system.security_scan }}5
    -
    -
    +
    -
    +
    +
    +
    Proposed components
    +
     
    +
     
    +
    + {% for proposal in system_proposals %} + {# Each "component" is a Element model object. #} +
    + +
    + {{ proposal.requested_element.component_type }} + {{ proposal.requested_element.component_state }} +
    +
    + {% if proposal.requested_element.description %}{{ proposal.requested_element.description }}{% else %}No description provided.{% endif %} +
    {% for tag in proposal.requested_element.tags.all %}{{ tag.label }} {% endfor %}
    +
    + {% with ctl_count=proposal.requested_element.get_control_impl_smts_prototype_count %} +
    + {% if ctl_count %}{{ ctl_count }} control{{ ctl_count|pluralize }}{% else %}None{% endif %} +
    + {% endwith %} + {% get_obj_perms request.user for system as "system_perms" %} + {% if "change_system" in system_perms %} + + {% endif %} +
    + + {% endfor %} +
    +
    +
    + {% include 'components/paginate_comp.html' with system_elements=page_obj %} +
    -
    -
    - - - {% if deployments|length < 1 %} -
    -
    -

    No Deployments are currently identified for this system.

    -
    -
    - {% else %} - {% for deployment in deployments %} - -
    -
    - {{ deployment.name }} - {{ deployment.description }}
    Updated {{ deployment.updated|timesince}} ago - -   - - -
    -
    - {% endfor %} - {% endif %} - -
    - -
    +

    @@ -137,15 +189,38 @@

    Deployment Details

    - - - {% endblock %} {% block scripts %} {{ block.super }} + - {% endblock %} + From 1b7bef337216839fad13ce80d986d3abc8b8d9b8 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Thu, 26 May 2022 05:04:38 -0400 Subject: [PATCH 13/27] Added Selected Controls Aspen summary page --- controls/urls.py | 1 + controls/views.py | 69 ++++ templates/summary-horizontal-nav.html | 2 +- .../systems/controls_selected_aspen.html | 297 ++++++++++++++++++ 4 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 templates/systems/controls_selected_aspen.html diff --git a/controls/urls.py b/controls/urls.py index 90133c082..ef4f7425b 100644 --- a/controls/urls.py +++ b/controls/urls.py @@ -26,6 +26,7 @@ # Systems url(r'^(?P.*)/controls/selected/export/xacta/xlsx$', views.controls_selected_export_xacta_xslx, name="controls_selected"), + url(r'^(?P.*)/controls/selected/aspen$', views.controls_selected_aspen, name="controls_selected_aspen"), url(r'^(?P.*)/controls/selected$', views.controls_selected, name="controls_selected"), url(r'^(?P.*)/controls/add$', views.system_controls_add, name="system_controls_add"), url(r'^(?P.*)/controls/remove/(?P.*)$', views.system_control_remove, name="system_control_remove"), diff --git a/controls/views.py b/controls/views.py index 6c8e9ebe8..454bfb9ea 100644 --- a/controls/views.py +++ b/controls/views.py @@ -160,6 +160,75 @@ def control(request, catalog_key, cl_id): } return render(request, "controls/detail.html", context) +@functools.lru_cache() +def controls_selected_aspen(request, system_id): + """Display System's selected controls view""" + + # Retrieve identified System + system = System.objects.get(id=system_id) + # if not request.user.has_perm('view_system', system): + # raise Http404 + + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + + system_summary = get_integrations_system_info(request, system_id) + # system_events = get_integrations_system_events(request, system_id) + + # Fix menu data for old vertical menu + project.system.root_element.name = system_summary['name'] + project.root_task.title_override = system_summary['name'] + + # Retrieve related selected controls if user has permission on system + if request.user.has_perm('view_system', system): + # Retrieve primary system Project + # Temporarily assume only one project and get first project + project = system.projects.all()[0] + controls = system.root_element.controls.all() + impl_smts = system.root_element.statements_consumed.all() + + # sort controls + controls = list(controls) + controls.sort(key=lambda control: control.get_flattened_oscal_control_as_dict()['sort_id']) + + # Determine if a legacy statement exists for the control + impl_smts_legacy = Statement.objects.filter(consumer_element=system.root_element, statement_type=StatementTypeEnum.CONTROL_IMPLEMENTATION_LEGACY.name) + impl_smts_legacy_dict = {} + for legacy_smt in impl_smts_legacy: + impl_smts_legacy_dict[legacy_smt.sid] = legacy_smt + + # Get count of componentes (e.g., producer_elements) associated with a control + impl_smts_cmpts_count = {} + ikeys = system.smts_control_implementation_as_dict.keys() + for c in controls: + impl_smts_cmpts_count[c.oscal_ctl_id] = 0 + if c.oscal_ctl_id in ikeys: + impl_smts_cmpts_count[c.oscal_ctl_id] = len(set([s.producer_element for s in system.smts_control_implementation_as_dict[c.oscal_ctl_id]['control_impl_smts']])) + + # Get list of catalog objects + catalog_list = Catalogs().list_catalogs() + # Remove the 3 nist catalogs that are hard-coded already in template + external_catalogs = [catalog for catalog in catalog_list if catalog.catalog_key not in ['NIST_SP-800-53_rev4', 'NIST_SP-800-53_rev5', 'NIST_SP-800-171_rev1', 'CMMC_ver1' ]] + + # Return the controls + context = { + "system": system, + "system_summary": system_summary, + "project": project, + "controls": controls, + "external_catalogs": external_catalogs, + "impl_smts_cmpts_count": impl_smts_cmpts_count, + "impl_smts_legacy_dict": impl_smts_legacy_dict, + "enable_experimental_opencontrol": SystemSettings.enable_experimental_opencontrol, + "display_urls": project_context(project) + } + return render(request, "systems/controls_selected_aspen.html", context) + else: + # User does not have permission to this system + raise Http404 + + @functools.lru_cache() def controls_selected(request, system_id): """Display System's selected controls view""" diff --git a/templates/summary-horizontal-nav.html b/templates/summary-horizontal-nav.html index 3c78c6ac1..2d53757be 100644 --- a/templates/summary-horizontal-nav.html +++ b/templates/summary-horizontal-nav.html @@ -27,7 +27,7 @@
    • homeSystem
    • -
    • listControls
    • +
    • listControls
    • settings_input_componentComponents
    • check_boxPOA&Ms
    • hubDeployments
    • diff --git a/templates/systems/controls_selected_aspen.html b/templates/systems/controls_selected_aspen.html new file mode 100644 index 000000000..536692558 --- /dev/null +++ b/templates/systems/controls_selected_aspen.html @@ -0,0 +1,297 @@ +{% extends "summary-base.html" %} +{% load humanize %} +{% load guardian_tags %} +{% load static %} +{% load q %} +{% load system_tags %} + +{% block title %} +System +{% endblock %} + +{% block head %} +{{block.super}} +{% include "controls/_style-controls.html" %} +{% endblock %} + + + + +{% block body_content %} + + + +
      +
      +
      +

      {{ system_summary.impact }}

      +

      {{ system_summary.name }}

      +

      A.K.A. {% for aka in system_summary.aka %}"{{ aka }}"{% if not forloop.last %}, {% endif %}{% endfor %}"

      +
      + +
      Organization-wide Initiative Status
      +
      + + + + +
       
      800-53 rev5 migration
       
      Log4J remediation solution (updated 4/21/22)
       
      Q3 Audit
      +
      +
      +
      + +{% include "summary-horizontal-nav.html" %} +
      +
      +
      + + + +
      + +
      +

      Controls Overview

      + +
      +

      + Controls are the selected cybersecurity compliance goals required for your system installed and operating in your organization. +

      + + + +
      +
      +
      Selected controls
      +
      +
      + {% csrf_token %} +
      +    + + +
      + +
      +
      +
      + + +
      +
      + {% if controls|length < 1 %} + + {% else %} + {% for control in controls %} +
      + +
      + {{ control.get_flattened_oscal_control_as_dict.title }} +
      +
      +
      + {% with total=impl_smts_cmpts_count|get_item:control.oscal_ctl_id %} + {% if total > 0 %} + {{ total }} component{{ total|pluralize }} + {% else %} + — + {% endif %} + {% endwith %} +
      +
      + {% with total=impl_smts_legacy_dict|get_item:control.oscal_ctl_id %} + {% if total %} + 1 legacy statement{{ total|pluralize }} + {% endif %} + {% endwith %} +
      +
      + {% get_obj_perms request.user for system as "system_perms" %} + {% if "view_system" in system_perms %} +
      + + + + +
      + {% else %} +
      + {% if control.smts_updated %} + {{ control.smts_updated|timesince}} ago + {% else %} + {{ control.created|timesince}} ago + {% endif %} +
      + {% endif %} +
      + {% endfor %} + {% endif %} +
      + +
      + +
      + + +
      + + + + + + +
      +
      + + + + + +{% endblock %} + +{% block scripts %} + {{ block.super }} + + + +{% endblock %} From 02cef45f424d53fe85d2190d4d02b705c00a8be5 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Thu, 26 May 2022 05:12:34 -0400 Subject: [PATCH 14/27] Style links in Aspen summary horoz nav --- templates/summary-horizontal-nav.html | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/summary-horizontal-nav.html b/templates/summary-horizontal-nav.html index 2d53757be..508e94fac 100644 --- a/templates/summary-horizontal-nav.html +++ b/templates/summary-horizontal-nav.html @@ -18,6 +18,7 @@ .summary-nav-options { padding-left:5px;} +.summary-nav-options a { color: #808080;; } From abab8d45d05b40865264fdb445f62ab97cc4b808 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Thu, 26 May 2022 10:08:00 -0400 Subject: [PATCH 15/27] Truncating component descriptions to avoid line overlap --- templates/systems/components_selected_aspen.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/systems/components_selected_aspen.html b/templates/systems/components_selected_aspen.html index 70f934c5f..4a072660b 100644 --- a/templates/systems/components_selected_aspen.html +++ b/templates/systems/components_selected_aspen.html @@ -62,7 +62,7 @@

      A.K.A. {% for aka in
      -
      +
      Selected components
       
      @@ -93,7 +93,7 @@

      A.K.A. {% for aka in {% for component in system_elements %} {# Each "component" is a Element model object. #} -
      +
      @@ -102,7 +102,7 @@

      A.K.A. {% for aka in {{ component.component_state }}

      - {% if component.description %}{{ component.description }}{% else %}No description provided.{% endif %} + {% if component.description %}{{ component.description|truncatewords:10 }}{% else %}No description provided.{% endif %}
      {% for tag in component.tags.all %}{{ tag.label }} {% endfor %}
      {% with ctl_count=component.get_control_impl_smts_prototype_count %} @@ -128,14 +128,14 @@

      A.K.A. {% for aka in
      -
      +
      Proposed components
       
       
      {% for proposal in system_proposals %} {# Each "component" is a Element model object. #} -
      +
      @@ -144,7 +144,7 @@

      A.K.A. {% for aka in {{ proposal.requested_element.component_state }}

      - {% if proposal.requested_element.description %}{{ proposal.requested_element.description }}{% else %}No description provided.{% endif %} + {% if proposal.requested_element.description %}{{ proposal.requested_element.description|truncatewords:10 }}{% else %}No description provided.{% endif %}
      {% for tag in proposal.requested_element.tags.all %}{{ tag.label }} {% endfor %}
      {% with ctl_count=proposal.requested_element.get_control_impl_smts_prototype_count %} From 482996de99558333bd25ad21fdbc5c73d5547445 Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Sat, 28 May 2022 20:53:52 -0400 Subject: [PATCH 16/27] Display system projects on Aspen summary page --- controls/urls.py | 2 - controls/views.py | 9 ++++ siteapp/model_mixins/appointments.py | 1 - templates/components/element_detail_tabs.html | 1 + templates/systems/system_summary_1.html | 41 +++++++++++++------ 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/controls/urls.py b/controls/urls.py index ef4f7425b..e086c5076 100644 --- a/controls/urls.py +++ b/controls/urls.py @@ -8,9 +8,7 @@ admin.autodiscover() from django.views.decorators.csrf import csrf_exempt -from controls import urls_api -import controls.views from controls import views from siteapp.settings import * diff --git a/controls/views.py b/controls/views.py index 454bfb9ea..e7a7b776f 100644 --- a/controls/views.py +++ b/controls/views.py @@ -3751,6 +3751,7 @@ def get_integrations_system_info(request, system_id): # Retrieve primary system Project # Temporarily assume only one project and get first project project = system.projects.all()[0] + system_name = system.root_element.name # Retrieve info from integrations @@ -3929,6 +3930,9 @@ def system_summary_1_aspen(request, system_id): system_summary = get_integrations_system_info(request, system_id) system_events = get_integrations_system_events(request, system_id) + # Get all projects + projects = system.projects.all() + # Fix menu data for old vertical menu project.system.root_element.name = system_summary['name'] project.root_task.title_override = system_summary['name'] @@ -3936,6 +3940,7 @@ def system_summary_1_aspen(request, system_id): context = { "system": system_summary, #"project": project, + "project": projects, "system_events": system_events, # "deployments": deployments, "display_urls": project_context(project) @@ -3957,6 +3962,9 @@ def system_summary_aspen(request, system_id): system_summary = get_integrations_system_info(request, system_id) system_events = get_integrations_system_events(request, system_id) + # Get all projects + projects = system.projects.all() + # Fix menu data for old vertical menu project.system.root_element.name = system_summary['name'] project.root_task.title_override = system_summary['name'] @@ -3964,6 +3972,7 @@ def system_summary_aspen(request, system_id): context = { "system": system_summary, #"project": project, + "projects": projects, "system_events": system_events, # "deployments": deployments, "display_urls": project_context(project) diff --git a/siteapp/model_mixins/appointments.py b/siteapp/model_mixins/appointments.py index c515af854..f392407d2 100644 --- a/siteapp/model_mixins/appointments.py +++ b/siteapp/model_mixins/appointments.py @@ -1,5 +1,4 @@ from django.db import models -from django.http import JsonResponse class AppointmentModelMixin(models.Model): appointments = models.ManyToManyField("siteapp.Appointment", blank=True, related_name="%(class)s") diff --git a/templates/components/element_detail_tabs.html b/templates/components/element_detail_tabs.html index d879b9c3d..f6965d7ed 100644 --- a/templates/components/element_detail_tabs.html +++ b/templates/components/element_detail_tabs.html @@ -89,6 +89,7 @@

      {{ element.name }} + {% if element.element_type == "system" %}(System){% endif %} {% if element.private == True %}{% endif %}

      diff --git a/templates/systems/system_summary_1.html b/templates/systems/system_summary_1.html index 69106457c..573b43d26 100644 --- a/templates/systems/system_summary_1.html +++ b/templates/systems/system_summary_1.html @@ -70,20 +70,37 @@

      System Details

      -
      - -

      Recent System Related Events

      - - {% for se in system_events %} - - - - {% endfor %} -
      {{ se.event_tag }}
      {{ se.event_summary }}
      - +
      +

      Recent System Related Events

      + + {% for se in system_events %} + + + + {% endfor %} +
      {{ se.event_tag }}
      {{ se.event_summary }}
      - +

      Projects (Questionnaires)

      + {% if projects|length < 1 %} +
      +
      +

      No Projects are currently identified for this system.

      +
      +
      + {% else %} + {% for p in projects %} + + {% endfor %} + {% endif %}
      From f3953aa735a65b7697f25cd5cd0d29802bd28bdf Mon Sep 17 00:00:00 2001 From: Greg Elin Date: Sun, 29 May 2022 06:18:44 -0400 Subject: [PATCH 17/27] Display project control text partially on page with modal for full text --- CHANGELOG.md | 1 + templates/control-description-modal.html | 37 +++++++++++++++ templates/controls/editor.html | 58 +++++++++++++++--------- templates/project-base.html | 1 + 4 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 templates/control-description-modal.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e82a3d36..c57ca1fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Release adds support for private components and integrations with third party se * Only Component owner can edit user permissions. * Display the control framework along side of controls in component control listing page. * Remove icons from project listing. +* Display project control text partially on page with modal for full text. **Developer changes** diff --git a/templates/control-description-modal.html b/templates/control-description-modal.html new file mode 100644 index 000000000..6cefcc4c8 --- /dev/null +++ b/templates/control-description-modal.html @@ -0,0 +1,37 @@ + + + +{% block scripts %} + +{% endblock %} diff --git a/templates/controls/editor.html b/templates/controls/editor.html index fbc08f8c8..2be9f0dea 100644 --- a/templates/controls/editor.html +++ b/templates/controls/editor.html @@ -33,14 +33,13 @@ margin: auto; } - .control-text { + .control-text-modal { white-space: pre-wrap; font-size: 11pt; - /*max-width: 700px;*/ font-family: trebuchet ms, sans-serif; - text-align: justify; - /*text-justify: inter-word;*/ - line-height: 24px; + /* text-align: justify; */ + /* text-justify: inter-word; */ + /* line-height: 18px; */ } #control-lookup input { @@ -98,6 +97,22 @@ border-radius: 0px; padding: 0px 0px 8px 12px; } + .modal-content { + position: fixed; + margin: auto; + width: 130%; + /* height: calc(100% - 53px); */ + -webkit-transform: translate3d(0%, 0, 0); + -ms-transform: translate3d(0%, 0, 0); + -o-transform: translate3d(0%, 0, 0); + transform: translate3d(0%, 0, 0); + } + + @media screen and (max-width: 700px) { + #control_description_modal { + width: 400px; + } + } {% endblock %} @@ -107,7 +122,7 @@

      - System Control: {{ control.id_display|upper }} {{ control.title }} + {{ control.id_display|upper }} {{ control.title }}

      {% if control.title is not None %} @@ -134,22 +149,23 @@

      -