def test_audit_item_method_account_pattern_score_override(self): account_pattern_score = AccountPatternAuditScore( account_type=self.account_type.name, account_field='name', account_pattern=self.test_account.name, score=2) item_audit_score = ItemAuditScore( technology='test_index', method='check_test (AuditorTestObj)', score=5, disabled=False, account_pattern_scores=[account_pattern_score]) db.session.add(account_pattern_score) db.session.add(item_audit_score) db.session.commit() item = ChangeItem(index='test_index', account=self.test_account.name, name='item_name') auditor = AuditorTestObj(accounts=[self.test_account.name]) self.assertEqual(len(item.audit_issues), 0) auditor.items = [item] auditor.audit_objects() self.assertEqual(len(item.audit_issues), 1) self.assertEqual(item.audit_issues[0].issue, 'Test issue') self.assertEqual(item.audit_issues[0].score, 2)
def test_audit_item_method_disabled(self): item_audit_score = ItemAuditScore(technology='test_index', method='check_test (AuditorTestObj)', score=0, disabled=True) db.session.add(item_audit_score) db.session.commit() auditor = AuditorTestObj(accounts=['test_account']) item = ChangeItem(index='test_index', account='test_account', name='item_name') self.assertEqual(len(item.audit_issues), 0) auditor.items = [item] auditor.audit_objects() self.assertEqual(len(item.audit_issues), 0)
def add_override_scores(file_name, field_mappings): """ Refreshes the audit disable/override scores from a csv file. Old scores not in the csv will be removed. :param file_name: path to the csv file :param field_mappings: Comma separated list of mappings of known types to csv file headers. Ex. 'tech=Tech Name,score=default score' """ from security_monkey.datastore import ItemAuditScore, AccountPatternAuditScore from security_monkey.auditor import auditor_registry import csv csvfile = open(file_name, 'r') reader = csv.DictReader(csvfile) errors = [] mappings = { 'tech': 'tech', 'auditor': 'auditor', 'method': 'method', 'disabled': 'disabled', 'score': 'score', 'patterns': {} } if field_mappings: mapping_defs = field_mappings.split(',') for mapping_def in mapping_defs: mapping = mapping_def.split('=') if mapping[0] in mappings: mappings[mapping[0]] = mapping[1] else: patterns = mappings['patterns'] patterns[mapping[0]] = mapping[1] line_num = 0 entries = [] for row in reader: line_num = line_num + 1 tech_name = row[mappings['tech']] auditor = row[mappings['auditor']] method = row[mappings['method']] if not tech_name or not auditor or not method: continue score = None str_score = row[mappings['score']].decode('ascii', 'ignore').strip('') if str_score != '': if not str_score.isdigit(): errors.append('Score {} line {} is not a positive int.'.format( str_score, line_num)) continue score = int(str_score) if row[mappings['disabled']].lower() == 'true': disabled = True else: disabled = False if score is None and not disabled: continue if score is None: score = 0 if tech_name not in auditor_registry: errors.append('Invalid tech name {} line {}.'.format( tech_name, line_num)) continue valid = False auditor_classes = auditor_registry[tech_name] for auditor_class in auditor_classes: if auditor_class.__name__ == auditor: valid = True break if not valid: errors.append('Invalid auditor {} line {}.'.format( auditor, line_num)) continue if not getattr(auditor_class, method, None): errors.append('Invalid method {} line {}.'.format( method, line_num)) continue entry = ItemAuditScore(technology=tech_name, method=method + ' (' + auditor + ')', score=score, disabled=disabled) pattern_mappings = mappings['patterns'] for mapping in pattern_mappings: str_pattern_score = row[pattern_mappings[mapping]].decode( 'ascii', 'ignore').strip() if str_pattern_score != '': if not str_pattern_score.isdigit(): errors.append( 'Pattern score {} line {} is not a positive int.'. format(str_pattern_score, line_num)) continue account_info = mapping.split('.') if len(account_info) != 3: errors.append( 'Invalid pattern mapping {}.'.format(mapping)) continue from security_monkey.account_manager import account_registry if account_info[0] not in account_registry: errors.append('Invalid account type {}'.format( account_info[0])) continue db_pattern_score = AccountPatternAuditScore( account_type=account_info[0], account_field=account_info[1], account_pattern=account_info[2], score=int(str_pattern_score)) entry.account_pattern_scores.append(db_pattern_score) entries.append(entry) if len(errors) > 0: for error in errors: sys.stderr.write("{}\n".format(error)) sys.exit(1) AccountPatternAuditScore.query.delete() ItemAuditScore.query.delete() for entry in entries: db.session.add(entry) db.session.commit() db.session.close()
def add_override_score(tech_name, method, auditor, score, disabled, pattern_scores): """ Adds an audit disable/override scores :param tech_name: technology index :param method: the neme of the auditor method to override :param auditor: The class name of the auditor containing the check method :param score: The default override score to assign to the check method issue :param disabled: Flag indicating whether the check method should be run :param pattern_scores: A comma separated list of account field values and scores. This can be used to override the default score based on some field in the account that the check method is running against. The format of each value/score is: account_type.account_field.account_value=score """ from security_monkey.datastore import ItemAuditScore from security_monkey.auditor import auditor_registry if tech_name not in auditor_registry: sys.stderr.write('Invalid tech name {}.\n'.format(tech_name)) sys.exit(1) valid = False auditor_classes = auditor_registry[tech_name] for auditor_class in auditor_classes: if auditor_class.__name__ == auditor: valid = True break if not valid: sys.stderr.write('Invalid auditor {}.\n'.format(auditor)) sys.exit(1) if not getattr(auditor_class, method, None): sys.stderr.write('Invalid method {}.\n'.format(method)) sys.exit(1) if score is None and not disabled: sys.stderr.write('Either score (-s) or disabled (-b) required') sys.exit(1) if score is None: score = 0 query = ItemAuditScore.query.filter(ItemAuditScore.technology == tech_name) method_str = "{method} ({auditor})".format(method=method, auditor=auditor) query = query.filter(ItemAuditScore.method == method_str) entry = query.first() if not entry: entry = ItemAuditScore() entry.technology = tech_name entry.method = method_str entry.score = score entry.disabled = disabled if pattern_scores is not None: scores = pattern_scores.split(',') for score in scores: left_right = score.split('=') if len(left_right) != 2: sys.stderr.write( 'pattern_scores (-p) format account_type.account_field.account_value=score\n' ) sys.exit(1) account_info = left_right[0].split('.') if len(account_info) != 3: sys.stderr.write( 'pattern_scores (-p) format account_type.account_field.account_value=score\n' ) sys.exit(1) from security_monkey.account_manager import account_registry if account_info[0] not in account_registry: sys.stderr.write('Invalid account type {}\n'.format( account_info[0])) sys.exit(1) entry.add_or_update_pattern_score(account_info[0], account_info[1], account_info[2], int(left_right[1])) db.session.add(entry) db.session.commit() db.session.close()
def add_override_score(tech_name, method, auditor, score, disabled, pattern_scores): """ Adds an audit disable/override scores :param tech_name: technology index :param method: the neme of the auditor method to override :param auditor: The class name of the auditor containing the check method :param score: The default override score to assign to the check method issue :param disabled: Flag indicating whether the check method should be run :param pattern_scores: A comma separated list of account field values and scores. This can be used to override the default score based on some field in the account that the check method is running against. The format of each value/score is: account_type.account_field.account_value=score """ from security_monkey.datastore import ItemAuditScore from security_monkey.auditor import auditor_registry if tech_name not in auditor_registry: sys.stderr.write('Invalid tech name {}.\n'.format(tech_name)) sys.exit(1) valid = False auditor_classes = auditor_registry[tech_name] for auditor_class in auditor_classes: if auditor_class.__name__ == auditor: valid = True break if not valid: sys.stderr.write('Invalid auditor {}.\n'.format(auditor)) sys.exit(1) if not getattr(auditor_class, method, None): sys.stderr.write('Invalid method {}.\n'.format(method)) sys.exit(1) if score is None and not disabled: sys.stderr.write('Either score (-s) or disabled (-b) required') sys.exit(1) if score is None: score = 0 query = ItemAuditScore.query.filter(ItemAuditScore.technology == tech_name) method_str = "{method} ({auditor})".format(method=method, auditor=auditor) query = query.filter(ItemAuditScore.method == method_str) entry = query.first() if not entry: entry = ItemAuditScore() entry.technology = tech_name entry.method = method_str entry.score = score entry.disabled = disabled if pattern_scores is not None: scores = pattern_scores.split(',') for score in scores: left_right = score.split('=') if len(left_right) != 2: sys.stderr.write('pattern_scores (-p) format account_type.account_field.account_value=score\n') sys.exit(1) account_info = left_right[0].split('.') if len(account_info) != 3: sys.stderr.write('pattern_scores (-p) format account_type.account_field.account_value=score\n') sys.exit(1) from security_monkey.account_manager import account_registry if account_info[0] not in account_registry: sys.stderr.write('Invalid account type {}\n'.format(account_info[0])) sys.exit(1) entry.add_or_update_pattern_score(account_info[0], account_info[1], account_info[2], int(left_right[1])) db.session.add(entry) db.session.commit() db.session.close()
def post(self): """ .. http:post:: /api/1/auditscores Create a new override audit score. **Example Request**: .. sourcecode:: http POST /api/1/auditscores HTTP/1.1 Host: example.com Accept: application/json { "method": "check_xxx", "technology": "policy", "score": 1 } **Example Response**: .. sourcecode:: http HTTP/1.1 201 Created Vary: Accept Content-Type: application/json { "id": 123, "name": "Corp", "notes": "Corporate Network", "cidr": "1.2.3.4/22" } :statuscode 201: created :statuscode 401: Authentication Error. Please Login. """ self.reqparse.add_argument('method', required=True, type=text_type, help='Must provide method name', location='json') self.reqparse.add_argument('technology', required=True, type=text_type, help='Technology required.', location='json') self.reqparse.add_argument('score', required=False, type=text_type, help='Override score required', location='json') self.reqparse.add_argument('disabled', required=True, type=text_type, help='Disabled flag', location='json') args = self.reqparse.parse_args() method = args['method'] technology = args['technology'] score = args['score'] if score is None: score = 0 disabled = args['disabled'] query = ItemAuditScore.query.filter( ItemAuditScore.technology == technology) query = query.filter(ItemAuditScore.method == method) auditscore = query.first() if not auditscore: auditscore = ItemAuditScore() auditscore.method = method auditscore.technology = technology auditscore.score = int(score) auditscore.disabled = bool(disabled) db.session.add(auditscore) db.session.commit() db.session.refresh(auditscore) auditscore_marshaled = marshal(auditscore.__dict__, AUDIT_SCORE_FIELDS) auditscore_marshaled['auth'] = self.auth_dict return auditscore_marshaled, 201
def post(self): """ .. http:post:: /api/1/auditscores Create a new override audit score. **Example Request**: .. sourcecode:: http POST /api/1/auditscores HTTP/1.1 Host: example.com Accept: application/json { "method": "check_xxx", "technology": "policy", "score": 1 } **Example Response**: .. sourcecode:: http HTTP/1.1 201 Created Vary: Accept Content-Type: application/json { "id": 123, "name": "Corp", "notes": "Corporate Network", "cidr": "1.2.3.4/22" } :statuscode 201: created :statuscode 401: Authentication Error. Please Login. """ self.reqparse.add_argument('method', required=True, type=unicode, help='Must provide method name', location='json') self.reqparse.add_argument('technology', required=True, type=unicode, help='Technology required.', location='json') self.reqparse.add_argument('score', required=False, type=unicode, help='Override score required', location='json') self.reqparse.add_argument('disabled', required=True, type=unicode, help='Disabled flag', location='json') args = self.reqparse.parse_args() method = args['method'] technology = args['technology'] score = args['score'] if score is None: score = 0 disabled = args['disabled'] query = ItemAuditScore.query.filter(ItemAuditScore.technology == technology) query = query.filter(ItemAuditScore.method == method) auditscore = query.first() if not auditscore: auditscore = ItemAuditScore() auditscore.method = method auditscore.technology = technology auditscore.score = int(score) auditscore.disabled = bool(disabled) db.session.add(auditscore) db.session.commit() db.session.refresh(auditscore) auditscore_marshaled = marshal(auditscore.__dict__, AUDIT_SCORE_FIELDS) auditscore_marshaled['auth'] = self.auth_dict return auditscore_marshaled, 201