////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2013 Denim Group, Ltd.
//
// The contents of this file are subject to the Mozilla Public License
// Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is ThreadFix.
//
// The Initial Developer of the Original Code is Denim Group, Ltd.
// Portions created by Denim Group, Ltd. are Copyright (C)
// Denim Group, Ltd. All Rights Reserved.
//
// Contributor(s): Denim Group, Ltd.
//
////////////////////////////////////////////////////////////////////////
package com.denimgroup.threadfix.data.dao.hibernate;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.denimgroup.threadfix.data.dao.VulnerabilityDao;
import com.denimgroup.threadfix.data.entities.Application;
import com.denimgroup.threadfix.data.entities.DeletedVulnerability;
import com.denimgroup.threadfix.data.entities.Finding;
import com.denimgroup.threadfix.data.entities.Vulnerability;
/**
* Hibernate Vulnerability DAO implementation. Most basic methods are
* implemented in the AbstractGenericDao
*
* @author mcollins, dwolf
* @see AbstractGenericDao
*/
@Repository
public class HibernateVulnerabilityDao implements VulnerabilityDao {
private SessionFactory sessionFactory;
@Autowired
public HibernateVulnerabilityDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
@SuppressWarnings("unchecked")
public List<Vulnerability> retrieveAll() {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vulnerability "
+ "where vulnerability.expired = :false order by vulnerability.id ")
.setBoolean("false", false).list();
}
@Override
@SuppressWarnings("unchecked")
public List<Vulnerability> retrieveAllActive() {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vulnerability "
+ "where vulnerability.active = :true "
+ "and vulnerability.expired = :false")
.setBoolean("false", false).setBoolean("true", true).list();
}
@Override
@SuppressWarnings("unchecked")
public List<Vulnerability> retrieveAllActiveByApplication(int applicationId) {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vuln where vuln.application = :appId "
+ "and vuln.active = :true and vuln.expired = :false")
.setInteger("appId", applicationId).setBoolean("true", true)
.setBoolean("false", false).list();
}
@Override
@SuppressWarnings("unchecked")
public List<Vulnerability> retrieveAllByGenericVulnerabilityAndApp(
Vulnerability vulnerability) {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vuln where vuln.application = :appId "
+ "and vuln.genericVulnerability = :gvId and vuln.expired = :false")
.setInteger("gvId",
vulnerability.getGenericVulnerability().getId())
.setInteger("appId", vulnerability.getApplication().getId())
.setBoolean("false", false).list();
}
@Override
@SuppressWarnings("unchecked")
public List<Vulnerability> retrieveAllInactive() {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vulnerability "
+ "where vulnerability.active = :false "
+ "and vulnerability.expired = :false")
.setBoolean("false", false).list();
}
@SuppressWarnings("unchecked")
@Override
public List<Vulnerability> retrieveByApplicationIdList(List<Integer> applicationIdList) {
return sessionFactory.getCurrentSession()
.createQuery("from Vulnerability vulnerability " +
"where vulnerability.application.id in (:idList)")
.setParameterList("idList", applicationIdList).list();
}
@Override
public Vulnerability retrieveByHashAndApp(String hash, int applicationId) {
// the function defaults to locationVulnerabilityHash (to avoid a super
// long name)
return (Vulnerability) sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vulnerability "
+ "where vulnerability.locationVariableHash = :hash "
+ "and vulnerability.application = :appId "
+ "and vulnerability.expired = :false")
.setString("hash", hash).setInteger("appId", applicationId)
.setBoolean("false", false).uniqueResult();
}
@Override
public Vulnerability retrieveById(int id) {
Vulnerability vuln = (Vulnerability) sessionFactory.getCurrentSession()
.get(Vulnerability.class, id);
if (vuln != null && !vuln.isExpired()) {
return vuln;
} else {
return null;
}
}
@SuppressWarnings("unchecked")
@Override
public List<Vulnerability> retrieveByLocationHashAndApp(String hash,
int applicationId) {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vulnerability "
+ "where vulnerability.locationHash = :hash "
+ "and vulnerability.application = :appId "
+ "and vulnerability.expired = :false")
.setString("hash", hash).setInteger("appId", applicationId)
.setBoolean("false", false).list();
}
@SuppressWarnings("unchecked")
@Override
public List<Vulnerability> retrieveByVariableHashAndApp(String hash,
int applicationId) {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vulnerability "
+ "where vulnerability.variableHash = :hash "
+ "and vulnerability.application = :appId "
+ "and vulnerability.expired = :false")
.setString("hash", hash).setInteger("appId", applicationId)
.setBoolean("false", false).list();
}
@Override
@SuppressWarnings("unchecked")
public List<Vulnerability> retrieveSimilarHashes(Vulnerability vulnerability) {
return sessionFactory
.getCurrentSession()
.createQuery(
"from Vulnerability vuln where vuln.application = :appId "
+ "and vuln.expired = :false "
+ "and (vuln.locationVariableHash = :lvHash or "
+ "vuln.locationHash = :lHash or vuln.variableHash = :vHash)")
.setString("lvHash", vulnerability.getLocationVariableHash())
.setString("lHash", vulnerability.getLocationHash())
.setString("vHash", vulnerability.getVariableHash())
.setInteger("appId", vulnerability.getApplication().getId())
.setBoolean("false", false).list();
}
@Override
public void saveOrUpdate(Vulnerability vulnerability) {
sessionFactory.getCurrentSession().saveOrUpdate(vulnerability);
}
@Override
public void delete(Vulnerability vulnerability) {
sessionFactory.getCurrentSession().save(new DeletedVulnerability(vulnerability));
sessionFactory.getCurrentSession().delete(vulnerability);
}
/**
* I would feel bad about having so much logic here but the alternatives are
* passing in a query string which is a terrible idea or
* having a ton of methods which also isn't any good.
*/
@SuppressWarnings("unchecked")
@Override
public List<Vulnerability> retrieveActiveByAppIdAndPage(int appId, int page,
int sort, int field, Integer cwe, String description, String severity,
String path, String param, boolean open, boolean falsePositive) {
String[] headers = new String[] { "",
"vuln.name",
"severity.intValue",
"surface.path",
"surface.parameter" };
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Vulnerability.class);
if (!open && falsePositive) {
criteria.add(Restrictions.eq("isFalsePositive", true));
} else {
criteria.add(Restrictions.eq("active", open))
.add(Restrictions.eq("isFalsePositive", falsePositive));
}
criteria.add( Restrictions.eq("application.id", appId))
.createAlias("genericSeverity", "severity")
.createAlias("genericVulnerability", "vuln")
.createAlias("surfaceLocation", "surface")
.setFirstResult((page - 1) * 100)
.setMaxResults(100);
// Add Filtering restrictions
if (description != null)
criteria.add(Restrictions.like("vuln.name", "%" + description + "%").ignoreCase());
if (severity != null)
criteria.add(Restrictions.like("severity.name", "%" + severity + "%").ignoreCase());
if (path != null)
criteria.add(Restrictions.like("surface.path", "%" + path + "%").ignoreCase());
if (param != null)
criteria.add(Restrictions.like("surface.parameter", "%" + param + "%").ignoreCase());
if (cwe != null) {
criteria.add(Restrictions.eq("vuln.id", cwe));
}
// Add Ordering
if ((sort != 1 && sort != 2) ||
field <= 0 || field > headers.length) {
criteria.addOrder( Order.desc("severity.intValue") )
.addOrder( Order.asc("vuln.name") )
.addOrder( Order.asc("surface.path") )
.addOrder( Order.asc("surface.parameter") );
} else {
String item = headers[field];
if (sort == 1) {
criteria.addOrder( Order.asc(item));
} else if (sort == 2) {
criteria.addOrder( Order.desc(item));
}
}
return criteria.list();
}
@Override
public long getVulnCountWithFilters(Integer appId, String description,
String severity, String path, String param, Integer cweInteger,
boolean open, boolean falsePositive) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
Vulnerability.class);
if (!open && falsePositive) {
criteria.add(Restrictions.eq("isFalsePositive", true));
} else {
criteria.add(Restrictions.eq("active", open))
.add(Restrictions.eq("isFalsePositive", falsePositive));
}
criteria.createAlias("genericVulnerability", "vuln")
.add(Restrictions.eq("application.id", appId));
// Add Filtering restrictions
if (description != null)
criteria.add(Restrictions
.like("vuln.name", "%" + description + "%").ignoreCase());
if (severity != null)
criteria.createAlias("genericSeverity", "severity")
.add(Restrictions.like("severity.name",
"%" + severity + "%").ignoreCase());
if (path != null)
criteria.createAlias("surfaceLocation", "surface")
.add(Restrictions.like("surface.path", "%" + path + "%")
.ignoreCase());
if (cweInteger != null) {
criteria.add(Restrictions.eq("vuln.id", cweInteger));
}
if (param != null)
criteria.add(Restrictions.like("surface.parameter",
"%" + param + "%").ignoreCase());
return (Long) criteria.setProjection(Projections.rowCount()).uniqueResult();
}
@Override
public long getVulnCount(Integer appId, boolean open) {
return (Long) sessionFactory
.getCurrentSession()
.createCriteria(Vulnerability.class)
.add(Restrictions.eq("active", open))
.add(Restrictions.eq("isFalsePositive", false))
.add(Restrictions.eq("application.id", appId))
.setProjection(Projections.rowCount())
.uniqueResult();
}
@SuppressWarnings("unchecked")
public List<Vulnerability> getFalsePositiveVulnCount(Application application,
boolean value) {
return sessionFactory
.getCurrentSession()
.createQuery("from Vulnerability vuln where vuln.application = :appId "
+ "and vuln.isFalsePositive = :fp")
.setBoolean("fp", value)
.setInteger("appId", application.getId()).list();
}
@Override
public void evict(Finding finding) {
sessionFactory.getCurrentSession().evict(finding);
}
@SuppressWarnings("unchecked")
@Override
public void markAllClosed(List<Integer> vulnerabilityIds) {
List<Vulnerability> vulns = sessionFactory.getCurrentSession()
.createCriteria(Vulnerability.class)
.add(Restrictions.in("id", vulnerabilityIds))
.list();
for (Vulnerability vuln : vulns) {
if (vuln != null && vuln.isActive()) {
vuln.setActive(false);
vuln.setFoundByScanner(false);
saveOrUpdate(vuln);
}
}
}
@SuppressWarnings("unchecked")
@Override
public void markAllOpen(List<Integer> vulnerabilityIds) {
List<Vulnerability> vulns = sessionFactory.getCurrentSession()
.createCriteria(Vulnerability.class)
.add(Restrictions.in("id", vulnerabilityIds))
.list();
for (Vulnerability vuln : vulns) {
if (vuln != null && !vuln.isActive()) {
vuln.setActive(true);
vuln.setFoundByScanner(true);
saveOrUpdate(vuln);
}
}
}
@Override
public boolean activeVulnerabilitiesExist() {
return ((Vulnerability) sessionFactory
.getCurrentSession()
.createCriteria(Vulnerability.class)
.createAlias("application", "app")
.add( Restrictions.eq("app.active", true))
.setMaxResults(1)
.uniqueResult()) != null;
}
@SuppressWarnings("unchecked")
@Override
public List<Integer> getTopTenVulnTypes(List<Integer> applicationIdList) {
return (List<Integer>) sessionFactory
.getCurrentSession()
.createQuery(
"select vuln.genericVulnerability.id " +
"from Vulnerability vuln " +
"where vuln.application.id in (:ids) " +
"group by vuln.genericVulnerability.id " +
"order by count(vuln.genericVulnerability.id) desc")
.setParameterList("ids", applicationIdList)
.setMaxResults(10)
.list();
}
}