org.owasp.dependencytrack.dao.VulnerabilityDao.java Source code

Java tutorial

Introduction

Here is the source code for org.owasp.dependencytrack.dao.VulnerabilityDao.java

Source

/*
 * This file is part of Dependency-Track.
 *
 * Dependency-Track is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * Dependency-Track is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Dependency-Track. If not, see http://www.gnu.org/licenses/.
 *
 * Copyright (c) Axway. All Rights Reserved.
 */

package org.owasp.dependencytrack.dao;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.owasp.dependencytrack.model.Application;
import org.owasp.dependencytrack.model.ApplicationDependency;
import org.owasp.dependencytrack.model.ApplicationVersion;
import org.owasp.dependencytrack.model.LibraryVersion;
import org.owasp.dependencytrack.model.ScanResult;
import org.owasp.dependencytrack.model.Vulnerability;
import org.owasp.dependencytrack.model.VulnerabilitySummary;
import org.owasp.dependencytrack.model.VulnerabilityTrend;
import org.owasp.dependencytrack.model.VulnerableComponent;
import org.owasp.dependencytrack.tasks.DependencyCheckAnalysisRequestEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Repository
public class VulnerabilityDao implements ApplicationEventPublisherAware {

    /**
     * Setup logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(VulnerabilityDao.class);

    /**
     * Event publisher
     */
    private ApplicationEventPublisher eventPublisher;

    /**
     * The Hibernate SessionFactory
     */
    @Autowired
    private SessionFactory sessionFactory;

    /**
     * Default constructor. Used when class is automatically
     * created and  SessionFactory is autowired.
     */
    public VulnerabilityDao() {
    }

    /**
     * Constructer used when class is manually created.
     * @param sessionFactory a Hibernate SessionFactory
     */
    public VulnerabilityDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /**
     * Returns a list of Vulnerability objects for LibraryVersions
     * that have a dependency of the specified ApplicationVersion.
     *
     * @param applicationVersion The ApplicationVersion to retrieve vulnerability for
     * @return a List of Vulnerability objects
     */
    @SuppressWarnings("unchecked")
    public List<VulnerableComponent> getVulnerableComponents(ApplicationVersion applicationVersion) {
        final Query query = sessionFactory.getCurrentSession()
                .createQuery("from ApplicationDependency where applicationVersion=:version");
        query.setParameter("version", applicationVersion);

        final List<VulnerableComponent> vulnerableComponents = new ArrayList<>();

        // Retrieve all of the library versions from the specified application version
        final List<LibraryVersion> libvers = new ArrayList<>();
        final List<ApplicationDependency> deps = query.list();
        for (ApplicationDependency dep : deps) {
            libvers.add(dep.getLibraryVersion());
        }

        // Iterate through the library versions looking for scan results
        for (LibraryVersion libraryVersion : libvers) {
            final Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ScanResult.class);
            criteria.add(Expression.eq("libraryVersion", libraryVersion));
            final ProjectionList projList = Projections.projectionList();
            projList.add(Projections.property("libraryVersion"));
            projList.add(Projections.property("vulnerability"));
            criteria.setProjection(Projections.distinct(projList));
            final List<Object[]> results = criteria.list();
            final List<Vulnerability> vulns = new ArrayList<>();

            for (Object[] result : results) {
                for (Object object : result) {
                    if (object instanceof Vulnerability) {
                        vulns.add((Vulnerability) object);
                    }
                }
            }

            final VulnerableComponent vulnerableComponent = new VulnerableComponent();
            vulnerableComponent.setLibraryVersion(libraryVersion);
            vulnerableComponent.setVulnerabilities(vulns);
            // Add the VulnerableComponent to the list of vulnerableComponents to return
            vulnerableComponents.add(vulnerableComponent);
        }
        return vulnerableComponents;
    }

    public List<VulnerabilitySummary> getVulnerabilitySummary(int id) {
        final List<VulnerabilitySummary> summaryList = new ArrayList<>();
        final Query query = sessionFactory.getCurrentSession().createQuery("from Application where id=:id");
        query.setParameter("id", id);
        final List<Application> applications = query.list();
        for (Application application : applications) {
            for (ApplicationVersion version : application.getVersions()) {
                summaryList.add(getVulnerabilitySummary(version));
            }
        }
        return summaryList;
    }

    public VulnerabilitySummary getVulnerabilitySummary(ApplicationVersion applicationVerion) {
        final List<VulnerableComponent> vulnerableComponents = getVulnerableComponents(applicationVerion);

        final VulnerabilitySummary vulnerabilitySummary = new VulnerabilitySummary();
        vulnerabilitySummary.setApplicationVersion(applicationVerion);
        vulnerabilitySummary.setVulnerableComponents(vulnerableComponents.size());

        for (VulnerableComponent vulnerableComponent : vulnerableComponents) {
            final List<Vulnerability> vulnerabilities = vulnerableComponent.getVulnerabilities();

            for (Vulnerability vulnerability : vulnerabilities) {

                if (vulnerability.getSeverity() == Vulnerability.Severity.HIGH) {
                    vulnerabilitySummary.setHigh(vulnerabilitySummary.getHigh() + 1);
                } else if (vulnerability.getSeverity() == Vulnerability.Severity.MEDIUM) {
                    vulnerabilitySummary.setMedium(vulnerabilitySummary.getMedium() + 1);
                } else if (vulnerability.getSeverity() == Vulnerability.Severity.LOW) {
                    vulnerabilitySummary.setLow(vulnerabilitySummary.getLow() + 1);
                }

            }
        }
        return vulnerabilitySummary;
    }

    public List<Vulnerability> getVulnsForLibraryVersion(LibraryVersion libraryVersion) {
        //todo: remove criteria and replace with HQL
        final Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ScanResult.class);
        criteria.add(Expression.eq("libraryVersion", libraryVersion));
        final ProjectionList projList = Projections.projectionList();
        projList.add(Projections.property("libraryVersion"));
        projList.add(Projections.property("vulnerability"));
        criteria.setProjection(Projections.distinct(projList));
        final List<Object[]> results = criteria.list();
        final List<Vulnerability> vulns = new ArrayList<>();

        for (Object[] result : results) {
            for (Object object : result) {
                if (object instanceof Vulnerability) {
                    vulns.add((Vulnerability) object);
                }
            }
        }

        return vulns;
    }

    /**
     * Performs a series of queries to obtain scan result history for the specified timespan
     * and constructs a VulnerabilityTrend object with historical vulnerability data.
     * @param timespan the timespan to perform the query on (i.e. last 30, 60, 90, 365 days)
     * @param appVersionId todo future use
     * @return a VulnerabilityTrend object containing historical data
     */
    public VulnerabilityTrend getVulnerabilityTrend(VulnerabilityTrend.Timespan timespan, int appVersionId) {
        final Session session = sessionFactory.getCurrentSession();
        final Map<Date, VulnerabilitySummary> map = new LinkedHashMap<>();

        // Get the start date and end date for retrieving result info
        final Calendar startDate = Calendar.getInstance();
        final Calendar endDate = Calendar.getInstance();
        startDate.add(Calendar.DAY_OF_MONTH, -timespan.getDays());

        // Using the date range above, check to see how many datapoints are in that range
        final Query dateQuery = session.createQuery(
                "select distinct s.scanDate from ScanResult s where s.scanDate >= ? and s.scanDate <= ? order by s.scanDate asc");
        dateQuery.setParameter(0, startDate.getTime());
        dateQuery.setParameter(1, endDate.getTime());
        final List<Date> dates = dateQuery.list();
        final int numDates = dates.size();

        final List<Date> dataPointDates = new ArrayList<>();
        if (numDates < timespan.getDivisions()) {
            dataPointDates.addAll(dates);
        } else {
            final int dataPoints = timespan.getDivisions();
            final double sliceEvery = ((double) dates.size() / (double) dataPoints);
            int sliceEveryProgress = 0;
            for (int i = 0; i < dataPoints; i++) {
                if (i == 0) { // Always include the first date from the results
                    dataPointDates.add(dates.get(0));
                } else if (i == (dataPoints - 1)) { // Always include the last date from the results
                    dataPointDates.add(dates.get(dates.size() - 1));
                } else if (sliceEveryProgress >= i) { // Include everything in between
                    dataPointDates.add(dates.get(i));
                }
                sliceEveryProgress += sliceEvery;
            }
        }
        // Iterate for the number of datapoints we're going to eventually present
        for (Date dataPointDate : dataPointDates) {
            final Query query = session.createQuery("select distinct s from ScanResult s where s.scanDate = ?");
            query.setParameter(0, dataPointDate);
            final List<ScanResult> scanResults = query.list();
            for (ScanResult scanResult : scanResults) {
                addVulnerabilityToTrend(map, scanResult);
            }
        }
        final VulnerabilityTrend trend = new VulnerabilityTrend();
        final Set<Date> keys = map.keySet();
        for (Date date : keys) {
            trend.addData(date, map.get(date));
        }
        return trend;
    }

    /**
     * Adds the specified scan result to a growing map
     * @param map a map of VulnerabilitySummary object using Date as the key
     * @param scanResult a ScanResult object
     */
    private void addVulnerabilityToTrend(Map<Date, VulnerabilitySummary> map, ScanResult scanResult) {
        final Date scanDate = scanResult.getScanDate();
        final Vulnerability vulnerability = scanResult.getVulnerability();
        VulnerabilitySummary summary = map.get(scanDate);
        if (summary == null) {
            summary = new VulnerabilitySummary();
            map.put(scanDate, summary);
        }
        final Vulnerability.Severity severity = vulnerability.getSeverity();
        if (Vulnerability.Severity.HIGH == severity) {
            summary.addHigh();
        } else if (Vulnerability.Severity.MEDIUM == severity) {
            summary.addMedium();
        } else if (Vulnerability.Severity.LOW == severity) {
            summary.addLow();
        }
    }

    public void initiateFullDependencyCheckScan() {
        final Query query = sessionFactory.getCurrentSession().createQuery("from LibraryVersion");
        final List<LibraryVersion> libraryVersions = query.list();
        this.eventPublisher.publishEvent(new DependencyCheckAnalysisRequestEvent(libraryVersions));
        sessionFactory.close();
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.eventPublisher = applicationEventPublisher;
    }

    /**
     * Update the vulnerability count in all ApplicationVersion objects.
     */
    @SuppressWarnings("unchecked")
    public void updateApplicationVersionVulnerabilityCount() {
        final Session session = sessionFactory.getCurrentSession();
        final Query appVerQuery = session.createQuery("FROM ApplicationVersion ");
        final List<ApplicationVersion> applicationVersions = appVerQuery.list();
        for (ApplicationVersion applicationVersion : applicationVersions) {
            final Query depQuery = sessionFactory.getCurrentSession()
                    .createQuery("from ApplicationDependency where applicationVersion=:version");
            depQuery.setParameter("version", applicationVersion);

            int appVulnCount = 0;
            final List<ApplicationDependency> dependencies = depQuery.list();
            for (ApplicationDependency dependency : dependencies) {
                final LibraryVersion libraryVersion = dependency.getLibraryVersion();
                appVulnCount += libraryVersion.getVulnCount();
            }
            applicationVersion.setVulnCount(appVulnCount);
            session.save(applicationVersion);
        }
    }

    /**
     * Update the vulnerability count in all LibraryVersion objects.
     */
    @SuppressWarnings("unchecked")
    public void updateLibraryVersionVulnerabilityCount() {
        final Session session = sessionFactory.getCurrentSession();
        final Query libverQuery = session.createQuery("FROM LibraryVersion");
        final List<LibraryVersion> libraryVersions = libverQuery.list();
        for (LibraryVersion libraryVersion : libraryVersions) {
            final SQLQuery vulnQuery = sessionFactory.getCurrentSession().createSQLQuery(
                    "SELECT DISTINCT VULNERABILITYID FROM SCANRESULT WHERE LIBRARYVERSIONID=:libraryVersion");

            vulnQuery.setParameter("libraryVersion", libraryVersion.getId());
            final int vulnCount = vulnQuery.list().size();
            libraryVersion.setVulnCount(vulnCount);
            session.save(libraryVersion);
        }
    }
}