def verify_and_call(*args, **kwargs): context = args[1].context finding_id = kwargs.get('finding_id') \ if kwargs.get('identifier') is None else kwargs.get('identifier') user_data = util.get_jwt_content(context) user_data['subscribed_projects'] = \ user_domain.get_projects(user_data['user_email']) user_data['subscribed_projects'] += \ user_domain.get_projects(user_data['user_email'], active=False) user_data['role'] = get_user_role(user_data) finding_project = finding_domain.get_finding(finding_id).get( 'projectName') if not re.match('^[0-9]*$', finding_id): rollbar.report_message('Error: Invalid finding id format', 'error', context) raise GraphQLError('Invalid finding id format') try: if not ENFORCER_BASIC.enforce(user_data, finding_project.lower()): util.cloudwatch_log( context, 'Security: \ Attempted to retrieve finding-related info without permission') raise GraphQLError('Access denied') except AttributeDoesNotExist: return GraphQLError('Access denied') return func(*args, **kwargs)
def mutate(self, info, finding_id, **parameters): project_name = finding_domain.get_finding(finding_id)['projectName'] user_mail = util.get_jwt_content(info.context)['user_email'] if parameters.get('acceptance_status') == '': del parameters['acceptance_status'] historic_treatment = finding_domain.get_finding( finding_id)['historicTreatment'] last_state = { key: value for key, value in historic_treatment[-1].items() if key not in ['date', 'user'] } new_state = { key: value for key, value in parameters.items() if key != 'bts_url' } bts_changed, treatment_changed = True, True Status = namedtuple('Status', 'bts_changed treatment_changed') if not finding_domain.compare_historic_treatments( last_state, new_state): treatment_changed = False if ('externalBts' in finding_domain.get_finding(finding_id) and parameters.get('bts_url') == finding_domain.get_finding(finding_id)['externalBts']): bts_changed = False update = Status(bts_changed=bts_changed, treatment_changed=treatment_changed) if not any(list(update)): raise GraphQLError( 'It cant be updated a finding with same values it already has') success = finding_domain.update_client_description( finding_id, parameters, user_mail, update) if success: util.invalidate_cache(finding_id) util.invalidate_cache(project_name) util.cloudwatch_log( info.context, 'Security: Updated treatment in ' f'finding {finding_id} succesfully') util.forces_trigger_deployment(project_name) else: util.cloudwatch_log( info.context, 'Security: Attempted to update ' f'treatment in finding {finding_id}') findings_loader = info.context.loaders['finding'] return UpdateClientDescription( finding=findings_loader.load(finding_id), success=success)
def has_access_to_finding(user: str, finding_id: str, role: str) -> bool: """ Verify if the user has access to a finding submission. """ has_access = False # Skip this check for admin users since they don't have any assigned projects if role == 'admin': has_access = True else: finding = finding_domain.get_finding(finding_id) has_access = has_access_to_project(user, str(finding.get('projectName', '')), role) return has_access
def test_delete_finding(self): query = ''' mutation { deleteFinding(findingId: "560175507", justification: NOT_REQUIRED) { success } } ''' testing_client = Client(SCHEMA) request_loaders = {'finding': FindingLoader()} result = self._get_result(query, testing_client, request_loaders) assert 'errors' not in result assert result['data']['deleteFinding']['success'] with pytest.raises(FindingNotFound): assert get_finding('560175507')
def format_release_date(finding): finding_dynamo = finding_domain.get_finding(finding['findingId']) if finding_dynamo: if finding_dynamo[0].get("releaseDate"): finding["releaseDate"] = finding_dynamo[0].get("releaseDate") if finding_dynamo[0].get("lastVulnerability"): finding["lastVulnerability"] = \ finding_dynamo[0].get("lastVulnerability") if finding.get("releaseDate"): final_date = util.calculate_datediff_since(finding["releaseDate"]) finding['edad'] = final_date.days final_vuln_date = util.calculate_datediff_since(finding["lastVulnerability"]) finding['lastVulnerability'] = final_vuln_date.days else: finding['lastVulnerability'] = '-' return finding
def mutate(self, info, finding_id, justification): project_name = finding_domain.get_finding(finding_id)['projectName'] success = finding_domain.delete_finding(finding_id, project_name, justification, info.context) if success: util.invalidate_cache(finding_id) util.invalidate_cache(project_name) util.cloudwatch_log( info.context, f'Security: Deleted finding: {finding_id} succesfully') else: util.cloudwatch_log( info.context, f'Security: Attempted to delete finding: {finding_id}') return DeleteFinding(success=success)
def mutate(self, info, finding_id): reviewer_email = util.get_jwt_content(info.context)['user_email'] project_name = finding_domain.get_finding(finding_id)['projectName'] success = finding_domain.reject_draft(finding_id, reviewer_email) if success: util.invalidate_cache(finding_id) util.invalidate_cache(project_name) util.cloudwatch_log( info.context, 'Security: Draft {} rejected succesfully'.format(finding_id)) else: util.cloudwatch_log( info.context, 'Security: Attempted to reject draft {}'.format(finding_id)) return RejectDraft(success=success)
def mutate(self, info, finding_id, **parameters): success = finding_domain.update_description(finding_id, parameters) if success: project_name = finding_domain.get_finding( finding_id)['projectName'] util.invalidate_cache(finding_id) util.invalidate_cache(project_name) util.cloudwatch_log( info.context, 'Security: Updated description in\ finding {id} succesfully'.format(id=finding_id)) else: util.cloudwatch_log( info.context, 'Security: Attempted to update \ description in finding {id}'.format(id=finding_id)) findings_loader = info.context.loaders['finding'] ret = UpdateDescription(finding=findings_loader.load(finding_id), success=success) return ret
def mutate(self, info, **parameters): """update vulnerabilities in database.""" min_value = 0 max_value = 1000000000 vulnerabilities = parameters.get('vulnerabilities') finding_id = parameters.get('finding_id') if parameters.get('severity') and parameters.get('severity') != -1: if min_value > parameters.get('severity') or \ parameters.get('severity') > max_value: raise InvalidSeverity([min_value, max_value]) user_data = util.get_jwt_content(info.context) project_name = finding_domain.get_finding(finding_id)['projectName'] is_customer_admin = is_customeradmin(project_name, user_data['user_email']) result_update_vuln = update_treatments(vulnerabilities, finding_id, parameters, info, is_customer_admin) if result_update_vuln: util.invalidate_cache(finding_id) result = UpdateTreatmentVuln(success=result_update_vuln) return result
def mutate(self, info, **parameters): user_info = util.get_jwt_content(info.context) user_mail = user_info['user_email'] finding_id = parameters.get('finding_id') historic_treatment = finding_domain.get_finding(finding_id).get( 'historicTreatment') if historic_treatment[-1]['acceptance_status'] != 'SUBMITTED': raise GraphQLError('It cant be approved/rejected a finding' + 'definite assumption without being requested') success = finding_domain.handle_acceptation( finding_id, parameters.get('observations'), user_mail, parameters.get('response')) if success: util.invalidate_cache(finding_id) util.invalidate_cache(parameters.get('project_name')) util.cloudwatch_log( info.context, 'Security: Verified a request ' f'in finding_id: {finding_id}') ret = HandleAcceptation(success=success) return ret
def mutate(self, info, draft_id): reviewer_email = util.get_jwt_content(info.context)['user_email'] project_name = finding_domain.get_finding(draft_id)['projectName'] has_vulns = [ vuln for vuln in vuln_domain.list_vulnerabilities([draft_id]) if vuln['historic_state'][-1].get('state') != 'DELETED' ] if not has_vulns: raise GraphQLError('CANT_APPROVE_FINDING_WITHOUT_VULNS') success, release_date = finding_domain.approve_draft( draft_id, reviewer_email) if success: util.invalidate_cache(draft_id) util.invalidate_cache(project_name) util.cloudwatch_log( info.context, 'Security: Approved draft in\ {project} project succesfully'.format(project=project_name)) else: util.cloudwatch_log( info.context, 'Security: Attempted to approve \ draft in {project} project'.format(project=project_name)) return ApproveDraft(release_date, success)
def download_vulnerabilities(request, findingid): """Download a file with all the vulnerabilities.""" if not has_access_to_finding(request.session['username'], findingid, request.session['role']): util.cloudwatch_log(request, 'Security: \ Attempted to retrieve vulnerabilities without permission') return util.response([], 'Access denied', True) else: finding = get_vulnerabilities_by_type(findingid) data_yml = {} vuln_types = {'ports': dict, 'lines': dict, 'inputs': dict} if finding: for vuln_key, cast_fuction in list(vuln_types.items()): if finding.get(vuln_key): data_yml[vuln_key] = list(map(cast_fuction, list(finding.get(vuln_key)))) else: # This finding does not have this type of vulnerabilities pass else: # This finding does not have new vulnerabilities pass project = finding_domain.get_finding(findingid)['projectName'] file_name = '/tmp/{project}-{finding_id}.yaml'.format( finding_id=findingid, project=project) stream = open(file_name, 'w') yaml.safe_dump(data_yml, stream, default_flow_style=False) try: with open(file_name, 'rb') as file_obj: response = HttpResponse(file_obj.read(), content_type='text/x-yaml') response['Content-Disposition'] = \ 'attachment; filename="{project}-{finding_id}.yaml"'.format( finding_id=findingid, project=project) return response except IOError: rollbar.report_message('Error: Invalid vulnerabilities file format', 'error', request) return util.response([], 'Invalid vulnerabilities file format', True)