continued work on threading and code improvement

This commit is contained in:
Jeremy Long
2017-09-03 09:05:55 -04:00
parent 795de6f9ea
commit ab5de24518
158 changed files with 1266 additions and 964 deletions

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.taskdefs;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
@@ -46,6 +47,7 @@ import org.slf4j.impl.StaticLoggerBinder;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class Check extends Update { public class Check extends Update {
/** /**
@@ -161,6 +163,7 @@ public class Check extends Update {
/** /**
* Suppression file paths. * Suppression file paths.
*/ */
@SuppressWarnings("CanBeFinal")
private List<String> suppressionFiles = new ArrayList<>(); private List<String> suppressionFiles = new ArrayList<>();
/** /**
@@ -1065,7 +1068,7 @@ public class Check extends Update {
* @throws BuildException thrown if a CVSS score is found that is higher * @throws BuildException thrown if a CVSS score is found that is higher
* than the threshold set * than the threshold set
*/ */
private void checkForFailure(List<Dependency> dependencies) throws BuildException { private void checkForFailure(Dependency[] dependencies) throws BuildException {
final StringBuilder ids = new StringBuilder(); final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) { for (Dependency d : dependencies) {
for (Vulnerability v : d.getVulnerabilities()) { for (Vulnerability v : d.getVulnerabilities()) {
@@ -1092,7 +1095,7 @@ public class Check extends Update {
* *
* @param dependencies a list of dependency objects * @param dependencies a list of dependency objects
*/ */
private void showSummary(List<Dependency> dependencies) { private void showSummary(Dependency[] dependencies) {
final StringBuilder summary = new StringBuilder(); final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) { for (Dependency d : dependencies) {
boolean firstEntry = true; boolean firstEntry = true;

View File

@@ -48,7 +48,7 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
* *
* @return the StaticLoggerBinder singleton * @return the StaticLoggerBinder singleton
*/ */
public static final StaticLoggerBinder getSingleton() { public static StaticLoggerBinder getSingleton() {
return SINGLETON; return SINGLETON;
} }

View File

@@ -312,7 +312,6 @@ public class App {
* @param excludes an array of ant style excludes * @param excludes an array of ant style excludes
* @return returns the set of identified files * @return returns the set of identified files
* @throws InvalidScanPathException thrown when the scan path is invalid * @throws InvalidScanPathException thrown when the scan path is invalid
* @throws IllegalStateException
*/ */
private Set<File> scanAntStylePaths(List<String> antStylePaths, int symLinkDepth, String[] excludes) private Set<File> scanAntStylePaths(List<String> antStylePaths, int symLinkDepth, String[] excludes)
throws InvalidScanPathException { throws InvalidScanPathException {

View File

@@ -21,12 +21,12 @@ import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer; import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Task to support parallelism of dependency-check analysis. Analyses a single * Task to support parallelism of dependency-check analysis. Analyses a single
@@ -34,6 +34,7 @@ import java.util.concurrent.Callable;
* *
* @author Stefan Neuhaus * @author Stefan Neuhaus
*/ */
@ThreadSafe
public class AnalysisTask implements Callable<Void> { public class AnalysisTask implements Callable<Void> {
/** /**
@@ -57,10 +58,6 @@ public class AnalysisTask implements Callable<Void> {
* The list of exceptions that may occur during analysis. * The list of exceptions that may occur during analysis.
*/ */
private final List<Throwable> exceptions; private final List<Throwable> exceptions;
/**
* A reference to the global settings object.
*/
private final Settings settings;
/** /**
* Creates a new analysis task. * Creates a new analysis task.
@@ -70,16 +67,12 @@ public class AnalysisTask implements Callable<Void> {
* @param engine the dependency-check engine * @param engine the dependency-check engine
* @param exceptions exceptions that occur during analysis will be added to * @param exceptions exceptions that occur during analysis will be added to
* this collection of exceptions * this collection of exceptions
* @param settings a reference to the global settings object; this is
* necessary so that when the thread is started the dependencies have a
* correct reference to the global settings.
*/ */
AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions, Settings settings) { AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions) {
this.analyzer = analyzer; this.analyzer = analyzer;
this.dependency = dependency; this.dependency = dependency;
this.engine = engine; this.engine = engine;
this.exceptions = exceptions; this.exceptions = exceptions;
this.settings = settings;
} }
/** /**

View File

@@ -57,6 +57,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.NotThreadSafe;
import static org.owasp.dependencycheck.analyzer.AnalysisPhase.*; import static org.owasp.dependencycheck.analyzer.AnalysisPhase.*;
@@ -68,6 +69,7 @@ import static org.owasp.dependencycheck.analyzer.AnalysisPhase.*;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class Engine implements FileFilter, AutoCloseable { public class Engine implements FileFilter, AutoCloseable {
/** /**
@@ -170,7 +172,7 @@ public class Engine implements FileFilter, AutoCloseable {
* The ClassLoader to use when dynamically loading Analyzer and Update * The ClassLoader to use when dynamically loading Analyzer and Update
* services. * services.
*/ */
private ClassLoader serviceClassLoader; private final ClassLoader serviceClassLoader;
/** /**
* A reference to the database. * A reference to the database.
*/ */
@@ -304,8 +306,42 @@ public class Engine implements FileFilter, AutoCloseable {
* @see Collections#synchronizedList(List) * @see Collections#synchronizedList(List)
* @see Analyzer#supportsParallelProcessing() * @see Analyzer#supportsParallelProcessing()
*/ */
public synchronized List<Dependency> getDependencies() { // public synchronized List<Dependency> getDependencies() {
return dependencies; // return dependencies;
// }
/**
* Adds a dependency.
*
* @param dependency the dependency to add
*/
public synchronized void addDependency(Dependency dependency) {
dependencies.add(dependency);
}
/**
* Sorts the dependency list.
*/
public synchronized void sortDependencies() {
//TODO - is this actually necassary????
Collections.sort(dependencies);
}
/**
* Removes the dependency.
*
* @param dependency the dependency to remove.
*/
public synchronized void removeDependency(Dependency dependency) {
dependencies.remove(dependency);
}
/**
* Returns a copy of the dependencies as an array.
*
* @return the dependencies identified
*/
public synchronized Dependency[] getDependencies() {
return dependencies.toArray(new Dependency[dependencies.size()]);
} }
/** /**
@@ -750,7 +786,7 @@ public class Engine implements FileFilter, AutoCloseable {
final List<AnalysisTask> result = new ArrayList<>(); final List<AnalysisTask> result = new ArrayList<>();
synchronized (dependencies) { synchronized (dependencies) {
for (final Dependency dependency : dependencies) { for (final Dependency dependency : dependencies) {
final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions, settings); final AnalysisTask task = new AnalysisTask(analyzer, dependency, this, exceptions);
result.add(task); result.add(task);
} }
} }
@@ -907,9 +943,9 @@ public class Engine implements FileFilter, AutoCloseable {
} }
/** /**
* Returns * Returns the configured settings.
* *
* @return * @return the configured settings
*/ */
public Settings getSettings() { public Settings getSettings() {
return settings; return settings;

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.agent;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
@@ -59,6 +60,7 @@ import org.slf4j.LoggerFactory;
* @author Steve Springett * @author Steve Springett
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
@NotThreadSafe
public class DependencyCheckScanAgent { public class DependencyCheckScanAgent {
//<editor-fold defaultstate="collapsed" desc="private fields"> //<editor-fold defaultstate="collapsed" desc="private fields">
@@ -938,7 +940,7 @@ public class DependencyCheckScanAgent {
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if * @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
* there is an exception executing the scan. * there is an exception executing the scan.
*/ */
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException { private void checkForFailure(Dependency[] dependencies) throws ScanAgentException {
final StringBuilder ids = new StringBuilder(); final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) { for (Dependency d : dependencies) {
boolean addName = true; boolean addName = true;
@@ -969,7 +971,7 @@ public class DependencyCheckScanAgent {
* *
* @param dependencies a list of dependency objects * @param dependencies a list of dependency objects
*/ */
private void showSummary(List<Dependency> dependencies) { private void showSummary(Dependency[] dependencies) {
final StringBuilder summary = new StringBuilder(); final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) { for (Dependency d : dependencies) {
boolean firstEntry = true; boolean firstEntry = true;

View File

@@ -23,6 +23,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public abstract class AbstractAnalyzer implements Analyzer { public abstract class AbstractAnalyzer implements Analyzer {
/** /**
@@ -153,7 +155,7 @@ public abstract class AbstractAnalyzer implements Analyzer {
try { try {
this.setEnabled(settings.getBoolean(key, true)); this.setEnabled(settings.getBoolean(key, true));
} catch (InvalidSettingException ex) { } catch (InvalidSettingException ex) {
String msg = String.format("Invalid setting for property '{}'", key); final String msg = String.format("Invalid setting for property '%s'", key);
LOGGER.warn(msg); LOGGER.warn(msg);
LOGGER.debug(msg, ex); LOGGER.debug(msg, ex);
} }

View File

@@ -0,0 +1,125 @@
/*
* This file is part of dependency-check-core.
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.analyzer;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* This analyzer ensures dependencies that should be grouped together, to remove
* excess noise from the report, are grouped. An example would be Spring, Spring
* Beans, Spring MVC, etc. If they are all for the same version and have the
* same relative path then these should be grouped into a single dependency
* under the core/main library.</p>
* <p>
* Note, this grouping only works on dependencies with identified CVE
* entries</p>
*
* @author Jeremy Long
*/
@ThreadSafe
public abstract class AbstractDependencyComparingAnalyzer extends AbstractAnalyzer {
/**
* The Logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDependencyComparingAnalyzer.class);
/**
* a flag indicating if this analyzer has run. This analyzer only runs once.
*/
private boolean analyzed = false;
/**
* Returns a flag indicating if this analyzer has run. This analyzer only
* runs once. Note this is currently only used in the unit tests.
*
* @return a flag indicating if this analyzer has run. This analyzer only
* runs once
*/
protected synchronized boolean getAnalyzed() {
return analyzed;
}
/**
* Does not support parallel processing as it only runs once and then
* operates on <em>all</em> dependencies.
*
* @return whether or not parallel processing is enabled
* @see #analyze(Dependency, Engine)
*/
@Override
public final boolean supportsParallelProcessing() {
return false;
}
/**
* Analyzes a set of dependencies. If they have been found to have the same
* base path and the same set of identifiers they are likely related. The
* related dependencies are bundled into a single reportable item.
*
* @param ignore this analyzer ignores the dependency being analyzed
* @param engine the engine that is scanning the dependencies
* @throws AnalysisException is thrown if there is an error reading the JAR
* file.
*/
@Override
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
if (!analyzed) {
analyzed = true;
final Set<Dependency> dependenciesToRemove = new HashSet<>();
final Dependency[] dependencies = engine.getDependencies();
if (dependencies.length < 2) {
return;
}
for (int x = 0; x < dependencies.length - 1; x++) {
final Dependency dependency = dependencies[x];
if (!dependenciesToRemove.contains(dependency)) {
for (int y = x + 1; y < dependencies.length; y++) {
final Dependency nextDependency = dependencies[y];
if (evaluateDependencies(dependency, nextDependency, dependenciesToRemove)) {
break;
}
}
}
}
for (Dependency d : dependenciesToRemove) {
engine.removeDependency(d);
}
}
}
/**
* Evaluates the dependencies
*
* @param dependency a dependency to compare
* @param nextDependency a dependency to compare
* @param dependenciesToRemove a set of dependencies that will be removed
* @return true if a dependency is removed; otherwise false
*/
protected abstract boolean evaluateDependencies(final Dependency dependency,
final Dependency nextDependency, final Set<Dependency> dependenciesToRemove);
}

View File

@@ -25,6 +25,7 @@ import java.io.FileFilter;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
@@ -34,6 +35,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer { public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
//<editor-fold defaultstate="collapsed" desc="Field definitions, getters, and setters "> //<editor-fold defaultstate="collapsed" desc="Field definitions, getters, and setters ">
@@ -46,15 +48,6 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
*/ */
private boolean filesMatched = false; private boolean filesMatched = false;
/**
* Get the value of filesMatched. A flag indicating whether the scan
* included any file types this analyzer supports.
*
* @return the value of filesMatched
*/
protected boolean isFilesMatched() {
return filesMatched;
}
/** /**
* Set the value of filesMatched. A flag indicating whether the scan * Set the value of filesMatched. A flag indicating whether the scan

View File

@@ -22,10 +22,11 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
@@ -47,6 +48,7 @@ import org.xml.sax.SAXException;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer { public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
/** /**
@@ -56,15 +58,15 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
/** /**
* The list of suppression rules * The list of suppression rules
*/ */
private List<SuppressionRule> rules; private SuppressionRule[] rules = null;
/** /**
* Get the number of suppression rules. * Get the number of suppression rules.
* *
* @return the number of suppression rules * @return the number of suppression rules
*/ */
protected synchronized int getRuleCount() { protected int getRuleCount() {
return rules.size(); return rules.length;
} }
/** /**
@@ -83,17 +85,19 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
* @throws InitializationException thrown if there is an exception * @throws InitializationException thrown if there is an exception
*/ */
@Override @Override
public void initializeAnalyzer(Engine engine) throws InitializationException { public synchronized void initializeAnalyzer(Engine engine) throws InitializationException {
try { if (rules == null) {
loadSuppressionData(); try {
} catch (SuppressionParseException ex) { rules = loadSuppressionData();
throw new InitializationException("Error initializing the suppression analyzer: " + ex.getLocalizedMessage(), ex); } catch (SuppressionParseException ex) {
throw new InitializationException("Error initializing the suppression analyzer: " + ex.getLocalizedMessage(), ex);
}
} }
} }
@Override @Override
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
if (rules == null || rules.size() <= 0) { if (rules == null || rules.length <= 0) {
return; return;
} }
for (final SuppressionRule rule : rules) { for (final SuppressionRule rule : rules) {
@@ -104,40 +108,43 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
/** /**
* Loads all the suppression rules files configured in the {@link Settings}. * Loads all the suppression rules files configured in the {@link Settings}.
* *
* @return the array of rules that were loaded
* @throws SuppressionParseException thrown if the XML cannot be parsed. * @throws SuppressionParseException thrown if the XML cannot be parsed.
*/ */
private synchronized void loadSuppressionData() throws SuppressionParseException { private SuppressionRule[] loadSuppressionData() throws SuppressionParseException {
List<SuppressionRule> ruleList;
final SuppressionParser parser = new SuppressionParser(); final SuppressionParser parser = new SuppressionParser();
try { try {
final InputStream in = FileUtils.getResourceAsStream("dependencycheck-base-suppression.xml"); final InputStream in = FileUtils.getResourceAsStream("dependencycheck-base-suppression.xml");
rules = Collections.synchronizedList(parser.parseSuppressionRules(in)); ruleList = parser.parseSuppressionRules(in);
} catch (SAXException ex) { } catch (SAXException ex) {
throw new SuppressionParseException("Unable to parse the base suppression data file", ex); throw new SuppressionParseException("Unable to parse the base suppression data file", ex);
} }
final String[] suppressionFilePaths = getSettings().getArray(Settings.KEYS.SUPPRESSION_FILE); final String[] suppressionFilePaths = getSettings().getArray(Settings.KEYS.SUPPRESSION_FILE);
if (suppressionFilePaths == null || suppressionFilePaths.length == 0) { if (suppressionFilePaths != null && suppressionFilePaths.length > 0) {
return; // Load all the suppression file paths
for (final String suppressionFilePath : suppressionFilePaths) {
ruleList.addAll(loadSuppressionFile(parser, suppressionFilePath));
}
} }
LOGGER.debug("{} suppression rules were loaded.", ruleList.size());
// Load all the suppression file paths return ruleList.toArray(new SuppressionRule[ruleList.size()]);
for (final String suppressionFilePath : suppressionFilePaths) {
loadSuppressionFile(parser, suppressionFilePath);
}
LOGGER.debug("{} suppression rules were loaded.", rules.size());
} }
/** /**
* Load a single suppression rules file from the path provided using the * Load a single suppression rules file from the path provided using the
* parser provided. * parser provided.
* *
* @param parser the parser to use for loading the file. * @param parser the parser to use for loading the file
* @param suppressionFilePath the path to load. * @param suppressionFilePath the path to load
* @return the list of loaded suppression rules
* @throws SuppressionParseException thrown if the suppression file cannot * @throws SuppressionParseException thrown if the suppression file cannot
* be loaded and parsed. * be loaded and parsed.
*/ */
private synchronized void loadSuppressionFile(final SuppressionParser parser, final String suppressionFilePath) throws SuppressionParseException { private List<SuppressionRule> loadSuppressionFile(final SuppressionParser parser,
final String suppressionFilePath) throws SuppressionParseException {
LOGGER.debug("Loading suppression rules from '{}'", suppressionFilePath); LOGGER.debug("Loading suppression rules from '{}'", suppressionFilePath);
final List<SuppressionRule> list = new ArrayList<>();
File file = null; File file = null;
boolean deleteTempFile = false; boolean deleteTempFile = false;
try { try {
@@ -146,7 +153,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
deleteTempFile = true; deleteTempFile = true;
file = getSettings().getTempFile("suppression", "xml"); file = getSettings().getTempFile("suppression", "xml");
final URL url = new URL(suppressionFilePath); final URL url = new URL(suppressionFilePath);
Downloader downloader = new Downloader(getSettings()); final Downloader downloader = new Downloader(getSettings());
try { try {
downloader.fetchFile(url, file, false); downloader.fetchFile(url, file, false);
} catch (DownloadFailedException ex) { } catch (DownloadFailedException ex) {
@@ -177,7 +184,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
throw new SuppressionParseException(msg); throw new SuppressionParseException(msg);
} }
try { try {
rules.addAll(parser.parseSuppressionRules(file)); list.addAll(parser.parseSuppressionRules(file));
} catch (SuppressionParseException ex) { } catch (SuppressionParseException ex) {
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath()); LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage()); LOGGER.warn(ex.getMessage());
@@ -197,6 +204,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
FileUtils.delete(file); FileUtils.delete(file);
} }
} }
return list;
} }
/** /**

View File

@@ -27,10 +27,10 @@ import org.owasp.dependencycheck.utils.Settings;
* <p> * <p>
* An interface that defines an Analyzer that is used to identify Dependencies. * An interface that defines an Analyzer that is used to identify Dependencies.
* An analyzer will collect information about the dependency in the form of * An analyzer will collect information about the dependency in the form of
* Evidence.<p> * Evidence.</p>
* <p> * <p>
* When the {@link org.owasp.dependencycheck.Engine} executes it will load the * When the {@link org.owasp.dependencycheck.Engine} executes it will load the
* analyzers and call the methods in the following order: * analyzers and call the methods in the following order:</p>
* <ol> * <ol>
* <li>{@link #initializeSettings(org.owasp.dependencycheck.utils.Settings)}</li> * <li>{@link #initializeSettings(org.owasp.dependencycheck.utils.Settings)}</li>
* <li>{@link #initialize(org.owasp.dependencycheck.Engine)}</li> * <li>{@link #initialize(org.owasp.dependencycheck.Engine)}</li>
@@ -75,7 +75,7 @@ public interface Analyzer {
* *
* @param settings the configured settings * @param settings the configured settings
*/ */
public void initializeSettings(Settings settings); void initializeSettings(Settings settings);
/** /**
* The initialize method is called (once) prior to the analyze method being * The initialize method is called (once) prior to the analyze method being

View File

@@ -24,13 +24,15 @@ import static java.util.Arrays.asList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* The Analyzer Service Loader. This class loads all services that implement * The Analyzer Service Loader. This class loads all services that implement
* org.owasp.dependencycheck.analyzer.Analyzer. * {@link org.owasp.dependencycheck.analyzer.Analyzer}.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class AnalyzerService { public class AnalyzerService {
/** /**

View File

@@ -121,6 +121,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
* The phase that this analyzer is intended to run in. * The phase that this analyzer is intended to run in.
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INITIAL; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INITIAL;
/** /**
* Initializes the analyzer with the configured settings. * Initializes the analyzer with the configured settings.
* *
@@ -289,9 +290,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
} }
if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) { if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
addDisguisedJarsToDependencies(dependency, engine); addDisguisedJarsToDependencies(dependency, engine);
engine.getDependencies().remove(dependency); engine.removeDependency(dependency);
} }
Collections.sort(engine.getDependencies()); engine.sortDependencies();
} }
/** /**

View File

@@ -43,6 +43,7 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.SystemUtils;
@@ -55,6 +56,7 @@ import org.owasp.dependencycheck.utils.XmlUtils;
* @author colezlaw * @author colezlaw
* *
*/ */
@ThreadSafe
public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer { public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -111,20 +113,16 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
* @throws AnalysisException if anything goes sideways * @throws AnalysisException if anything goes sideways
*/ */
@Override @Override
public void analyzeDependency(Dependency dependency, Engine engine) public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
throws AnalysisException {
final File test = new File(dependency.getActualFilePath()); final File test = new File(dependency.getActualFilePath());
if (!test.isFile()) { if (!test.isFile()) {
throw new AnalysisException(String.format("%s does not exist and cannot be analyzed by dependency-check", throw new AnalysisException(String.format("%s does not exist and cannot be analyzed by dependency-check",
dependency.getActualFilePath())); dependency.getActualFilePath()));
} }
if (grokAssemblyExe == null) { if (grokAssemblyExe == null) {
LOGGER.warn("GrokAssembly didn't get deployed"); LOGGER.warn("GrokAssembly didn't get deployed");
return; return;
} }
final List<String> args = buildArgumentList(); final List<String> args = buildArgumentList();
if (args == null) { if (args == null) {
LOGGER.warn("Assembly Analyzer was unable to execute"); LOGGER.warn("Assembly Analyzer was unable to execute");
@@ -199,8 +197,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.error("----------------------------------------------------"); LOGGER.error("----------------------------------------------------");
throw new AnalysisException("Couldn't parse Assembly Analyzer results (GrokAssembly)", saxe); throw new AnalysisException("Couldn't parse Assembly Analyzer results (GrokAssembly)", saxe);
} }
// This shouldn't happen
} }
/** /**

View File

@@ -176,7 +176,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
} }
} }
} else { } else {
engine.getDependencies().remove(dependency); engine.removeDependency(dependency);
} }
} }

View File

@@ -224,7 +224,7 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
} }
final MessageDigest sha1 = getSha1MessageDigest(); final MessageDigest sha1 = getSha1MessageDigest();
currentDep.setSha1sum(Checksum.getHex(sha1.digest(path))); currentDep.setSha1sum(Checksum.getHex(sha1.digest(path)));
engine.getDependencies().add(currentDep); engine.addDependency(currentDep);
} }
final String source = currentDep.getDisplayFileName(); final String source = currentDep.getDisplayFileName();
currentDep.getProductEvidence().addEvidence(source, "Product", currentDep.getProductEvidence().addEvidence(source, "Product",

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.lucene.analysis.util.CharArraySet; import org.apache.lucene.analysis.util.CharArraySet;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
@@ -63,6 +64,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class CPEAnalyzer extends AbstractAnalyzer { public class CPEAnalyzer extends AbstractAnalyzer {
/** /**
@@ -92,6 +94,10 @@ public class CPEAnalyzer extends AbstractAnalyzer {
* data that will be written into the string. * data that will be written into the string.
*/ */
private static final int STRING_BUILDER_BUFFER = 20; private static final int STRING_BUILDER_BUFFER = 20;
/**
* The URL to perform a search of the NVD CVE data at NIST.
*/
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
/** /**
* The CPE in memory index. * The CPE in memory index.
*/ */
@@ -101,11 +107,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
*/ */
private CveDB cve; private CveDB cve;
/**
* The URL to perform a search of the NVD CVE data at NIST.
*/
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
/** /**
* Returns the name of this analyzer. * Returns the name of this analyzer.
* *
@@ -126,18 +127,18 @@ public class CPEAnalyzer extends AbstractAnalyzer {
return AnalysisPhase.IDENTIFIER_ANALYSIS; return AnalysisPhase.IDENTIFIER_ANALYSIS;
} }
/** // /**
* The default is to support parallel processing. // * The default is to support parallel processing.
* // *
* @return false // * @return false
*/ // */
@Override // @Override
public boolean supportsParallelProcessing() { // public boolean supportsParallelProcessing() {
return false; // return false;
} // }
/** /**
* Creates the CPE Lucene Index. * Creates the CPE Lucene Index.
*
* @param engine a reference to the dependency-check engine * @param engine a reference to the dependency-check engine
* @throws InitializationException is thrown if there is an issue opening * @throws InitializationException is thrown if there is an issue opening
* the index. * the index.
@@ -164,7 +165,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
* @throws DatabaseException when the database throws an exception. This * @throws DatabaseException when the database throws an exception. This
* usually occurs when the database is in use by another process. * usually occurs when the database is in use by another process.
*/ */
public void open(CveDB cve) throws IOException, DatabaseException { public synchronized void open(CveDB cve) throws IOException, DatabaseException {
if (!isOpen()) { if (!isOpen()) {
this.cve = cve; this.cve = cve;
this.cpe = CpeMemoryIndex.getInstance(); this.cpe = CpeMemoryIndex.getInstance();
@@ -185,10 +186,6 @@ public class CPEAnalyzer extends AbstractAnalyzer {
*/ */
@Override @Override
public void closeAnalyzer() { public void closeAnalyzer() {
if (cve != null) {
cve.close();
cve = null;
}
if (cpe != null) { if (cpe != null) {
cpe.close(); cpe.close();
cpe = null; cpe = null;
@@ -490,7 +487,7 @@ public class CPEAnalyzer extends AbstractAnalyzer {
final String[] words = text.split("[\\s_-]"); final String[] words = text.split("[\\s_-]");
final List<String> list = new ArrayList<>(); final List<String> list = new ArrayList<>();
String tempWord = null; String tempWord = null;
CharArraySet stopWords = SearchFieldAnalyzer.getStopWords(); final CharArraySet stopWords = SearchFieldAnalyzer.getStopWords();
for (String word : words) { for (String word : words) {
if (stopWords.contains(word)) { if (stopWords.contains(word)) {
continue; continue;

View File

@@ -36,6 +36,7 @@ import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.Downloader;
@@ -49,6 +50,7 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class CentralAnalyzer extends AbstractFileTypeAnalyzer { public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -232,7 +234,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.debug("Unable to delete temp file"); LOGGER.debug("Unable to delete temp file");
} }
LOGGER.debug("Downloading {}", ma.getPomUrl()); LOGGER.debug("Downloading {}", ma.getPomUrl());
Downloader downloader = new Downloader(getSettings()); final Downloader downloader = new Downloader(getSettings());
downloader.fetchFile(new URL(ma.getPomUrl()), pomFile); downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
PomUtils.analyzePOM(dependency, pomFile); PomUtils.analyzePOM(dependency, pomFile);

View File

@@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
@@ -41,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
* @author Bianca Jiang (https://twitter.com/biancajiang) * @author Bianca Jiang (https://twitter.com/biancajiang)
*/ */
@Experimental @Experimental
@ThreadSafe
public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer { public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer {
/** /**

View File

@@ -117,7 +117,7 @@ public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
d.getProductEvidence().addEvidence(COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST); d.getProductEvidence().addEvidence(COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST);
d.getVersionEvidence().addEvidence(COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST); d.getVersionEvidence().addEvidence(COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST);
LOGGER.info("Adding dependency {}", d); LOGGER.info("Adding dependency {}", d);
engine.getDependencies().add(d); engine.addDependency(d);
} }
} catch (IOException ex) { } catch (IOException ex) {
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath()); LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());

View File

@@ -17,6 +17,7 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
@@ -26,6 +27,7 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer { public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
/** /**

View File

@@ -18,14 +18,11 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.File; import java.io.File;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.owasp.dependencycheck.Engine; import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.utils.DependencyVersion; import org.owasp.dependencycheck.utils.DependencyVersion;
@@ -47,37 +44,19 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
public class DependencyBundlingAnalyzer extends AbstractAnalyzer { @ThreadSafe
public class DependencyBundlingAnalyzer extends AbstractDependencyComparingAnalyzer {
/** /**
* The Logger. * The Logger.
*/ */
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class); private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class);
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/** /**
* A pattern for obtaining the first part of a filename. * A pattern for obtaining the first part of a filename.
*/ */
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*"); private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*");
/**
* a flag indicating if this analyzer has run. This analyzer only runs once.
*/
private boolean analyzed = false;
/**
* Returns a flag indicating if this analyzer has run. This analyzer only
* runs once. Note this is currently only used in the unit tests.
*
* @return a flag indicating if this analyzer has run. This analyzer only
* runs once
*/
protected synchronized boolean getAnalyzed() {
return analyzed;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/** /**
* The name of the analyzer. * The name of the analyzer.
*/ */
@@ -106,19 +85,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
public AnalysisPhase getAnalysisPhase() { public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }
//</editor-fold>
/**
* Does not support parallel processing as it only runs once and then
* operates on <em>all</em> dependencies.
*
* @return whether or not parallel processing is enabled
* @see #analyze(Dependency, Engine)
*/
@Override
public boolean supportsParallelProcessing() {
return false;
}
/** /**
* <p> * <p>
@@ -132,65 +98,46 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
} }
/** /**
* Analyzes a set of dependencies. If they have been found to have the same * Evaluates the dependencies
* base path and the same set of identifiers they are likely related. The
* related dependencies are bundled into a single reportable item.
* *
* @param ignore this analyzer ignores the dependency being analyzed * @param dependency a dependency to compare
* @param engine the engine that is scanning the dependencies * @param nextDependency a dependency to compare
* @throws AnalysisException is thrown if there is an error reading the JAR * @param dependenciesToRemove a set of dependencies that will be removed
* file. * @return true if a dependency is removed; otherwise false
*/ */
@Override @Override
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException { protected boolean evaluateDependencies(final Dependency dependency, final Dependency nextDependency, final Set<Dependency> dependenciesToRemove) {
if (!analyzed) { if (hashesMatch(dependency, nextDependency)) {
analyzed = true; if (!containedInWar(dependency.getFilePath())
final Set<Dependency> dependenciesToRemove = new HashSet<>(); && !containedInWar(nextDependency.getFilePath())) {
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator(); if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
//for (Dependency nextDependency : engine.getDependencies()) { mergeDependencies(dependency, nextDependency, dependenciesToRemove);
while (mainIterator.hasNext()) { } else {
final Dependency dependency = mainIterator.next(); mergeDependencies(nextDependency, dependency, dependenciesToRemove);
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) { return true; //since we merged into the next dependency - skip forward to the next in mainIterator
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
while (subIterator.hasNext()) {
final Dependency nextDependency = subIterator.next();
if (hashesMatch(dependency, nextDependency)) {
if (!containedInWar(dependency.getFilePath())
&& !containedInWar(nextDependency.getFilePath())) {
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
} else if (isShadedJar(dependency, nextDependency)) {
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
nextDependency.getRelatedDependencies().remove(dependency);
break;
} else {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
dependency.getRelatedDependencies().remove(nextDependency);
}
} else if (cpeIdentifiersMatch(dependency, nextDependency)
&& hasSameBasePath(dependency, nextDependency)
&& vulnCountMatches(dependency, nextDependency)
&& fileNameMatch(dependency, nextDependency)) {
if (isCore(dependency, nextDependency)) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
}
} }
} }
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions } else if (isShadedJar(dependency, nextDependency)) {
// was difficult because of the inner iterator. if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
engine.getDependencies().removeAll(dependenciesToRemove); mergeDependencies(nextDependency, dependency, dependenciesToRemove);
nextDependency.getRelatedDependencies().remove(dependency);
return true;
} else {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
dependency.getRelatedDependencies().remove(nextDependency);
}
} else if (cpeIdentifiersMatch(dependency, nextDependency)
&& hasSameBasePath(dependency, nextDependency)
&& vulnCountMatches(dependency, nextDependency)
&& fileNameMatch(dependency, nextDependency)) {
if (isCore(dependency, nextDependency)) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
return true; //since we merged into the next dependency - skip forward to the next in mainIterator
}
} }
return false;
} }
/** /**

View File

@@ -18,12 +18,8 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.File; import java.io.File;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set; import java.util.Set;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -36,31 +32,12 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
public class DependencyMergingAnalyzer extends AbstractAnalyzer { public class DependencyMergingAnalyzer extends AbstractDependencyComparingAnalyzer {
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
/** /**
* The Logger. * The Logger.
*/ */
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyMergingAnalyzer.class); private static final Logger LOGGER = LoggerFactory.getLogger(DependencyMergingAnalyzer.class);
/**
* a flag indicating if this analyzer has run. This analyzer only runs once.
*/
private boolean analyzed = false;
/**
* Returns a flag indicating if this analyzer has run. This analyzer only
* runs once. Note this is currently only used in the unit tests.
*
* @return a flag indicating if this analyzer has run. This analyzer only
* runs once
*/
protected synchronized boolean getAnalyzed() {
return analyzed;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/** /**
* The name of the analyzer. * The name of the analyzer.
*/ */
@@ -90,18 +67,6 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }
/**
* Does not support parallel processing as it only runs once and then
* operates on <em>all</em> dependencies.
*
* @return whether or not parallel processing is enabled
* @see #analyze(Dependency, Engine)
*/
@Override
public boolean supportsParallelProcessing() {
return false;
}
/** /**
* <p> * <p>
* Returns the setting key to determine if the analyzer is enabled.</p> * Returns the setting key to determine if the analyzer is enabled.</p>
@@ -112,55 +77,34 @@ public class DependencyMergingAnalyzer extends AbstractAnalyzer {
protected String getAnalyzerEnabledSettingKey() { protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_DEPENDENCY_MERGING_ENABLED; return Settings.KEYS.ANALYZER_DEPENDENCY_MERGING_ENABLED;
} }
//</editor-fold>
/** /**
* Analyzes a set of dependencies. If they have been found to be the same * Evaluates the dependencies
* dependency created by more multiple FileTypeAnalyzers (i.e. a gemspec
* dependency and a dependency from the Bundle Audit Analyzer. The
* dependencies are then merged into a single reportable item.
* *
* @param ignore this analyzer ignores the dependency being analyzed * @param dependency a dependency to compare
* @param engine the engine that is scanning the dependencies * @param nextDependency a dependency to compare
* @throws AnalysisException is thrown if there is an error reading the JAR * @param dependenciesToRemove a set of dependencies that will be removed
* file. * @return true if a dependency is removed; otherwise false
*/ */
@Override @Override
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException { protected boolean evaluateDependencies(final Dependency dependency, final Dependency nextDependency, final Set<Dependency> dependenciesToRemove) {
if (!analyzed) { Dependency main;
analyzed = true; if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
final Set<Dependency> dependenciesToRemove = new HashSet<>(); if (main == dependency) {
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator(); mergeDependencies(dependency, nextDependency, dependenciesToRemove);
//for (Dependency nextDependency : engine.getDependencies()) { } else {
while (mainIterator.hasNext()) { mergeDependencies(nextDependency, dependency, dependenciesToRemove);
final Dependency dependency = mainIterator.next(); return true; //since we merged into the next dependency - skip forward to the next in mainIterator
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) { }
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex()); } else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
while (subIterator.hasNext()) { if (main == dependency) {
final Dependency nextDependency = subIterator.next(); mergeDependencies(dependency, nextDependency, dependenciesToRemove);
Dependency main; } else {
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) { mergeDependencies(nextDependency, dependency, dependenciesToRemove);
if (main == dependency) { return true; //since we merged into the next dependency - skip forward to the next in mainIterator
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
} else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
if (main == dependency) {
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
} else {
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
break; //since we merged into the next dependency - skip forward to the next in mainIterator
}
}
}
}
} }
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
// was difficult because of the inner iterator.
engine.getDependencies().removeAll(dependenciesToRemove);
} }
return false;
} }
/** /**

View File

@@ -28,6 +28,7 @@ import java.util.ListIterator;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
@@ -44,6 +45,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class FalsePositiveAnalyzer extends AbstractAnalyzer { public class FalsePositiveAnalyzer extends AbstractAnalyzer {
/** /**
@@ -155,8 +157,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
} }
} }
} }
if (mustContain if (mustContain != null) {
!= null) {
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator(); final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
while (itr.hasNext()) { while (itr.hasNext()) {
final Identifier i = itr.next(); final Identifier i = itr.next();
@@ -444,7 +445,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
String parentPath = dependency.getFilePath().toLowerCase(); String parentPath = dependency.getFilePath().toLowerCase();
if (parentPath.contains(".jar")) { if (parentPath.contains(".jar")) {
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4); parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
final List<Dependency> dependencies = engine.getDependencies(); final Dependency[] dependencies = engine.getDependencies();
final Dependency parent = findDependency(parentPath, dependencies); final Dependency parent = findDependency(parentPath, dependencies);
if (parent != null) { if (parent != null) {
boolean remove = false; boolean remove = false;
@@ -462,7 +463,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
} }
} }
if (remove) { if (remove) {
dependencies.remove(dependency); engine.removeDependency(dependency);
} }
} }
} }
@@ -474,10 +475,10 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
* dependencies. * dependencies.
* *
* @param dependencyPath the path of the dependency to return * @param dependencyPath the path of the dependency to return
* @param dependencies the collection of dependencies to search * @param dependencies the array of dependencies to search
* @return the dependency object for the given path, otherwise null * @return the dependency object for the given path, otherwise null
*/ */
private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) { private Dependency findDependency(String dependencyPath, Dependency[] dependencies) {
for (Dependency d : dependencies) { for (Dependency d : dependencies) {
if (d.getFilePath().equalsIgnoreCase(dependencyPath)) { if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
return d; return d;

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.File; import java.io.File;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.NameFileFilter;
@@ -30,11 +31,11 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
*
* Takes a dependency and analyzes the filename and determines the hashes. * Takes a dependency and analyzes the filename and determines the hashes.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class FileNameAnalyzer extends AbstractAnalyzer { public class FileNameAnalyzer extends AbstractAnalyzer {
/** /**
@@ -76,6 +77,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer {
public AnalysisPhase getAnalysisPhase() { public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE; return ANALYSIS_PHASE;
} }
/** /**
* <p> * <p>
* Returns the setting key to determine if the analyzer is enabled.</p> * Returns the setting key to determine if the analyzer is enabled.</p>

View File

@@ -26,6 +26,8 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang.ArrayUtils;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
@@ -40,7 +42,6 @@ import org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule;
import org.owasp.dependencycheck.xml.hints.HintParseException; import org.owasp.dependencycheck.xml.hints.HintParseException;
import org.owasp.dependencycheck.xml.hints.HintParser; import org.owasp.dependencycheck.xml.hints.HintParser;
import org.owasp.dependencycheck.xml.hints.HintRule; import org.owasp.dependencycheck.xml.hints.HintRule;
import org.owasp.dependencycheck.xml.hints.Hints;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@@ -51,6 +52,7 @@ import org.xml.sax.SAXException;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class HintAnalyzer extends AbstractAnalyzer { public class HintAnalyzer extends AbstractAnalyzer {
/** /**
@@ -62,11 +64,14 @@ public class HintAnalyzer extends AbstractAnalyzer {
*/ */
private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml"; private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
/** /**
* The collection of hints. * The array of hint rules.
*/ */
private Hints hints; private HintRule[] hints = null;
/**
* The array of vendor duplicating hint rules.
*/
private VendorDuplicatingHintRule[] vendorHints;
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
/** /**
* The name of the analyzer. * The name of the analyzer.
*/ */
@@ -122,7 +127,6 @@ public class HintAnalyzer extends AbstractAnalyzer {
throw new InitializationException("Unable to parse the hint file", ex); throw new InitializationException("Unable to parse the hint file", ex);
} }
} }
//</editor-fold>
/** /**
* The HintAnalyzer uses knowledge about a dependency to add additional * The HintAnalyzer uses knowledge about a dependency to add additional
@@ -135,7 +139,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
*/ */
@Override @Override
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
for (HintRule hint : hints.getHintRules()) { for (HintRule hint : hints) {
boolean matchFound = false; boolean matchFound = false;
for (Evidence given : hint.getGivenVendor()) { for (Evidence given : hint.getGivenVendor()) {
if (dependency.getVendorEvidence().getEvidence().contains(given)) { if (dependency.getVendorEvidence().getEvidence().contains(given)) {
@@ -199,7 +203,7 @@ public class HintAnalyzer extends AbstractAnalyzer {
final List<Evidence> newEntries = new ArrayList<>(); final List<Evidence> newEntries = new ArrayList<>();
while (itr.hasNext()) { while (itr.hasNext()) {
final Evidence e = itr.next(); final Evidence e = itr.next();
for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) { for (VendorDuplicatingHintRule dhr : vendorHints) {
if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) { if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) {
newEntries.add(new Evidence(e.getSource() + " (hint)", newEntries.add(new Evidence(e.getSource() + " (hint)",
e.getName(), dhr.getDuplicate(), e.getConfidence())); e.getName(), dhr.getDuplicate(), e.getConfidence()));
@@ -217,71 +221,79 @@ public class HintAnalyzer extends AbstractAnalyzer {
* @throws HintParseException thrown if the XML cannot be parsed. * @throws HintParseException thrown if the XML cannot be parsed.
*/ */
private void loadHintRules() throws HintParseException { private void loadHintRules() throws HintParseException {
final HintParser parser = new HintParser(); if (hints == null) {
File file = null; final HintParser parser = new HintParser();
try { File file = null;
hints = parser.parseHints(FileUtils.getResourceAsStream(HINT_RULE_FILE_NAME)); try {
} catch (HintParseException | SAXException ex) { parser.parseHints(FileUtils.getResourceAsStream(HINT_RULE_FILE_NAME));
LOGGER.error("Unable to parse the base hint data file"); hints = parser.getHintRules();
LOGGER.debug("Unable to parse the base hint data file", ex); vendorHints = parser.getVendorDuplicatingHintRules();
} } catch (HintParseException | SAXException ex) {
final String filePath = getSettings().getString(Settings.KEYS.HINTS_FILE); LOGGER.error("Unable to parse the base hint data file");
if (filePath == null) { LOGGER.debug("Unable to parse the base hint data file", ex);
return; }
} final String filePath = getSettings().getString(Settings.KEYS.HINTS_FILE);
boolean deleteTempFile = false; if (filePath == null) {
try { return;
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE); }
if (uriRx.matcher(filePath).matches()) { boolean deleteTempFile = false;
deleteTempFile = true; try {
file = getSettings().getTempFile("hint", "xml"); final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
final URL url = new URL(filePath); if (uriRx.matcher(filePath).matches()) {
Downloader downloader = new Downloader(getSettings()); deleteTempFile = true;
try { file = getSettings().getTempFile("hint", "xml");
downloader.fetchFile(url, file, false); final URL url = new URL(filePath);
} catch (DownloadFailedException ex) { final Downloader downloader = new Downloader(getSettings());
downloader.fetchFile(url, file, true); try {
} downloader.fetchFile(url, file, false);
} else { } catch (DownloadFailedException ex) {
file = new File(filePath); downloader.fetchFile(url, file, true);
if (!file.exists()) { }
try (InputStream fromClasspath = FileUtils.getResourceAsStream(filePath)) { } else {
if (fromClasspath != null) { file = new File(filePath);
deleteTempFile = true; if (!file.exists()) {
file = getSettings().getTempFile("hint", "xml"); try (InputStream fromClasspath = FileUtils.getResourceAsStream(filePath)) {
try { if (fromClasspath != null) {
org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file); deleteTempFile = true;
} catch (IOException ex) { file = getSettings().getTempFile("hint", "xml");
throw new HintParseException("Unable to locate hints file in classpath", ex); try {
org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
} catch (IOException ex) {
throw new HintParseException("Unable to locate hints file in classpath", ex);
}
} }
} }
} }
} }
}
if (file != null) { if (file != null) {
try { try {
final Hints newHints = parser.parseHints(file); parser.parseHints(file);
hints.getHintRules().addAll(newHints.getHintRules()); if (parser.getHintRules() != null && parser.getHintRules().length > 0) {
hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules()); hints = (HintRule[]) ArrayUtils.addAll(hints, parser.getHintRules());
LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size()); }
LOGGER.debug("{} duplicating hint rules were loaded.", hints.getVendorDuplicatingHintRules().size()); if (parser.getVendorDuplicatingHintRules() != null && parser.getVendorDuplicatingHintRules().length > 0) {
} catch (HintParseException ex) { vendorHints = (VendorDuplicatingHintRule[]) ArrayUtils.addAll(vendorHints, parser.getVendorDuplicatingHintRules());
LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath()); }
LOGGER.warn(ex.getMessage()); LOGGER.debug("{} hint rules were loaded.", hints.length);
LOGGER.debug("", ex); LOGGER.debug("{} duplicating hint rules were loaded.", vendorHints.length);
throw ex; } catch (HintParseException ex) {
LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
LOGGER.warn(ex.getMessage());
LOGGER.debug("", ex);
throw ex;
}
}
} catch (DownloadFailedException ex) {
throw new HintParseException("Unable to fetch the configured hint file", ex);
} catch (MalformedURLException ex) {
throw new HintParseException("Configured hint file has an invalid URL", ex);
} catch (IOException ex) {
throw new HintParseException("Unable to create temp file for hints", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
} }
}
} catch (DownloadFailedException ex) {
throw new HintParseException("Unable to fetch the configured hint file", ex);
} catch (MalformedURLException ex) {
throw new HintParseException("Configured hint file has an invalid URL", ex);
} catch (IOException ex) {
throw new HintParseException("Unable to create temp file for hints", ex);
} finally {
if (deleteTempFile && file != null) {
FileUtils.delete(file);
} }
} }
} }

View File

@@ -251,7 +251,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|| fileName.endsWith("-doc.jar") || fileName.endsWith("-doc.jar")
|| isMacOSMetaDataFile(dependency, engine)) || isMacOSMetaDataFile(dependency, engine))
|| !isZipFile(dependency)) { || !isZipFile(dependency)) {
engine.getDependencies().remove(dependency); engine.removeDependency(dependency);
return; return;
} }
final boolean hasManifest = parseManifest(dependency, classNames); final boolean hasManifest = parseManifest(dependency, classNames);
@@ -289,7 +289,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
* @return whether or not the given dependencies contain a dependency with * @return whether or not the given dependencies contain a dependency with
* the given filename * the given filename
*/ */
private boolean hasDependencyWithFilename(final List<Dependency> dependencies, final String fileName) { private boolean hasDependencyWithFilename(final Dependency[] dependencies, final String fileName) {
for (final Dependency dependency : dependencies) { for (final Dependency dependency : dependencies) {
if (Paths.get(dependency.getActualFilePath()).getFileName().toString().toLowerCase() if (Paths.get(dependency.getActualFilePath()).getFileName().toString().toLowerCase()
.equals(fileName.toLowerCase())) { .equals(fileName.toLowerCase())) {
@@ -386,7 +386,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
newDependency.setFileName(displayName); newDependency.setFileName(displayName);
newDependency.setFilePath(displayPath); newDependency.setFilePath(displayPath);
setPomEvidence(newDependency, pom, null); setPomEvidence(newDependency, pom, null);
engine.getDependencies().add(newDependency); engine.addDependency(newDependency);
} catch (AnalysisException ex) { } catch (AnalysisException ex) {
LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath()); LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
LOGGER.trace("", ex); LOGGER.trace("", ex);
@@ -700,6 +700,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
value = Jsoup.parse(value).text(); value = Jsoup.parse(value).text();
} }
if (IGNORE_VALUES.contains(value)) { if (IGNORE_VALUES.contains(value)) {
//noinspection UnnecessaryContinue
continue; continue;
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) { } else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
foundSomething = true; foundSomething = true;
@@ -733,6 +734,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
foundSomething = true; foundSomething = true;
versionEvidence.addEvidence(source, key, value, Confidence.HIGH); versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
} else if (key.equalsIgnoreCase(Attributes.Name.MAIN_CLASS.toString())) { } else if (key.equalsIgnoreCase(Attributes.Name.MAIN_CLASS.toString())) {
//noinspection UnnecessaryContinue
continue; continue;
//skipping main class as if this has important information to add it will be added during class name analysis... //skipping main class as if this has important information to add it will be added during class name analysis...
} else { } else {

View File

@@ -35,6 +35,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.Downloader;
@@ -59,6 +60,7 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class NexusAnalyzer extends AbstractFileTypeAnalyzer { public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -251,7 +253,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
LOGGER.debug("Unable to delete temp file"); LOGGER.debug("Unable to delete temp file");
} }
LOGGER.debug("Downloading {}", ma.getPomUrl()); LOGGER.debug("Downloading {}", ma.getPomUrl());
Downloader downloader = new Downloader(getSettings()); final Downloader downloader = new Downloader(getSettings());
downloader.fetchFile(new URL(ma.getPomUrl()), pomFile); downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
PomUtils.analyzePOM(dependency, pomFile); PomUtils.analyzePOM(dependency, pomFile);
} catch (DownloadFailedException ex) { } catch (DownloadFailedException ex) {

View File

@@ -32,6 +32,7 @@ import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
import javax.json.Json; import javax.json.Json;
import javax.json.JsonException; import javax.json.JsonException;
import javax.json.JsonObject; import javax.json.JsonObject;
@@ -47,6 +48,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
* @author Dale Visser * @author Dale Visser
*/ */
@Experimental @Experimental
@ThreadSafe
public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer { public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer {
/** /**

View File

@@ -37,11 +37,11 @@ import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
import javax.json.Json; import javax.json.Json;
import javax.json.JsonArray; import javax.json.JsonArray;
import javax.json.JsonException; import javax.json.JsonException;
@@ -59,6 +59,7 @@ import org.owasp.dependencycheck.utils.URLConnectionFailureException;
* *
* @author Steve Springett * @author Steve Springett
*/ */
@ThreadSafe
public class NspAnalyzer extends AbstractFileTypeAnalyzer { public class NspAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -284,11 +285,11 @@ public class NspAnalyzer extends AbstractFileTypeAnalyzer {
* @param depType the dependency type * @param depType the dependency type
*/ */
private void processPackage(Dependency dependency, JsonArray jsonArray, String depType) { private void processPackage(Dependency dependency, JsonArray jsonArray, String depType) {
JsonObjectBuilder builder = Json.createObjectBuilder(); final JsonObjectBuilder builder = Json.createObjectBuilder();
for (JsonString str : jsonArray.getValuesAs(JsonString.class)) { for (JsonString str : jsonArray.getValuesAs(JsonString.class)) {
builder.add(str.toString(), ""); builder.add(str.toString(), "");
} }
JsonObject jsonObject = builder.build(); final JsonObject jsonObject = builder.build();
processPackage(dependency, jsonObject, depType); processPackage(dependency, jsonObject, depType);
} }

View File

@@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
/** /**
@@ -40,6 +41,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class NuspecAnalyzer extends AbstractFileTypeAnalyzer { public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
/** /**

View File

@@ -17,9 +17,8 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -27,9 +26,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.LoggerFactory;
/** /**
* NvdCveAnalyzer is a utility class that takes a project dependency and * NvdCveAnalyzer is a utility class that takes a project dependency and
@@ -38,36 +35,13 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class NvdCveAnalyzer extends AbstractAnalyzer { public class NvdCveAnalyzer extends AbstractAnalyzer {
/** /**
* The Logger for use throughout the class * The Logger for use throughout the class
*/ */
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class); //private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
/**
* The CVE Index.
*/
private CveDB cveDB;
/**
* Closes the data source.
*/
@Override
public void closeAnalyzer() {
cveDB.close();
cveDB = null;
}
/**
* Returns the status of the data source - is the database open.
*
* @return true or false.
*/
public boolean isOpen() {
return cveDB != null;
}
/** /**
* Analyzes a dependency and attempts to determine if there are any CPE * Analyzes a dependency and attempts to determine if there are any CPE
* identifiers for this dependency. * identifiers for this dependency.
@@ -79,6 +53,7 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
*/ */
@Override @Override
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
final CveDB cveDB = engine.getDatabase();
for (Identifier id : dependency.getIdentifiers()) { for (Identifier id : dependency.getIdentifiers()) {
if ("cpe".equals(id.getType())) { if ("cpe".equals(id.getType())) {
try { try {
@@ -133,16 +108,4 @@ public class NvdCveAnalyzer extends AbstractAnalyzer {
protected String getAnalyzerEnabledSettingKey() { protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_NVD_CVE_ENABLED; return Settings.KEYS.ANALYZER_NVD_CVE_ENABLED;
} }
/**
* Opens the database used to gather NVD CVE data.
*
* @param engine a reference the dependency-check engine
* @throws InitializationException is thrown if there is an issue opening
* the index.
*/
@Override
public void initializeAnalyzer(Engine engine) throws InitializationException {
this.cveDB = engine.getDatabase();
}
} }

View File

@@ -31,6 +31,7 @@ import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
/** /**
@@ -38,6 +39,7 @@ import org.owasp.dependencycheck.exception.InitializationException;
* *
* @author Dale Visser * @author Dale Visser
*/ */
@ThreadSafe
public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer { public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -143,6 +145,16 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
return OPENSSLV_FILTER; return OPENSSLV_FILTER;
} }
/**
* Returns the setting for the analyzer enabled setting key.
*
* @return the setting for the analyzer enabled setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
}
/** /**
* No-op initializer implementation. * No-op initializer implementation.
* *
@@ -182,7 +194,7 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
dependency.getVendorEvidence().addEvidence(OPENSSLV_H, "Vendor", "OpenSSL", Confidence.HIGHEST); dependency.getVendorEvidence().addEvidence(OPENSSLV_H, "Vendor", "OpenSSL", Confidence.HIGHEST);
dependency.getProductEvidence().addEvidence(OPENSSLV_H, "Product", "OpenSSL", Confidence.HIGHEST); dependency.getProductEvidence().addEvidence(OPENSSLV_H, "Product", "OpenSSL", Confidence.HIGHEST);
} else { } else {
engine.getDependencies().remove(dependency); engine.removeDependency(dependency);
} }
} }
@@ -202,14 +214,4 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
"Problem occurred while reading dependency file.", e); "Problem occurred while reading dependency file.", e);
} }
} }
/**
* Returns the setting for the analyzer enabled setting key.
*
* @return the setting for the analyzer enabled setting key
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
}
} }

View File

@@ -46,6 +46,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.UrlStringUtils; import org.owasp.dependencycheck.utils.UrlStringUtils;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Used to analyze a Wheel or egg distribution files, or their contents in * Used to analyze a Wheel or egg distribution files, or their contents in
@@ -55,30 +56,26 @@ import java.util.concurrent.atomic.AtomicInteger;
* @author Dale Visser * @author Dale Visser
*/ */
@Experimental @Experimental
@ThreadSafe
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
* Name of egg metadata files to analyze. * Name of egg metadata files to analyze.
*/ */
private static final String PKG_INFO = "PKG-INFO"; private static final String PKG_INFO = "PKG-INFO";
/** /**
* Name of wheel metadata files to analyze. * Name of wheel metadata files to analyze.
*/ */
private static final String METADATA = "METADATA"; private static final String METADATA = "METADATA";
/** /**
* The logger. * The logger.
*/ */
private static final Logger LOGGER = LoggerFactory private static final Logger LOGGER = LoggerFactory.getLogger(PythonDistributionAnalyzer.class);
.getLogger(PythonDistributionAnalyzer.class);
/** /**
* The count of directories created during analysis. This is used for * The count of directories created during analysis. This is used for
* creating temporary directories. * creating temporary directories.
*/ */
private static final AtomicInteger DIR_COUNT = new AtomicInteger(0); private static final AtomicInteger DIR_COUNT = new AtomicInteger(0);
/** /**
* The name of the analyzer. * The name of the analyzer.
*/ */
@@ -87,52 +84,39 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
* The phase that this analyzer is intended to run in. * The phase that this analyzer is intended to run in.
*/ */
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
/** /**
* The set of file extensions supported by this analyzer. * The set of file extensions supported by this analyzer.
*/ */
private static final String[] EXTENSIONS = {"whl", "egg", "zip"}; private static final String[] EXTENSIONS = {"whl", "egg", "zip"};
/** /**
* Used to match on egg archive candidate extensions. * Used to match on egg archive candidate extensions.
*/ */
private static final FileFilter EGG_OR_ZIP = FileFilterBuilder.newInstance().addExtensions("egg", "zip").build(); private static final FileFilter EGG_OR_ZIP = FileFilterBuilder.newInstance().addExtensions("egg", "zip").build();
/** /**
* Used to detect files with a .whl extension. * Used to detect files with a .whl extension.
*/ */
private static final FileFilter WHL_FILTER = FileFilterBuilder.newInstance().addExtensions("whl").build(); private static final FileFilter WHL_FILTER = FileFilterBuilder.newInstance().addExtensions("whl").build();
/** /**
* The parent directory for the individual directories per archive. * The parent directory for the individual directories per archive.
*/ */
private File tempFileLocation; private File tempFileLocation;
/** /**
* Filter that detects *.dist-info files (but doesn't verify they are * Filter that detects *.dist-info files (but doesn't verify they are
* directories. * directories.
*/ */
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter( private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(".dist-info");
".dist-info");
/** /**
* Filter that detects files named "METADATA". * Filter that detects files named "METADATA".
*/ */
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter( private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter("EGG-INFO");
"EGG-INFO");
/** /**
* Filter that detects files named "METADATA". * Filter that detects files named "METADATA".
*/ */
private static final NameFileFilter METADATA_FILTER = new NameFileFilter( private static final NameFileFilter METADATA_FILTER = new NameFileFilter(METADATA);
METADATA);
/** /**
* Filter that detects files named "PKG-INFO". * Filter that detects files named "PKG-INFO".
*/ */
private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter( private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter(PKG_INFO);
PKG_INFO);
/** /**
* The file filter used to determine which files this analyzer supports. * The file filter used to determine which files this analyzer supports.
*/ */
@@ -311,8 +295,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW); addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW);
final String summary = headers.getHeader("Summary", null); final String summary = headers.getHeader("Summary", null);
if (StringUtils.isNotBlank(summary)) { if (StringUtils.isNotBlank(summary)) {
JarAnalyzer JarAnalyzer.addDescription(dependency, summary, METADATA, "summary");
.addDescription(dependency, summary, METADATA, "summary");
} }
} }

View File

@@ -35,6 +35,7 @@ import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.exception.InitializationException;
/** /**
@@ -44,13 +45,13 @@ import org.owasp.dependencycheck.exception.InitializationException;
* @author Dale Visser * @author Dale Visser
*/ */
@Experimental @Experimental
@ThreadSafe
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer { public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
* Used when compiling file scanning regex patterns. * Used when compiling file scanning regex patterns.
*/ */
private static final int REGEX_OPTIONS = Pattern.DOTALL private static final int REGEX_OPTIONS = Pattern.DOTALL | Pattern.CASE_INSENSITIVE;
| Pattern.CASE_INSENSITIVE;
/** /**
* Filename extensions for files to be analyzed. * Filename extensions for files to be analyzed.
@@ -58,16 +59,14 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
private static final String EXTENSIONS = "py"; private static final String EXTENSIONS = "py";
/** /**
* Pattern for matching the module docstring in a source file. * Pattern for matching the module doc string in a source file.
*/ */
private static final Pattern MODULE_DOCSTRING = Pattern.compile( private static final Pattern MODULE_DOCSTRING = Pattern.compile("^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
"^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
/** /**
* Matches assignments to version variables in Python source code. * Matches assignments to version variables in Python source code.
*/ */
private static final Pattern VERSION_PATTERN = Pattern.compile( private static final Pattern VERSION_PATTERN = Pattern.compile("\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
"\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
REGEX_OPTIONS); REGEX_OPTIONS);
/** /**
@@ -130,6 +129,16 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
return AnalysisPhase.INFORMATION_COLLECTION; return AnalysisPhase.INFORMATION_COLLECTION;
} }
/**
* Returns the key name for the analyzers enabled setting.
*
* @return the key name for the analyzers enabled setting
*/
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
}
/** /**
* Returns the FileFilter * Returns the FileFilter
* *
@@ -192,7 +201,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
} }
} }
} else { } else {
engine.getDependencies().remove(dependency); engine.removeDependency(dependency);
} }
} }
@@ -212,8 +221,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
try { try {
contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim(); contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim();
} catch (IOException e) { } catch (IOException e) {
throw new AnalysisException( throw new AnalysisException("Problem occurred while reading dependency file.", e);
"Problem occurred while reading dependency file.", e);
} }
boolean found = false; boolean found = false;
if (!contents.isEmpty()) { if (!contents.isEmpty()) {
@@ -311,9 +319,4 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
} }
return found; return found;
} }
@Override
protected String getAnalyzerEnabledSettingKey() {
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
}
} }

View File

@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
@@ -50,6 +51,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Dale Visser * @author Dale Visser
*/ */
@ThreadSafe
public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -482,7 +484,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
dependency.setDisplayFileName(displayFileName); dependency.setDisplayFileName(displayFileName);
dependency.setFileName(fileName); dependency.setFileName(fileName);
dependency.setFilePath(filePath); dependency.setFilePath(filePath);
engine.getDependencies().add(dependency); engine.addDependency(dependency);
return dependency; return dependency;
} }
} }

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.analyzer;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
@@ -47,6 +48,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
* @author Bianca Jiang (https://twitter.com/biancajiang) * @author Bianca Jiang (https://twitter.com/biancajiang)
*/ */
@Experimental @Experimental
@ThreadSafe
public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer { public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
/** /**

View File

@@ -25,6 +25,7 @@ import java.nio.charset.Charset;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
@@ -46,6 +47,7 @@ import org.slf4j.LoggerFactory;
* @author Dale Visser * @author Dale Visser
*/ */
@Experimental @Experimental
@ThreadSafe
public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer { public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
/** /**
@@ -130,8 +132,7 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
private static final Pattern GEMSPEC_BLOCK_INIT = Pattern.compile("Gem::Specification\\.new\\s+?do\\s+?\\|(.+?)\\|"); private static final Pattern GEMSPEC_BLOCK_INIT = Pattern.compile("Gem::Specification\\.new\\s+?do\\s+?\\|(.+?)\\|");
@Override @Override
protected void analyzeDependency(Dependency dependency, Engine engine) protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
throws AnalysisException {
String contents; String contents;
try { try {
contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset()); contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset());

View File

@@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
@@ -41,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
* @author Bianca Jiang (https://twitter.com/biancajiang) * @author Bianca Jiang (https://twitter.com/biancajiang)
*/ */
@Experimental @Experimental
@ThreadSafe
public class SwiftPackageManagerAnalyzer extends AbstractFileTypeAnalyzer { public class SwiftPackageManagerAnalyzer extends AbstractFileTypeAnalyzer {
/** /**

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.analyzer;
import java.util.Iterator; import java.util.Iterator;
import java.util.Objects; import java.util.Objects;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
@@ -37,8 +38,14 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class VersionFilterAnalyzer extends AbstractAnalyzer { public class VersionFilterAnalyzer extends AbstractAnalyzer {
/**
* The Logger for use throughout the class
*/
private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class);
//<editor-fold defaultstate="collapsed" desc="Constants"> //<editor-fold defaultstate="collapsed" desc="Constants">
/** /**
* Evidence source. * Evidence source.
@@ -111,11 +118,6 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
} }
//</editor-fold> //</editor-fold>
/**
* The Logger for use throughout the class
*/
private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class);
/** /**
* The HintAnalyzer uses knowledge about a dependency to add additional * The HintAnalyzer uses knowledge about a dependency to add additional
* information to help in identification of identifiers or vulnerabilities. * information to help in identification of identifiers or vulnerabilities.
@@ -126,7 +128,7 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer {
* the dependency. * the dependency.
*/ */
@Override @Override
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
String fileVersion = null; String fileVersion = null;
String pomVersion = null; String pomVersion = null;
String manifestVersion = null; String manifestVersion = null;

View File

@@ -17,6 +17,7 @@
*/ */
package org.owasp.dependencycheck.analyzer; package org.owasp.dependencycheck.analyzer;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
@@ -26,6 +27,7 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer { public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
/** /**

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.analyzer.exception; package org.owasp.dependencycheck.analyzer.exception;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception thrown when the analysis of a dependency fails. * An exception thrown when the analysis of a dependency fails.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class AnalysisException extends Exception { public class AnalysisException extends Exception {
/** /**

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.analyzer.exception; package org.owasp.dependencycheck.analyzer.exception;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception thrown when files in an archive cannot be extracted. * An exception thrown when files in an archive cannot be extracted.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class ArchiveExtractionException extends Exception { public class ArchiveExtractionException extends Exception {
/** /**

View File

@@ -21,9 +21,11 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath; import javax.xml.xpath.XPath;
@@ -45,12 +47,13 @@ import org.xml.sax.SAXException;
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class CentralSearch { public class CentralSearch {
/** /**
* The URL for the Central service * The URL for the Central service
*/ */
private final URL rootURL; private final String rootURL;
/** /**
* Whether to use the Proxy when making requests * Whether to use the Proxy when making requests
@@ -70,7 +73,7 @@ public class CentralSearch {
* Creates a NexusSearch for the given repository URL. * Creates a NexusSearch for the given repository URL.
* *
* @param settings the configured settings * @param settings the configured settings
* @throws java.net.MalformedURLException thrown if the configured URL is * @throws MalformedURLException thrown if the configured URL is
* invalid * invalid
*/ */
public CentralSearch(Settings settings) throws MalformedURLException { public CentralSearch(Settings settings) throws MalformedURLException {
@@ -78,7 +81,10 @@ public class CentralSearch {
final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL); final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
LOGGER.debug("Central Search URL: {}", searchUrl); LOGGER.debug("Central Search URL: {}", searchUrl);
this.rootURL = new URL(searchUrl); if (isInvalidURL(searchUrl)) {
throw new MalformedURLException(String.format("The configured central analyzer URL is invalid: %s", searchUrl));
}
this.rootURL = searchUrl;
if (null != settings.getString(Settings.KEYS.PROXY_SERVER)) { if (null != settings.getString(Settings.KEYS.PROXY_SERVER)) {
useProxy = true; useProxy = true;
LOGGER.debug("Using proxy"); LOGGER.debug("Using proxy");
@@ -103,7 +109,7 @@ public class CentralSearch {
throw new IllegalArgumentException("Invalid SHA1 format"); throw new IllegalArgumentException("Invalid SHA1 format");
} }
List<MavenArtifact> result = null; List<MavenArtifact> result = null;
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1)); final URL url = new URL(String.format("%s?q=1:\"%s\"&wt=xml", rootURL, sha1));
LOGGER.debug("Searching Central url {}", url); LOGGER.debug("Searching Central url {}", url);
@@ -178,4 +184,21 @@ public class CentralSearch {
} }
return result; return result;
} }
/**
* Tests to determine if the gien URL is <b>invalid</b>.
*
* @param url the url to evaluate
* @return true if the url is malformed; otherwise false
*/
private boolean isInvalidURL(String url) {
try {
final URL u = new URL(url);
u.toURI();
} catch (MalformedURLException | URISyntaxException e) {
LOGGER.trace("URL is invalid: {}", url);
return true;
}
return false;
}
} }

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.composer; package org.owasp.dependencycheck.data.composer;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Represents a dependency (GAV, right now) from a Composer dependency. * Represents a dependency (GAV, right now) from a Composer dependency.
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public final class ComposerDependency { public final class ComposerDependency {
/** /**

View File

@@ -17,11 +17,15 @@
*/ */
package org.owasp.dependencycheck.data.composer; package org.owasp.dependencycheck.data.composer;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Represents an exception when handling a composer.json or composer.lock file. Generally used to wrap a downstream exception. * Represents an exception when handling a composer.json or composer.lock file.
* Generally used to wrap a downstream exception.
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class ComposerException extends RuntimeException { public class ComposerException extends RuntimeException {
/** /**

View File

@@ -29,12 +29,14 @@ import javax.json.stream.JsonParsingException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/** /**
* Parses a Composer.lock file from an input stream. In a separate class so it can hopefully be injected. * Parses a Composer.lock file from an input stream. In a separate class so it can hopefully be injected.
* *
* @author colezlaw * @author colezlaw
*/ */
@NotThreadSafe
public class ComposerLockParser { public class ComposerLockParser {
/** /**

View File

@@ -21,6 +21,8 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.KeywordAnalyzer; import org.apache.lucene.analysis.core.KeywordAnalyzer;
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper; import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
@@ -47,21 +49,29 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* <p>
* An in memory Lucene index that contains the vendor/product combinations from * An in memory Lucene index that contains the vendor/product combinations from
* the CPE (application) identifiers within the NVD CVE data. * the CPE (application) identifiers within the NVD CVE data.</p>
*
* This is the last remaining singleton in dependency-check-core; The use of
* this singleton - while it may not technically be thread-safe (one database
* used to build this index may not have the same entries as another) the risk
* of this is currently believed to be small. As this memory index consumes a
* large amount of memory we will remain using the singleton pattern for now.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public final class CpeMemoryIndex implements AutoCloseable { public final class CpeMemoryIndex implements AutoCloseable {
/**
* Singleton instance.
*/
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
/** /**
* The logger. * The logger.
*/ */
private static final Logger LOGGER = LoggerFactory.getLogger(CpeMemoryIndex.class); private static final Logger LOGGER = LoggerFactory.getLogger(CpeMemoryIndex.class);
/**
* singleton instance.
*/
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
/** /**
* The in memory Lucene index. * The in memory Lucene index.
*/ */
@@ -82,19 +92,11 @@ public final class CpeMemoryIndex implements AutoCloseable {
* The Lucene QueryParser used for Searching. * The Lucene QueryParser used for Searching.
*/ */
private QueryParser queryParser; private QueryParser queryParser;
/**
* The search field analyzer for the product field.
*/
private SearchFieldAnalyzer productFieldAnalyzer;
/**
* The search field analyzer for the vendor field.
*/
private SearchFieldAnalyzer vendorFieldAnalyzer;
/** /**
* Track the number of current users of the Lucene index; used to track it * Track the number of current users of the Lucene index; used to track it
* it is okay to actually close the index. * it is okay to actually close the index.
*/ */
private int usageCount = 0; private final AtomicInteger usageCount = new AtomicInteger(0);
/** /**
* private constructor for singleton. * private constructor for singleton.
@@ -118,8 +120,7 @@ public final class CpeMemoryIndex implements AutoCloseable {
* @throws IndexException thrown if there is an error creating the index * @throws IndexException thrown if there is an error creating the index
*/ */
public synchronized void open(CveDB cve) throws IndexException { public synchronized void open(CveDB cve) throws IndexException {
if (INSTANCE.usageCount <= 0) { if (INSTANCE.usageCount.addAndGet(1) == 1) {
INSTANCE.usageCount = 0;
index = new RAMDirectory(); index = new RAMDirectory();
buildIndex(cve); buildIndex(cve);
try { try {
@@ -131,7 +132,6 @@ public final class CpeMemoryIndex implements AutoCloseable {
searchingAnalyzer = createSearchingAnalyzer(); searchingAnalyzer = createSearchingAnalyzer();
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer); queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
} }
INSTANCE.usageCount += 1;
} }
/** /**
@@ -140,7 +140,7 @@ public final class CpeMemoryIndex implements AutoCloseable {
* @return whether or not the index is open * @return whether or not the index is open
*/ */
public synchronized boolean isOpen() { public synchronized boolean isOpen() {
return INSTANCE.usageCount > 0; return INSTANCE.usageCount.get() > 0;
} }
/** /**
@@ -151,8 +151,8 @@ public final class CpeMemoryIndex implements AutoCloseable {
private Analyzer createSearchingAnalyzer() { private Analyzer createSearchingAnalyzer() {
final Map<String, Analyzer> fieldAnalyzers = new HashMap<>(); final Map<String, Analyzer> fieldAnalyzers = new HashMap<>();
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer()); fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION); SearchFieldAnalyzer productFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
vendorFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION); SearchFieldAnalyzer vendorFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
fieldAnalyzers.put(Fields.PRODUCT, productFieldAnalyzer); fieldAnalyzers.put(Fields.PRODUCT, productFieldAnalyzer);
fieldAnalyzers.put(Fields.VENDOR, vendorFieldAnalyzer); fieldAnalyzers.put(Fields.VENDOR, vendorFieldAnalyzer);
@@ -164,8 +164,9 @@ public final class CpeMemoryIndex implements AutoCloseable {
*/ */
@Override @Override
public synchronized void close() { public synchronized void close() {
INSTANCE.usageCount -= 1; final int count = INSTANCE.usageCount.get() - 1;
if (INSTANCE.usageCount <= 0) { if (count <= 0) {
INSTANCE.usageCount.set(0);
if (searchingAnalyzer != null) { if (searchingAnalyzer != null) {
searchingAnalyzer.close(); searchingAnalyzer.close();
searchingAnalyzer = null; searchingAnalyzer = null;
@@ -218,8 +219,6 @@ public final class CpeMemoryIndex implements AutoCloseable {
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
LOGGER.debug("", ex); LOGGER.debug("", ex);
throw new IndexException("Error reading CPE data", ex); throw new IndexException("Error reading CPE data", ex);
} catch (CorruptIndexException ex) {
throw new IndexException("Unable to close an in-memory index", ex);
} catch (IOException ex) { } catch (IOException ex) {
throw new IndexException("Unable to close an in-memory index", ex); throw new IndexException("Unable to close an in-memory index", ex);
} }

View File

@@ -17,11 +17,15 @@
*/ */
package org.owasp.dependencycheck.data.cpe; package org.owasp.dependencycheck.data.cpe;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Fields is a collection of field names used within the Lucene index for CPE entries. * Fields is a collection of field names used within the Lucene index for CPE
* entries.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public final class Fields { public final class Fields {
/** /**
@@ -38,7 +42,8 @@ public final class Fields {
public static final String PRODUCT = "product"; public static final String PRODUCT = "product";
/** /**
* Private constructor as this is more of an enumeration rather then a full class. * Private constructor as this is more of an enumeration rather then a full
* class.
*/ */
private Fields() { private Fields() {
} }

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.cpe;
import java.io.Serializable; import java.io.Serializable;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
/** /**
@@ -27,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class IndexEntry implements Serializable { public class IndexEntry implements Serializable {
/** /**

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.cpe; package org.owasp.dependencycheck.data.cpe;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception thrown when the there is an issue using the in-memory CPE Index. * An exception thrown when the there is an issue using the in-memory CPE Index.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class IndexException extends Exception { public class IndexException extends Exception {
/** /**

View File

@@ -26,11 +26,13 @@ import java.io.InputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public final class CweDB { public final class CweDB {
/** /**
@@ -59,9 +61,7 @@ public final class CweDB {
final String filePath = "data/cwe.hashmap.serialized"; final String filePath = "data/cwe.hashmap.serialized";
try (InputStream input = FileUtils.getResourceAsStream(filePath); try (InputStream input = FileUtils.getResourceAsStream(filePath);
ObjectInputStream oin = new ObjectInputStream(input)) { ObjectInputStream oin = new ObjectInputStream(input)) {
return (HashMap<String, String>) oin.readObject();
final Map<String, String> ret = (HashMap<String, String>) oin.readObject();
return ret;
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
LOGGER.warn("Unable to load CWE data. This should not be an issue."); LOGGER.warn("Unable to load CWE data. This should not be an issue.");
LOGGER.debug("", ex); LOGGER.debug("", ex);
@@ -79,7 +79,7 @@ public final class CweDB {
* @param cweId the CWE ID * @param cweId the CWE ID
* @return the full name of the CWE * @return the full name of the CWE
*/ */
public static String getCweName(String cweId) { public static synchronized String getCweName(String cweId) {
if (cweId != null) { if (cweId != null) {
return CWE.get(cweId); return CWE.get(cweId);
} }

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.data.cwe; package org.owasp.dependencycheck.data.cwe;
import java.util.HashMap; import java.util.HashMap;
import javax.annotation.concurrent.NotThreadSafe;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
@@ -27,6 +28,7 @@ import org.xml.sax.helpers.DefaultHandler;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class CweHandler extends DefaultHandler { public class CweHandler extends DefaultHandler {
/** /**

View File

@@ -18,15 +18,18 @@
package org.owasp.dependencycheck.data.lucene; package org.owasp.dependencycheck.data.lucene;
import java.util.LinkedList; import java.util.LinkedList;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.TokenFilter; import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
/** /**
* An abstract tokenizing filter that can be used as the base for a tokenizing filter. * An abstract tokenizing filter that can be used as the base for a tokenizing
* filter.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public abstract class AbstractTokenizingFilter extends TokenFilter { public abstract class AbstractTokenizingFilter extends TokenFilter {
/** /**

View File

@@ -18,14 +18,17 @@
package org.owasp.dependencycheck.data.lucene; package org.owasp.dependencycheck.data.lucene;
import java.io.Reader; import java.io.Reader;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.util.CharTokenizer; import org.apache.lucene.analysis.util.CharTokenizer;
import org.apache.lucene.util.Version; import org.apache.lucene.util.Version;
/** /**
* Tokenizes the input breaking it into tokens when non-alpha/numeric characters are found. * Tokenizes the input breaking it into tokens when non-alpha/numeric characters
* are found.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class AlphaNumericTokenizer extends CharTokenizer { public class AlphaNumericTokenizer extends CharTokenizer {
/** /**

View File

@@ -17,12 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.lucene; package org.owasp.dependencycheck.data.lucene;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.search.similarities.DefaultSimilarity; import org.apache.lucene.search.similarities.DefaultSimilarity;
/** /**
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class DependencySimilarity extends DefaultSimilarity { public class DependencySimilarity extends DefaultSimilarity {
/** /**

View File

@@ -18,19 +18,22 @@
package org.owasp.dependencycheck.data.lucene; package org.owasp.dependencycheck.data.lucene;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.lucene.util.Version; import org.apache.lucene.util.Version;
/** /**
* <p> * <p>
* Lucene utils is a set of utilize written to make constructing Lucene queries simpler.</p> * Lucene utils is a set of utilize written to make constructing Lucene queries
* simpler.</p>
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public final class LuceneUtils { public final class LuceneUtils {
/** /**
* The current version of Lucene being used. Declaring this one place so an upgrade doesn't require hunting through the code * The current version of Lucene being used. Declaring this one place so an
* base. * upgrade doesn't require hunting through the code base.
*/ */
public static final Version CURRENT_VERSION = Version.LUCENE_47; public static final Version CURRENT_VERSION = Version.LUCENE_47;
@@ -41,7 +44,8 @@ public final class LuceneUtils {
} }
/** /**
* Appends the text to the supplied StringBuilder escaping Lucene control characters in the process. * Appends the text to the supplied StringBuilder escaping Lucene control
* characters in the process.
* *
* @param buf a StringBuilder to append the escaped text to * @param buf a StringBuilder to append the escaped text to
* @param text the data to be escaped * @param text the data to be escaped
@@ -88,7 +92,8 @@ public final class LuceneUtils {
} }
/** /**
* Escapes the text passed in so that it is treated as data instead of control characters. * Escapes the text passed in so that it is treated as data instead of
* control characters.
* *
* @param text data to be escaped * @param text data to be escaped
* @return the escaped text. * @return the escaped text.

View File

@@ -18,8 +18,6 @@
package org.owasp.dependencycheck.data.lucene; package org.owasp.dependencycheck.data.lucene;
import java.io.Reader; import java.io.Reader;
import java.util.Arrays;
import java.util.List;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.Tokenizer;
@@ -44,8 +42,8 @@ public class SearchFieldAnalyzer extends Analyzer {
/** /**
* The list of additional stop words to use. * The list of additional stop words to use.
*/ */
private static final List<String> ADDITIONAL_STOP_WORDS = Arrays.asList("software", "framework", "inc", private static final String[] ADDITIONAL_STOP_WORDS = {"software", "framework", "inc",
"com", "org", "net", "www", "consulting", "ltd", "foundation", "project"); "com", "org", "net", "www", "consulting", "ltd", "foundation", "project"};
/** /**
* The set of stop words to use in the analyzer. * The set of stop words to use in the analyzer.
*/ */
@@ -57,8 +55,8 @@ public class SearchFieldAnalyzer extends Analyzer {
* @return the set of stop words being used * @return the set of stop words being used
*/ */
public static CharArraySet getStopWords() { public static CharArraySet getStopWords() {
CharArraySet words = new CharArraySet(LuceneUtils.CURRENT_VERSION, StopAnalyzer.ENGLISH_STOP_WORDS_SET, true); final CharArraySet words = StopFilter.makeStopSet(LuceneUtils.CURRENT_VERSION, ADDITIONAL_STOP_WORDS, true);
words.addAll(ADDITIONAL_STOP_WORDS); words.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
return words; return words;
} }

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.lucene;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.TokenFilter; import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
@@ -33,6 +34,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public final class TokenPairConcatenatingFilter extends TokenFilter { public final class TokenPairConcatenatingFilter extends TokenFilter {
/** /**

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.owasp.dependencycheck.utils.UrlStringUtils; import org.owasp.dependencycheck.utils.UrlStringUtils;
@@ -28,13 +29,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* <p> *
* Takes a TokenStream and splits or adds tokens to correctly index version numbers.</p> * Takes a TokenStream, looks for URLs, and breaks them into separate tokens.
* <p>
* <b>Example:</b> "3.0.0.RELEASE" -&gt; "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public final class UrlTokenizingFilter extends AbstractTokenizingFilter { public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
/** /**
@@ -52,8 +52,9 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
} }
/** /**
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by concatenating * Increments the underlying TokenStream and sets CharTermAttributes to
* tokens with the previous token. * construct an expanded set of tokens by concatenating tokens with the
* previous token.
* *
* @return whether or not we have hit the end of the TokenStream * @return whether or not we have hit the end of the TokenStream
* @throws IOException is thrown when an IOException occurs * @throws IOException is thrown when an IOException occurs

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.nexus; package org.owasp.dependencycheck.data.nexus;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Simple bean representing a Maven Artifact. * Simple bean representing a Maven Artifact.
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class MavenArtifact { public class MavenArtifact {
/** /**
@@ -45,7 +48,8 @@ public class MavenArtifact {
private String version; private String version;
/** /**
* The artifact url. This may change depending on which Nexus server the search took place. * The artifact url. This may change depending on which Nexus server the
* search took place.
*/ */
private String artifactUrl; private String artifactUrl;
/** /**
@@ -80,7 +84,8 @@ public class MavenArtifact {
* @param version the version * @param version the version
* @param jarAvailable if the jar file is available from central * @param jarAvailable if the jar file is available from central
* @param pomAvailable if the pom file is available from central * @param pomAvailable if the pom file is available from central
* @param secureDownload if the jar and pom files should be downloaded using HTTPS. * @param secureDownload if the jar and pom files should be downloaded using
* HTTPS.
*/ */
public MavenArtifact(String groupId, String artifactId, String version, boolean jarAvailable, boolean pomAvailable, boolean secureDownload) { public MavenArtifact(String groupId, String artifactId, String version, boolean jarAvailable, boolean pomAvailable, boolean secureDownload) {
this.groupId = groupId; this.groupId = groupId;
@@ -220,5 +225,3 @@ public class MavenArtifact {
} }
} }
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath; import javax.xml.xpath.XPath;
@@ -41,6 +42,7 @@ import org.xml.sax.SAXException;
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class NexusSearch { public class NexusSearch {
/** /**
@@ -66,7 +68,8 @@ public class NexusSearch {
* *
* @param settings the configured settings * @param settings the configured settings
* @param useProxy flag indicating if the proxy settings should be used * @param useProxy flag indicating if the proxy settings should be used
* @throws java.net.MalformedURLException thrown if the configured URL is invalid * @throws java.net.MalformedURLException thrown if the configured URL is
* invalid
*/ */
public NexusSearch(Settings settings, boolean useProxy) throws MalformedURLException { public NexusSearch(Settings settings, boolean useProxy) throws MalformedURLException {
this.settings = settings; this.settings = settings;
@@ -103,7 +106,7 @@ public class NexusSearch {
// 2) Otherwise, don't use the proxy (either the proxy isn't configured, // 2) Otherwise, don't use the proxy (either the proxy isn't configured,
// or proxy is specifically set to false // or proxy is specifically set to false
HttpURLConnection conn; HttpURLConnection conn;
URLConnectionFactory factory = new URLConnectionFactory(settings); final URLConnectionFactory factory = new URLConnectionFactory(settings);
conn = factory.createHttpURLConnection(url, useProxy); conn = factory.createHttpURLConnection(url, useProxy);
conn.setDoOutput(true); conn.setDoOutput(true);
@@ -169,7 +172,7 @@ public class NexusSearch {
HttpURLConnection conn; HttpURLConnection conn;
try { try {
final URL url = new URL(rootURL, "status"); final URL url = new URL(rootURL, "status");
URLConnectionFactory factory = new URLConnectionFactory(settings); final URLConnectionFactory factory = new URLConnectionFactory(settings);
conn = factory.createHttpURLConnection(url, useProxy); conn = factory.createHttpURLConnection(url, useProxy);
conn.addRequestProperty("Accept", "application/xml"); conn.addRequestProperty("Accept", "application/xml");
conn.connect(); conn.connect();
@@ -187,9 +190,6 @@ public class NexusSearch {
} catch (IOException | ParserConfigurationException | SAXException e) { } catch (IOException | ParserConfigurationException | SAXException e) {
return false; return false;
} }
return true; return true;
} }
} }
// vim: cc=120:sw=4:ts=4:sts=4

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.data.nsp; package org.owasp.dependencycheck.data.nsp;
import java.util.Arrays; import java.util.Arrays;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* The response from NSP check API will respond with 0 or more advisories. This * The response from NSP check API will respond with 0 or more advisories. This
@@ -25,6 +26,7 @@ import java.util.Arrays;
* *
* @author Steve Springett * @author Steve Springett
*/ */
@ThreadSafe
public class Advisory { public class Advisory {
/** /**

View File

@@ -28,6 +28,7 @@ import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.URLConnectionFactory; import org.owasp.dependencycheck.utils.URLConnectionFactory;
@@ -45,6 +46,7 @@ import org.owasp.dependencycheck.utils.URLConnectionFailureException;
* *
* @author Steve Springett * @author Steve Springett
*/ */
@ThreadSafe
public class NspSearch { public class NspSearch {
/** /**

View File

@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Class used to create a Sanitized version of package.json suitable for * Class used to create a Sanitized version of package.json suitable for
@@ -32,6 +33,7 @@ import java.util.Map;
* *
* @author Steve Springett * @author Steve Springett
*/ */
@ThreadSafe
public final class SanitizePackage { public final class SanitizePackage {
/** /**

View File

@@ -17,12 +17,16 @@
*/ */
package org.owasp.dependencycheck.data.nuget; package org.owasp.dependencycheck.data.nuget;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Represents the contents of a Nuspec manifest. * Represents the contents of a Nuspec manifest.
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class NugetPackage { public class NugetPackage {
/** /**
* The id. * The id.
*/ */
@@ -55,6 +59,7 @@ public class NugetPackage {
/** /**
* Sets the id. * Sets the id.
*
* @param id the id * @param id the id
*/ */
public void setId(String id) { public void setId(String id) {
@@ -63,6 +68,7 @@ public class NugetPackage {
/** /**
* Gets the id. * Gets the id.
*
* @return the id * @return the id
*/ */
public String getId() { public String getId() {
@@ -71,6 +77,7 @@ public class NugetPackage {
/** /**
* Sets the version. * Sets the version.
*
* @param version the version * @param version the version
*/ */
public void setVersion(String version) { public void setVersion(String version) {
@@ -79,6 +86,7 @@ public class NugetPackage {
/** /**
* Gets the version. * Gets the version.
*
* @return the version * @return the version
*/ */
public String getVersion() { public String getVersion() {
@@ -87,6 +95,7 @@ public class NugetPackage {
/** /**
* Sets the title. * Sets the title.
*
* @param title the title * @param title the title
*/ */
public void setTitle(String title) { public void setTitle(String title) {
@@ -95,6 +104,7 @@ public class NugetPackage {
/** /**
* Gets the title. * Gets the title.
*
* @return the title * @return the title
*/ */
public String getTitle() { public String getTitle() {
@@ -103,6 +113,7 @@ public class NugetPackage {
/** /**
* Sets the authors. * Sets the authors.
*
* @param authors the authors * @param authors the authors
*/ */
public void setAuthors(String authors) { public void setAuthors(String authors) {
@@ -111,6 +122,7 @@ public class NugetPackage {
/** /**
* Gets the authors. * Gets the authors.
*
* @return the authors * @return the authors
*/ */
public String getAuthors() { public String getAuthors() {
@@ -119,6 +131,7 @@ public class NugetPackage {
/** /**
* Sets the owners. * Sets the owners.
*
* @param owners the owners * @param owners the owners
*/ */
public void setOwners(String owners) { public void setOwners(String owners) {
@@ -127,6 +140,7 @@ public class NugetPackage {
/** /**
* Gets the owners. * Gets the owners.
*
* @return the owners * @return the owners
*/ */
public String getOwners() { public String getOwners() {
@@ -135,6 +149,7 @@ public class NugetPackage {
/** /**
* Sets the licenseUrl. * Sets the licenseUrl.
*
* @param licenseUrl the licenseUrl * @param licenseUrl the licenseUrl
*/ */
public void setLicenseUrl(String licenseUrl) { public void setLicenseUrl(String licenseUrl) {
@@ -143,6 +158,7 @@ public class NugetPackage {
/** /**
* Gets the licenseUrl. * Gets the licenseUrl.
*
* @return the licenseUrl * @return the licenseUrl
*/ */
public String getLicenseUrl() { public String getLicenseUrl() {

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.nuget; package org.owasp.dependencycheck.data.nuget;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Exception during the parsing of a Nuspec file. * Exception during the parsing of a Nuspec file.
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class NuspecParseException extends Exception { public class NuspecParseException extends Exception {
/** /**
@@ -32,19 +35,20 @@ public class NuspecParseException extends Exception {
/** /**
* Constructs a new exception with <code>null</code> as its detail message. * Constructs a new exception with <code>null</code> as its detail message.
* *
* The cause is not initialized, and may subsequently be initialized by a call to * The cause is not initialized, and may subsequently be initialized by a
* {@link java.lang.Throwable#initCause(java.lang.Throwable)}. * call to {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
*/ */
public NuspecParseException() { public NuspecParseException() {
super(); super();
} }
/** /**
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently * Constructs a new exception with the specified detail message. The cause
* be initialized by a call to {@link java.lang.Throwable#initCause(java.lang.Throwable)}. * is not initialized, and may subsequently be initialized by a call to
* {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
* *
* @param message the detail message. The detail message is saved for later retrieval by the * @param message the detail message. The detail message is saved for later
* {@link java.lang.Throwable#getMessage()} method. * retrieval by the {@link java.lang.Throwable#getMessage()} method.
*/ */
public NuspecParseException(String message) { public NuspecParseException(String message) {
super(message); super(message);
@@ -53,13 +57,16 @@ public class NuspecParseException extends Exception {
/** /**
* Constructs a new exception with the specified detail message and cause. * Constructs a new exception with the specified detail message and cause.
* *
* Note that the detail message associated with <code>cause</code> is <em>not</em> * Note that the detail message associated with <code>cause</code> is
* <em>not</em>
* automatically incorporated in this exception's detail message. * automatically incorporated in this exception's detail message.
* *
* @param message the detail message (which is saved for later retrieval by the * @param message the detail message (which is saved for later retrieval by
* {@link java.lang.Throwable#getMessage()} method. * the {@link java.lang.Throwable#getMessage()} method.
* @param cause the cause (which is saved for later retrieval by the {@link java.lang.Throwable#getCause()} method). * @param cause the cause (which is saved for later retrieval by the
* (A <code>null</code> value is permitted, and indicates that the cause is nonexistent or unknown). * {@link java.lang.Throwable#getCause()} method). (A <code>null</code>
* value is permitted, and indicates that the cause is nonexistent or
* unknown).
*/ */
public NuspecParseException(String message, Throwable cause) { public NuspecParseException(String message, Throwable cause) {
super(message, cause); super(message, cause);

View File

@@ -26,6 +26,7 @@ import java.io.InputStream;
* *
*/ */
public interface NuspecParser { public interface NuspecParser {
/** /**
* Parse an input stream and return the resulting {@link NugetPackage}. * Parse an input stream and return the resulting {@link NugetPackage}.
* *

View File

@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.nuget;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath; import javax.xml.xpath.XPath;
@@ -35,6 +36,7 @@ import org.xml.sax.SAXException;
* *
* @author colezlaw * @author colezlaw
*/ */
@ThreadSafe
public class XPathNuspecParser implements NuspecParser { public class XPathNuspecParser implements NuspecParser {
/** /**

View File

@@ -27,6 +27,7 @@ import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.owasp.dependencycheck.utils.DBUtils; import org.owasp.dependencycheck.utils.DBUtils;
import org.owasp.dependencycheck.utils.DependencyVersion; import org.owasp.dependencycheck.utils.DependencyVersion;
@@ -44,6 +45,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public final class ConnectionFactory { public final class ConnectionFactory {
/** /**
@@ -245,6 +247,7 @@ public final class ConnectionFactory {
public boolean h2DataFileExists() throws IOException { public boolean h2DataFileExists() throws IOException {
return h2DataFileExists(settings); return h2DataFileExists(settings);
} }
/** /**
* Determines if the H2 database file exists. If it does not exist then the * Determines if the H2 database file exists. If it does not exist then the
* data structure will need to be created. * data structure will need to be created.

View File

@@ -17,11 +17,15 @@
*/ */
package org.owasp.dependencycheck.data.nvdcve; package org.owasp.dependencycheck.data.nvdcve;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception used to indicate the db4o database is corrupt. This could be due to invalid data or a complete failure of the db. * An exception used to indicate the db4o database is corrupt. This could be due
* to invalid data or a complete failure of the db.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class CorruptDatabaseException extends DatabaseException { public class CorruptDatabaseException extends DatabaseException {
/** /**

View File

@@ -17,7 +17,6 @@
*/ */
package org.owasp.dependencycheck.data.nvdcve; package org.owasp.dependencycheck.data.nvdcve;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.sql.Connection; import java.sql.Connection;
@@ -354,6 +353,7 @@ public final class CveDB implements AutoCloseable {
* *
* @throws SQLException thrown if a SQL Exception occurs * @throws SQLException thrown if a SQL Exception occurs
*/ */
@SuppressWarnings("EmptyMethod")
public synchronized void commit() throws SQLException { public synchronized void commit() throws SQLException {
//temporary remove this as autocommit is on. //temporary remove this as autocommit is on.
//if (isOpen()) { //if (isOpen()) {
@@ -514,7 +514,7 @@ public final class CveDB implements AutoCloseable {
* *
* It should be also called when DB is closed. * It should be also called when DB is closed.
*/ */
private void clearCache() { private synchronized void clearCache() {
vulnerabilitiesForCpeCache.clear(); vulnerabilitiesForCpeCache.clear();
} }

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.nvdcve; package org.owasp.dependencycheck.data.nvdcve;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception thrown if an operation against the database fails. * An exception thrown if an operation against the database fails.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class DatabaseException extends RuntimeException { public class DatabaseException extends RuntimeException {
/** /**

View File

@@ -97,7 +97,7 @@ public class DatabaseProperties {
* *
* @return whether or not any properties are set * @return whether or not any properties are set
*/ */
public boolean isEmpty() { public synchronized boolean isEmpty() {
return properties == null || properties.isEmpty(); return properties == null || properties.isEmpty();
} }
@@ -107,7 +107,7 @@ public class DatabaseProperties {
* @param updatedValue the updated NVD CVE entry * @param updatedValue the updated NVD CVE entry
* @throws UpdateException is thrown if there is an update exception * @throws UpdateException is thrown if there is an update exception
*/ */
public void save(NvdCveInfo updatedValue) throws UpdateException { public synchronized void save(NvdCveInfo updatedValue) throws UpdateException {
if (updatedValue == null) { if (updatedValue == null) {
return; return;
} }
@@ -121,7 +121,7 @@ public class DatabaseProperties {
* @param value the property value * @param value the property value
* @throws UpdateException is thrown if there is an update exception * @throws UpdateException is thrown if there is an update exception
*/ */
public void save(String key, String value) throws UpdateException { public synchronized void save(String key, String value) throws UpdateException {
properties.put(key, value); properties.put(key, value);
cveDB.saveProperty(key, value); cveDB.saveProperty(key, value);
} }
@@ -133,7 +133,7 @@ public class DatabaseProperties {
* @param key the property key * @param key the property key
* @return the value of the property * @return the value of the property
*/ */
public String getProperty(String key) { public synchronized String getProperty(String key) {
return properties.getProperty(key); return properties.getProperty(key);
} }
@@ -145,7 +145,7 @@ public class DatabaseProperties {
* @param defaultValue the default value * @param defaultValue the default value
* @return the value of the property * @return the value of the property
*/ */
public String getProperty(String key, String defaultValue) { public synchronized String getProperty(String key, String defaultValue) {
return properties.getProperty(key, defaultValue); return properties.getProperty(key, defaultValue);
} }
@@ -154,7 +154,7 @@ public class DatabaseProperties {
* *
* @return the collection of Database Properties * @return the collection of Database Properties
*/ */
public Properties getProperties() { public synchronized Properties getProperties() {
return properties; return properties;
} }
@@ -165,7 +165,7 @@ public class DatabaseProperties {
* *
* @return a map of the database meta data * @return a map of the database meta data
*/ */
public Map<String, String> getMetaData() { public synchronized Map<String, String> getMetaData() {
final Map<String, String> map = new TreeMap<>(); final Map<String, String> map = new TreeMap<>();
for (Entry<Object, Object> entry : properties.entrySet()) { for (Entry<Object, Object> entry : properties.entrySet()) {
final String key = (String) entry.getKey(); final String key = (String) entry.getKey();

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.nvdcve; package org.owasp.dependencycheck.data.nvdcve;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception thrown the database driver is unable to be loaded. * An exception thrown the database driver is unable to be loaded.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class DriverLoadException extends Exception { public class DriverLoadException extends Exception {
/** /**

View File

@@ -31,12 +31,14 @@ import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* DriverLoader is a utility class that is used to load database drivers. * DriverLoader is a utility class that is used to load database drivers.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public final class DriverLoader { public final class DriverLoader {
/** /**
@@ -148,8 +150,6 @@ public final class DriverLoader {
final Driver driver = (Driver) c.newInstance(); final Driver driver = (Driver) c.newInstance();
//TODO add usage count so we don't de-register a driver that is in use. //TODO add usage count so we don't de-register a driver that is in use.
final Driver shim = new DriverShim(driver); final Driver shim = new DriverShim(driver);
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path //using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
DriverManager.registerDriver(shim); DriverManager.registerDriver(shim);

View File

@@ -28,16 +28,19 @@ import java.sql.DriverPropertyInfo;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties; import java.util.Properties;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* <p> * <p>
* Driver shim to get around the class loader issue with the DriverManager. The following code is a nearly identical * Driver shim to get around the class loader issue with the DriverManager. The
* copy (with more comments and a few more methods implemented) of the DriverShim from:</p> * following code is a nearly identical copy (with more comments and a few more
* methods implemented) of the DriverShim from:</p>
* <blockquote>http://www.kfu.com/~nsayer/Java/dyn-jdbc.html</blockquote> * <blockquote>http://www.kfu.com/~nsayer/Java/dyn-jdbc.html</blockquote>
* *
* @author Jeremy Long * @author Jeremy Long
* @see java.sql.Driver * @see java.sql.Driver
*/ */
@ThreadSafe
class DriverShim implements Driver { class DriverShim implements Driver {
/** /**
@@ -59,12 +62,13 @@ class DriverShim implements Driver {
} }
/** /**
* Wraps the underlying driver's call to acceptsURL. Returns whether or not the driver can open a connection to the * Wraps the underlying driver's call to acceptsURL. Returns whether or not
* given URL. * the driver can open a connection to the given URL.
* *
* @param url the URL of the database * @param url the URL of the database
* @return true if the wrapped driver can connect to the specified URL * @return true if the wrapped driver can connect to the specified URL
* @throws SQLException thrown if there is an error connecting to the database * @throws SQLException thrown if there is an error connecting to the
* database
* @see java.sql.Driver#acceptsURL(java.lang.String) * @see java.sql.Driver#acceptsURL(java.lang.String)
*/ */
@Override @Override
@@ -78,7 +82,8 @@ class DriverShim implements Driver {
* @param url the URL of the database * @param url the URL of the database
* @param info a collection of string/value pairs * @param info a collection of string/value pairs
* @return a Connection object * @return a Connection object
* @throws SQLException thrown if there is an error connecting to the database * @throws SQLException thrown if there is an error connecting to the
* database
* @see java.sql.Driver#connect(java.lang.String, java.util.Properties) * @see java.sql.Driver#connect(java.lang.String, java.util.Properties)
*/ */
@Override @Override
@@ -112,7 +117,8 @@ class DriverShim implements Driver {
* Wraps the call to the underlying driver's getParentLogger method. * Wraps the call to the underlying driver's getParentLogger method.
* *
* @return the parent's Logger * @return the parent's Logger
* @throws SQLFeatureNotSupportedException thrown if the feature is not supported * @throws SQLFeatureNotSupportedException thrown if the feature is not
* supported
* @see java.sql.Driver#getParentLogger() * @see java.sql.Driver#getParentLogger()
*/ */
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
@@ -140,7 +146,8 @@ class DriverShim implements Driver {
* @param info a collection of string/value pairs * @param info a collection of string/value pairs
* @return an array of DriverPropertyInfo objects * @return an array of DriverPropertyInfo objects
* @throws SQLException thrown if there is an error accessing the database * @throws SQLException thrown if there is an error accessing the database
* @see java.sql.Driver#getPropertyInfo(java.lang.String, java.util.Properties) * @see java.sql.Driver#getPropertyInfo(java.lang.String,
* java.util.Properties)
*/ */
@Override @Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -44,6 +45,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class EngineVersionCheck implements CachedWebDataSource { public class EngineVersionCheck implements CachedWebDataSource {
/** /**
@@ -115,7 +117,7 @@ public class EngineVersionCheck implements CachedWebDataSource {
public void update(Engine engine) throws UpdateException { public void update(Engine engine) throws UpdateException {
this.settings = engine.getSettings(); this.settings = engine.getSettings();
try { try {
CveDB db = engine.getDatabase(); final CveDB db = engine.getDatabase();
final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true); final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
final boolean enabled = settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true); final boolean enabled = settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true);
final String original = settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL); final String original = settings.getString(Settings.KEYS.CVE_ORIGINAL_MODIFIED_20_URL);
@@ -208,7 +210,7 @@ public class EngineVersionCheck implements CachedWebDataSource {
try { try {
final String str = settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt"); final String str = settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
final URL url = new URL(str); final URL url = new URL(str);
URLConnectionFactory factory = new URLConnectionFactory(settings); final URLConnectionFactory factory = new URLConnectionFactory(settings);
conn = factory.createHttpURLConnection(url); conn = factory.createHttpURLConnection(url);
conn.connect(); conn.connect();
if (conn.getResponseCode() != 200) { if (conn.getResponseCode() != 200) {

View File

@@ -17,9 +17,6 @@
*/ */
package org.owasp.dependencycheck.data.update; package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
@@ -27,8 +24,6 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.net.URL; import java.net.URL;
import java.nio.channels.FileLock;
import java.util.Date;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@@ -36,6 +31,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory; import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -63,6 +59,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class NvdCveUpdater implements CachedWebDataSource { public class NvdCveUpdater implements CachedWebDataSource {
/** /**
@@ -116,9 +113,12 @@ public class NvdCveUpdater implements CachedWebDataSource {
if (isUpdateConfiguredFalse()) { if (isUpdateConfiguredFalse()) {
return; return;
} }
H2DBLock dbupdate = new H2DBLock(settings, ConnectionFactory.isH2Connection(settings)); H2DBLock dbupdate = null;
try { try {
dbupdate.lock(); if (ConnectionFactory.isH2Connection(settings)) {
dbupdate = new H2DBLock(settings);
dbupdate.lock();
}
initializeExecutorServices(); initializeExecutorServices();
dbProperties = cveDb.getDatabaseProperties(); dbProperties = cveDb.getDatabaseProperties();
@@ -142,7 +142,9 @@ public class NvdCveUpdater implements CachedWebDataSource {
} catch (H2DBLockException ex) { } catch (H2DBLockException ex) {
throw new UpdateException("Unable to obtain an exclusive lock on the H2 database to perform updates", ex); throw new UpdateException("Unable to obtain an exclusive lock on the H2 database to perform updates", ex);
} finally { } finally {
dbupdate.release(); if (dbupdate != null) {
dbupdate.release();
}
shutdownExecutorServices(); shutdownExecutorServices();
} }
} }
@@ -480,7 +482,7 @@ public class NvdCveUpdater implements CachedWebDataSource {
* *
* @param settings the configured settings * @param settings the configured settings
*/ */
protected void setSettings(Settings settings) { protected synchronized void setSettings(Settings settings) {
this.settings = settings; this.settings = settings;
} }
@@ -513,7 +515,7 @@ public class NvdCveUpdater implements CachedWebDataSource {
public Long call() throws Exception { public Long call() throws Exception {
LOGGER.debug("Checking for updates from: {}", url); LOGGER.debug("Checking for updates from: {}", url);
try { try {
Downloader downloader = new Downloader(settings); final Downloader downloader = new Downloader(settings);
return downloader.getLastModified(new URL(url)); return downloader.getLastModified(new URL(url));
} finally { } finally {
settings.cleanup(false); settings.cleanup(false);

View File

@@ -19,13 +19,15 @@ package org.owasp.dependencycheck.data.update;
import java.util.Iterator; import java.util.Iterator;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import javax.annotation.concurrent.NotThreadSafe;
/** /**
* The CachedWebDataSource Service Loader. This class loads all services that implement * The CachedWebDataSource Service Loader. This class loads all services that
* org.owasp.dependencycheck.data.update.CachedWebDataSource. * implement {@link org.owasp.dependencycheck.data.update.CachedWebDataSource}.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class UpdateService { public class UpdateService {
/** /**
@@ -36,14 +38,16 @@ public class UpdateService {
/** /**
* Creates a new instance of UpdateService. * Creates a new instance of UpdateService.
* *
* @param classLoader the ClassLoader to use when dynamically loading Analyzer and Update services * @param classLoader the ClassLoader to use when dynamically loading
* Analyzer and Update services
*/ */
public UpdateService(ClassLoader classLoader) { public UpdateService(ClassLoader classLoader) {
loader = ServiceLoader.load(CachedWebDataSource.class, classLoader); loader = ServiceLoader.load(CachedWebDataSource.class, classLoader);
} }
/** /**
* Returns an Iterator for all instances of the CachedWebDataSource interface. * Returns an Iterator for all instances of the CachedWebDataSource
* interface.
* *
* @return an iterator of CachedWebDataSource. * @return an iterator of CachedWebDataSource.
*/ */

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.update.cpe;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import org.owasp.dependencycheck.data.update.NvdCveUpdater; import org.owasp.dependencycheck.data.update.NvdCveUpdater;
import org.owasp.dependencycheck.data.update.exception.InvalidDataException; import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
@@ -34,6 +35,7 @@ import org.xml.sax.helpers.DefaultHandler;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class CPEHandler extends DefaultHandler { public class CPEHandler extends DefaultHandler {
/** /**
@@ -62,6 +64,11 @@ public class CPEHandler extends DefaultHandler {
*/ */
private final List<Cpe> data = new ArrayList<>(); private final List<Cpe> data = new ArrayList<>();
/**
* Constructs a new CPE Handler object with the configured settings.
*
* @param settings the configured settings
*/
public CPEHandler(Settings settings) { public CPEHandler(Settings settings) {
cpeStartsWith = settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER, "cpe:/a:"); cpeStartsWith = settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER, "cpe:/a:");
} }

View File

@@ -20,14 +20,30 @@ package org.owasp.dependencycheck.data.update.cpe;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.data.update.exception.InvalidDataException; import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
/** /**
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class Cpe { public class Cpe {
/**
* The CPE identifier string (cpe:/a:vendor:product:version).
*/
private String value;
/**
* The vendor portion of the identifier.
*/
private String vendor;
/**
* The product portion of the identifier.
*/
private String product;
/** /**
* Constructs a new Cpe Object by parsing the vendor and product from the CPE identifier value. * Constructs a new Cpe Object by parsing the vendor and product from the CPE identifier value.
* *
@@ -47,11 +63,6 @@ public class Cpe {
} }
} }
/**
* The CPE identifier string (cpe:/a:vendor:product:version).
*/
private String value;
/** /**
* Get the value of value. * Get the value of value.
* *
@@ -69,10 +80,6 @@ public class Cpe {
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }
/**
* The vendor portion of the identifier.
*/
private String vendor;
/** /**
* Get the value of vendor. * Get the value of vendor.
@@ -92,11 +99,6 @@ public class Cpe {
this.vendor = vendor; this.vendor = vendor;
} }
/**
* The product portion of the identifier.
*/
private String product;
/** /**
* Get the value of product. * Get the value of product.
* *

View File

@@ -17,11 +17,15 @@
*/ */
package org.owasp.dependencycheck.data.update.exception; package org.owasp.dependencycheck.data.update.exception;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An InvalidDataDataException is a generic exception used when trying to load the NVD CVE meta data. * An InvalidDataDataException is a generic exception used when trying to load
* the NVD CVE meta data.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class InvalidDataException extends Exception { public class InvalidDataException extends Exception {
/** /**

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.data.update.exception; package org.owasp.dependencycheck.data.update.exception;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception used when an error occurs reading a setting. * An exception used when an error occurs reading a setting.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class UpdateException extends Exception { public class UpdateException extends Exception {
/** /**

View File

@@ -25,6 +25,7 @@ import java.net.URL;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import javax.annotation.concurrent.ThreadSafe;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.update.exception.UpdateException; import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.DownloadFailedException;
@@ -39,6 +40,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class DownloadTask implements Callable<Future<ProcessTask>> { public class DownloadTask implements Callable<Future<ProcessTask>> {
/** /**
@@ -128,15 +130,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
return first; return first;
} }
/**
* Set the value of first.
*
* @param first new value of first
*/
public void setFirst(File first) {
this.first = first;
}
/** /**
* Get the value of second. * Get the value of second.
* *
@@ -146,15 +139,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
return second; return second;
} }
/**
* Set the value of second.
*
* @param second new value of second
*/
public void setSecond(File second) {
this.second = second;
}
@Override @Override
public Future<ProcessTask> call() throws Exception { public Future<ProcessTask> call() throws Exception {
try { try {
@@ -163,7 +147,7 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId()); LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId());
final long startDownload = System.currentTimeMillis(); final long startDownload = System.currentTimeMillis();
try { try {
Downloader downloader = new Downloader(settings); final Downloader downloader = new Downloader(settings);
downloader.fetchFile(url1, first); downloader.fetchFile(url1, first);
downloader.fetchFile(url2, second); downloader.fetchFile(url2, second);
} catch (DownloadFailedException ex) { } catch (DownloadFailedException ex) {

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.NotThreadSafe;
import org.owasp.dependencycheck.dependency.VulnerableSoftware; import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@@ -34,6 +35,7 @@ import org.xml.sax.helpers.DefaultHandler;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class NvdCve12Handler extends DefaultHandler { public class NvdCve12Handler extends DefaultHandler {
/** /**

View File

@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.data.update.nvd;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
@@ -40,6 +41,7 @@ import static org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler.Attribut
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class NvdCve20Handler extends DefaultHandler { public class NvdCve20Handler extends DefaultHandler {
/** /**
@@ -184,9 +186,7 @@ public class NvdCve20Handler extends DefaultHandler {
totalNumberOfApplicationEntries += 1; totalNumberOfApplicationEntries += 1;
try { try {
saveEntry(vulnerability); saveEntry(vulnerability);
} catch (DatabaseException | CorruptIndexException ex) { } catch (DatabaseException | IOException ex) {
throw new SAXException(ex);
} catch (IOException ex) {
throw new SAXException(ex); throw new SAXException(ex);
} }
} }

View File

@@ -17,17 +17,36 @@
*/ */
package org.owasp.dependencycheck.data.update.nvd; package org.owasp.dependencycheck.data.update.nvd;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* A pojo that contains the Url and timestamp of the current NvdCve XML files. * A pojo that contains the Url and timestamp of the current NvdCve XML files.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class NvdCveInfo { public class NvdCveInfo {
/** /**
* an id. * an id.
*/ */
private String id; private String id;
/**
* a url.
*/
private String url;
/**
* The 1.2 schema URL.
*/
private String oldSchemaVersionUrl;
/**
* a timestamp - epoch time.
*/
private long timestamp;
/**
* indicates whether or not this item should be updated.
*/
private boolean needsUpdate = true;
/** /**
* Get the value of id. * Get the value of id.
@@ -46,10 +65,6 @@ public class NvdCveInfo {
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
/**
* a url.
*/
private String url;
/** /**
* Get the value of url. * Get the value of url.
@@ -68,10 +83,6 @@ public class NvdCveInfo {
public void setUrl(String url) { public void setUrl(String url) {
this.url = url; this.url = url;
} }
/**
* The 1.2 schema URL.
*/
private String oldSchemaVersionUrl;
/** /**
* Get the value of oldSchemaVersionUrl. * Get the value of oldSchemaVersionUrl.
@@ -90,10 +101,6 @@ public class NvdCveInfo {
public void setOldSchemaVersionUrl(String oldSchemaVersionUrl) { public void setOldSchemaVersionUrl(String oldSchemaVersionUrl) {
this.oldSchemaVersionUrl = oldSchemaVersionUrl; this.oldSchemaVersionUrl = oldSchemaVersionUrl;
} }
/**
* a timestamp - epoch time.
*/
private long timestamp;
/** /**
* Get the value of timestamp - epoch time. * Get the value of timestamp - epoch time.
@@ -112,10 +119,6 @@ public class NvdCveInfo {
public void setTimestamp(long timestamp) { public void setTimestamp(long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
/**
* indicates whether or not this item should be updated.
*/
private boolean needsUpdate = true;
/** /**
* Get the value of needsUpdate. * Get the value of needsUpdate.

View File

@@ -23,6 +23,7 @@ import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParser;
import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.CveDB;
@@ -42,6 +43,7 @@ import org.xml.sax.SAXException;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class ProcessTask implements Callable<ProcessTask> { public class ProcessTask implements Callable<ProcessTask> {
/** /**

View File

@@ -21,13 +21,15 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.TreeMap; import java.util.TreeMap;
import javax.annotation.concurrent.NotThreadSafe;
/** /**
* Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded and * Contains a collection of updateable NvdCveInfo objects. This is used to
* processed. * determine which files need to be downloaded and processed.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveInfo> { public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
/** /**
@@ -36,7 +38,13 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
private final Map<String, NvdCveInfo> collection = new TreeMap<>(); private final Map<String, NvdCveInfo> collection = new TreeMap<>();
/** /**
* Returns the collection of NvdCveInfo objects. This method is mainly used for testing. * An internal iterator used to implement iterable.
*/
private Iterator<Entry<String, NvdCveInfo>> iterableContent = null;
/**
* Returns the collection of NvdCveInfo objects. This method is mainly used
* for testing.
* *
* @return the collection of NvdCveInfo objects * @return the collection of NvdCveInfo objects
*/ */
@@ -63,7 +71,8 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
* *
* @param id the key for the item to be added * @param id the key for the item to be added
* @param url the URL to download the item * @param url the URL to download the item
* @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need). * @param oldUrl the URL for the old version of the item (the NVD CVE old
* schema still contains useful data we need).
* @param timestamp the last modified date of the downloaded item * @param timestamp the last modified date of the downloaded item
* @param needsUpdate whether or not the data needs to be updated * @param needsUpdate whether or not the data needs to be updated
*/ */
@@ -93,10 +102,6 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
public long getTimeStamp(String key) { public long getTimeStamp(String key) {
return collection.get(key).getTimestamp(); return collection.get(key).getTimestamp();
} }
/**
* An internal iterator used to implement iterable.
*/
private Iterator<Entry<String, NvdCveInfo>> iterableContent = null;
/** /**
* <p> * <p>
@@ -118,7 +123,8 @@ public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveIn
* <p> * <p>
* <b>This method is not thread safe.</b></p> * <b>This method is not thread safe.</b></p>
* *
* @return true or false depending on whether or not another item exists in the collection * @return true or false depending on whether or not another item exists in
* the collection
*/ */
@Override @Override
public boolean hasNext() { public boolean hasNext() {

View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -43,6 +44,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class Dependency implements Serializable, Comparable<Dependency> { public class Dependency implements Serializable, Comparable<Dependency> {
/** /**

View File

@@ -22,12 +22,14 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.io.Serializable; import java.io.Serializable;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Evidence is a piece of information about a Dependency. * Evidence is a piece of information about a Dependency.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class Evidence implements Serializable, Comparable<Evidence> { public class Evidence implements Serializable, Comparable<Evidence> {
/** /**
@@ -44,6 +46,31 @@ public class Evidence implements Serializable, Comparable<Evidence> {
*/ */
private static final int MAGIC_HASH_MULTIPLIER = 67; private static final int MAGIC_HASH_MULTIPLIER = 67;
/**
* The name of the evidence.
*/
private String name;
/**
* The source of the evidence.
*/
private String source;
/**
* The value of the evidence.
*/
private String value;
/**
* A value indicating if the Evidence has been "used" (aka read).
*/
private boolean used;
/**
* The confidence level for the evidence.
*/
private Confidence confidence;
/** /**
* Creates a new Evidence object. * Creates a new Evidence object.
*/ */
@@ -65,11 +92,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.confidence = confidence; this.confidence = confidence;
} }
/**
* The name of the evidence.
*/
private String name;
/** /**
* Get the value of name. * Get the value of name.
* *
@@ -88,11 +110,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.name = name; this.name = name;
} }
/**
* The source of the evidence.
*/
private String source;
/** /**
* Get the value of source. * Get the value of source.
* *
@@ -111,11 +128,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.source = source; this.source = source;
} }
/**
* The value of the evidence.
*/
private String value;
/** /**
* Get the value of value. * Get the value of value.
* *
@@ -148,11 +160,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.value = value; this.value = value;
} }
/**
* A value indicating if the Evidence has been "used" (aka read).
*/
private boolean used;
/** /**
* Get the value of used. * Get the value of used.
* *
@@ -171,11 +178,6 @@ public class Evidence implements Serializable, Comparable<Evidence> {
this.used = used; this.used = used;
} }
/**
* The confidence level for the evidence.
*/
private Confidence confidence;
/** /**
* Get the value of confidence. * Get the value of confidence.
* *

View File

@@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.owasp.dependencycheck.utils.DependencyVersion; import org.owasp.dependencycheck.utils.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil; import org.owasp.dependencycheck.utils.DependencyVersionUtil;
@@ -37,6 +38,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class EvidenceCollection implements Serializable, Iterable<Evidence> { public class EvidenceCollection implements Serializable, Iterable<Evidence> {
/** /**

View File

@@ -18,12 +18,14 @@
package org.owasp.dependencycheck.dependency; package org.owasp.dependencycheck.dependency;
import java.io.Serializable; import java.io.Serializable;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* In identifier such as a CPE or dependency coordinates (i.e. GAV). * In identifier such as a CPE or dependency coordinates (i.e. GAV).
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class Identifier implements Serializable, Comparable<Identifier> { public class Identifier implements Serializable, Comparable<Identifier> {
//<editor-fold defaultstate="collapsed" desc="fields"> //<editor-fold defaultstate="collapsed" desc="fields">

View File

@@ -18,6 +18,7 @@
package org.owasp.dependencycheck.dependency; package org.owasp.dependencycheck.dependency;
import java.io.Serializable; import java.io.Serializable;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.CompareToBuilder;
/** /**
@@ -26,6 +27,7 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class Reference implements Serializable, Comparable<Reference> { public class Reference implements Serializable, Comparable<Reference> {
/** /**

View File

@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.CompareToBuilder;
/** /**
@@ -30,6 +31,7 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class Vulnerability implements Serializable, Comparable<Vulnerability> { public class Vulnerability implements Serializable, Comparable<Vulnerability> {
/** /**

View File

@@ -19,12 +19,14 @@ package org.owasp.dependencycheck.dependency;
import java.io.Serializable; import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Comparator for Vulnerability objects. * Comparator for Vulnerability objects.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class VulnerabilityComparator implements Comparator<Vulnerability>, Serializable { public class VulnerabilityComparator implements Comparator<Vulnerability>, Serializable {
/** /**

View File

@@ -20,16 +20,19 @@ package org.owasp.dependencycheck.dependency;
import java.io.Serializable; import java.io.Serializable;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.owasp.dependencycheck.data.cpe.IndexEntry; import org.owasp.dependencycheck.data.cpe.IndexEntry;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A record containing information about vulnerable software. This is referenced from a vulnerability. * A record containing information about vulnerable software. This is referenced
* from a vulnerability.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> { public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {
/** /**
@@ -41,6 +44,26 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
*/ */
private static final long serialVersionUID = 307319490326651052L; private static final long serialVersionUID = 307319490326651052L;
/**
* If present, indicates that previous version are vulnerable.
*/
private String previousVersion;
/**
* The name of the cpe.
*/
private String name;
/**
* The product version number.
*/
private String version;
/**
* The product update version.
*/
private String update;
/** /**
* Parse a CPE entry from the cpe string representation. * Parse a CPE entry from the cpe string representation.
* *
@@ -58,7 +81,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
/** /**
* <p> * <p>
* Parses a name attribute value, from the cpe.xml, into its corresponding parts: vendor, product, version, update.</p> * Parses a name attribute value, from the cpe.xml, into its corresponding
* parts: vendor, product, version, update.</p>
* <p> * <p>
* Example:</p> * Example:</p>
* <code>&nbsp;&nbsp;&nbsp;cpe:/a:apache:struts:1.1:rc2</code> * <code>&nbsp;&nbsp;&nbsp;cpe:/a:apache:struts:1.1:rc2</code>
@@ -93,10 +117,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
} }
} }
/**
* If present, indicates that previous version are vulnerable.
*/
private String previousVersion;
/** /**
* Indicates if previous versions of this software are vulnerable. * Indicates if previous versions of this software are vulnerable.
@@ -126,7 +146,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
/** /**
* Standard equals implementation to compare this VulnerableSoftware to another object. * Standard equals implementation to compare this VulnerableSoftware to
* another object.
* *
* @param obj the object to compare * @param obj the object to compare
* @return whether or not the objects are equal * @return whether or not the objects are equal
@@ -156,7 +177,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
/** /**
* Standard toString() implementation display the name and whether or not previous versions are also affected. * Standard toString() implementation display the name and whether or not
* previous versions are also affected.
* *
* @return a string representation of the object * @return a string representation of the object
*/ */
@@ -224,10 +246,9 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
/** /**
* Determines if the string passed in is a positive integer. * Determines if the string passed in is a positive integer. To be counted
* To be counted as a positive integer, the string must only contain 0-9 * as a positive integer, the string must only contain 0-9 and must not have
* and must not have any leading zeros (though "0" is a valid positive * any leading zeros (though "0" is a valid positive integer).
* integer).
* *
* @param str the string to test * @param str the string to test
* @return true if the string only contains 0-9, otherwise false. * @return true if the string only contains 0-9, otherwise false.
@@ -251,10 +272,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
return true; return true;
} }
/**
* The name of the cpe.
*/
private String name;
/** /**
* Get the value of name. * Get the value of name.
@@ -273,10 +290,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
/**
* The product version number.
*/
private String version;
/** /**
* Get the value of version. * Get the value of version.
@@ -295,10 +308,6 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
public void setVersion(String version) { public void setVersion(String version) {
this.version = version; this.version = version;
} }
/**
* The product update version.
*/
private String update;
/** /**
* Get the value of update. * Get the value of update.
@@ -341,7 +350,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
/** /**
* Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default. * Replaces '+' with '%2B' and then URL Decodes the string attempting first
* UTF-8, then ASCII, then default.
* *
* @param string the string to URL Decode * @param string the string to URL Decode
* @return the URL Decoded string * @return the URL Decoded string
@@ -362,7 +372,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
} }
/** /**
* Call {@link java.net.URLDecoder#decode(String)} to URL decode using the default encoding. * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the
* default encoding.
* *
* @param text www-form-encoded URL to decode * @param text www-form-encoded URL to decode
* @return the newly decoded String * @return the newly decoded String

View File

@@ -17,11 +17,14 @@
*/ */
package org.owasp.dependencycheck.exception; package org.owasp.dependencycheck.exception;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* An exception used when a dependency could not be found. * An exception used when a dependency could not be found.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@ThreadSafe
public class DependencyNotFoundException extends Exception { public class DependencyNotFoundException extends Exception {
/** /**

View File

@@ -21,12 +21,14 @@ import java.io.PrintStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/** /**
* A collection of several exceptions. * A collection of several exceptions.
* *
* @author Jeremy Long * @author Jeremy Long
*/ */
@NotThreadSafe
public class ExceptionCollection extends Exception { public class ExceptionCollection extends Exception {
/** /**
* The serial version uid. * The serial version uid.

Some files were not shown because too many files have changed in this diff Show More