def service_list(self, workspace_name, host_id): """ --- get: tags: ["Host", "Service"] summary: Get the services of a host responses: 200: description: Ok content: application/json: schema: ServiceSchema tags: ["Host", "Service"] responses: 200: description: Ok """ services = self._get_object(host_id, workspace_name).services return ServiceSchema(many=True).dump(services)
class VulnerabilitySchema(AutoSchema): _id = fields.Integer(dump_only=True, attribute='id') _rev = fields.String(dump_only=True, default='') _attachments = fields.Method(serialize='get_attachments', deserialize='load_attachments', default=[]) owned = fields.Boolean(dump_only=True, default=False) owner = PrimaryKeyRelatedField('username', dump_only=True, attribute='creator') impact = SelfNestedField(ImpactSchema()) desc = fields.String(attribute='description') description = fields.String(dump_only=True) policyviolations = fields.List(fields.String, attribute='policy_violations') refs = fields.List(fields.String(), attribute='references') issuetracker = fields.Method(serialize='get_issuetracker', dump_only=True) parent = fields.Method(serialize='get_parent', deserialize='load_parent', required=True) parent_type = MutableField(fields.Method('get_parent_type'), fields.String(), required=True) tags = PrimaryKeyRelatedField('name', dump_only=True, many=True) easeofresolution = fields.String(attribute='ease_of_resolution', validate=OneOf( Vulnerability.EASE_OF_RESOLUTIONS), allow_none=True) hostnames = PrimaryKeyRelatedField('name', many=True, dump_only=True) service = fields.Nested(ServiceSchema(only=[ '_id', 'ports', 'status', 'protocol', 'name', 'version', 'summary' ]), dump_only=True) host = fields.Integer(dump_only=True, attribute='host_id') severity = SeverityField(required=True) status = fields.Method(serialize='get_status', validate=OneOf(Vulnerability.STATUSES + ['opened']), deserialize='load_status') type = fields.Method(serialize='get_type', deserialize='load_type', required=True) obj_id = fields.String(dump_only=True, attribute='id') target = fields.String(dump_only=True, attribute='target_host_ip') host_os = fields.String(dump_only=True, attribute='target_host_os') metadata = SelfNestedField(CustomMetadataSchema()) date = fields.DateTime(attribute='create_date', dump_only=True) # This is only used for sorting custom_fields = FaradayCustomField(table_name='vulnerability', attribute='custom_fields') external_id = fields.String(allow_none=True) class Meta: model = Vulnerability fields = ('_id', 'status', 'issuetracker', 'description', 'parent', 'parent_type', 'tags', 'severity', '_rev', 'easeofresolution', 'owned', 'hostnames', 'owner', 'date', 'data', 'refs', 'desc', 'impact', 'confirmed', 'name', 'service', 'obj_id', 'type', 'policyviolations', '_attachments', 'target', 'host_os', 'resolution', 'metadata', 'custom_fields', 'external_id') def get_type(self, obj): return obj.__class__.__name__ def get_attachments(self, obj): res = {} for file_obj in obj.evidence: try: ret, errors = EvidenceSchema().dump(file_obj) if errors: raise ValidationError(errors, data=ret) res[file_obj.filename] = ret except IOError: logger.warning("File not found. Did you move your server?") return res def load_attachments(self, value): return value def get_parent(self, obj): return obj.service_id or obj.host_id def get_parent_type(self, obj): assert obj.service_id is not None or obj.host_id is not None return 'Service' if obj.service_id is not None else 'Host' def get_status(self, obj): if obj.status == 'open': return 'opened' return obj.status def get_issuetracker(self, obj): return {} def load_status(self, value): if value == 'opened': return 'open' return value def load_type(self, value): if value == 'Vulnerability': return 'vulnerability' if value == 'VulnerabilityWeb': return 'vulnerability_web' else: raise ValidationError('Invalid vulnerability type.') def load_parent(self, value): try: # sometimes api requests send str or unicode. value = int(value) except ValueError: raise ValidationError("Invalid parent type") return value @post_load def post_load_impact(self, data): # Unflatten impact (move data[impact][*] to data[*]) impact = data.pop('impact', None) if impact: data.update(impact) return data @post_load def post_load_parent(self, data): # schema guarantees that parent_type exists. parent_class = None parent_type = data.pop('parent_type', None) parent_id = data.pop('parent', None) if not (parent_type and parent_id): # Probably a partial load, since they are required return if parent_type == 'Host': parent_class = Host parent_field = 'host_id' if parent_type == 'Service': parent_class = Service parent_field = 'service_id' if not parent_class: raise ValidationError('Unknown parent type') if parent_type == 'Host' and data['type'] == 'vulnerability_web': raise ValidationError( 'Trying to set a host for a vulnerability web') try: parent = db.session.query(parent_class).join(Workspace).filter( Workspace.name == self.context['workspace_name'], parent_class.id == parent_id).one() except NoResultFound: raise ValidationError('Parent id not found: {}'.format(parent_id)) data[parent_field] = parent.id # TODO migration: check what happens when updating the parent from # service to host or viceverse return data
def service_list(self, workspace_name, host_id): services = self._get_object(host_id, workspace_name).services return ServiceSchema(many=True).dump(services)