Merge branch 'ctrl-alt-dev-master'

Former-commit-id: 18b9ce0c578195a3275c4cb54ed14f6aff953d2b
This commit is contained in:
Jeremy Long
2014-10-25 08:10:14 -04:00
15 changed files with 230 additions and 115 deletions

3
.gitignore vendored
View File

@@ -7,6 +7,9 @@
# Eclipse project files # Eclipse project files
.classpath .classpath
.project .project
.settings
maven-eclipse.xml
.externalToolBuilders
# Netbeans configuration # Netbeans configuration
nb-configuration.xml nb-configuration.xml
/target/ /target/

View File

@@ -400,6 +400,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<version>3.1</version> <version>3.1</version>
<configuration> <configuration>
<showDeprecation>false</showDeprecation> <showDeprecation>false</showDeprecation>
<compilerArgument>-Xlint:unchecked</compilerArgument>
<source>1.6</source> <source>1.6</source>
<target>1.6</target> <target>1.6</target>
</configuration> </configuration>

View File

@@ -168,99 +168,133 @@ public class Engine implements Serializable {
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any * Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection. * dependencies identified are added to the dependency collection.
* *
* @since v0.3.2.5 * @param paths an array of paths to files or directories to be analyzed
* @return the list of dependencies scanned
* *
* @param paths an array of paths to files or directories to be analyzed. * @since v0.3.2.5
*/ */
public void scan(String[] paths) { public List<Dependency> scan(String[] paths) {
List<Dependency> deps = new ArrayList<Dependency>();
for (String path : paths) { for (String path : paths) {
final File file = new File(path); final File file = new File(path);
scan(file); List<Dependency> d = scan(file);
if (d != null) {
deps.addAll(d);
}
} }
return deps;
} }
/** /**
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies * Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
* identified are added to the dependency collection. * identified are added to the dependency collection.
* *
* @param path the path to a file or directory to be analyzed. * @param path the path to a file or directory to be analyzed
* @return the list of dependencies scanned
*/ */
public void scan(String path) { public List<Dependency> scan(String path) {
if (path.matches("^.*[\\/]\\*\\.[^\\/:*|?<>\"]+$")) { if (path.matches("^.*[\\/]\\*\\.[^\\/:*|?<>\"]+$")) {
final String[] parts = path.split("\\*\\."); final String[] parts = path.split("\\*\\.");
final String[] ext = new String[]{parts[parts.length - 1]}; final String[] ext = new String[]{parts[parts.length - 1]};
final File dir = new File(path.substring(0, path.length() - ext[0].length() - 2)); final File dir = new File(path.substring(0, path.length() - ext[0].length() - 2));
if (dir.isDirectory()) { if (dir.isDirectory()) {
final List<File> files = (List<File>) org.apache.commons.io.FileUtils.listFiles(dir, ext, true); final List<File> files = (List<File>) org.apache.commons.io.FileUtils.listFiles(dir, ext, true);
scan(files); return scan(files);
} else { } else {
final String msg = String.format("Invalid file path provided to scan '%s'", path); final String msg = String.format("Invalid file path provided to scan '%s'", path);
LOGGER.log(Level.SEVERE, msg); LOGGER.log(Level.SEVERE, msg);
} }
} else { } else {
final File file = new File(path); final File file = new File(path);
scan(file); return scan(file);
} }
return null;
} }
/** /**
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any * Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection. * dependencies identified are added to the dependency collection.
* *
* @since v0.3.2.5
*
* @param files an array of paths to files or directories to be analyzed. * @param files an array of paths to files or directories to be analyzed.
* @return the list of dependencies
*
* @since v0.3.2.5
*/ */
public void scan(File[] files) { public List<Dependency> scan(File[] files) {
List<Dependency> deps = new ArrayList<Dependency>();
for (File file : files) { for (File file : files) {
scan(file); List<Dependency> d = scan(file);
if (d != null) {
deps.addAll(d);
}
} }
return deps;
} }
/** /**
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any * Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection. * dependencies identified are added to the dependency collection.
* *
* @since v0.3.2.5 * @param files a set of paths to files or directories to be analyzed
* @return the list of dependencies scanned
* *
* @param files a set of paths to files or directories to be analyzed. * @since v0.3.2.5
*/ */
public void scan(Set<File> files) { public List<Dependency> scan(Set<File> files) {
List<Dependency> deps = new ArrayList<Dependency>();
for (File file : files) { for (File file : files) {
scan(file); List<Dependency> d = scan(file);
if (d != null) {
deps.addAll(d);
}
} }
return deps;
} }
/** /**
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any * Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
* dependencies identified are added to the dependency collection. * dependencies identified are added to the dependency collection.
* *
* @since v0.3.2.5 * @param files a set of paths to files or directories to be analyzed
* @return the list of dependencies scanned
* *
* @param files a set of paths to files or directories to be analyzed. * @since v0.3.2.5
*/ */
public void scan(List<File> files) { public List<Dependency> scan(List<File> files) {
List<Dependency> deps = new ArrayList<Dependency>();
for (File file : files) { for (File file : files) {
scan(file); List<Dependency> d = scan(file);
if (d != null) {
deps.addAll(d);
}
} }
return deps;
} }
/** /**
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies * Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
* identified are added to the dependency collection. * identified are added to the dependency collection.
* *
* @param file the path to a file or directory to be analyzed
* @return the list of dependencies scanned
*
* @since v0.3.2.4 * @since v0.3.2.4
* *
* @param file the path to a file or directory to be analyzed.
*/ */
public void scan(File file) { public List<Dependency> scan(File file) {
if (file.exists()) { if (file.exists()) {
if (file.isDirectory()) { if (file.isDirectory()) {
scanDirectory(file); return scanDirectory(file);
} else { } else {
scanFile(file); Dependency d = scanFile(file);
if (d != null) {
List<Dependency> deps = new ArrayList<Dependency>();
deps.add(d);
return deps;
}
} }
} }
return null;
} }
/** /**
@@ -268,42 +302,50 @@ public class Engine implements Serializable {
* *
* @param dir the directory to scan. * @param dir the directory to scan.
*/ */
protected void scanDirectory(File dir) { protected List<Dependency> scanDirectory(File dir) {
final File[] files = dir.listFiles(); final File[] files = dir.listFiles();
List<Dependency> deps = new ArrayList<Dependency>();
if (files != null) { if (files != null) {
for (File f : files) { for (File f : files) {
if (f.isDirectory()) { if (f.isDirectory()) {
scanDirectory(f); List<Dependency> d = scanDirectory(f);
if (d != null) {
deps.addAll(d);
}
} else { } else {
scanFile(f); Dependency d = scanFile(f);
deps.add(d);
} }
} }
} }
return deps;
} }
/** /**
* Scans a specified file. If a dependency is identified it is added to the dependency collection. * Scans a specified file. If a dependency is identified it is added to the dependency collection.
* *
* @param file The file to scan. * @param file The file to scan
* @return the scanned dependency
*/ */
protected void scanFile(File file) { protected Dependency scanFile(File file) {
if (!file.isFile()) { if (!file.isFile()) {
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString()); final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
LOGGER.log(Level.FINE, msg); LOGGER.log(Level.FINE, msg);
return; return null;
} }
final String fileName = file.getName(); final String fileName = file.getName();
final String extension = FileUtils.getFileExtension(fileName); final String extension = FileUtils.getFileExtension(fileName);
Dependency dependency = null;
if (extension != null) { if (extension != null) {
if (supportsExtension(extension)) { if (supportsExtension(extension)) {
final Dependency dependency = new Dependency(file); dependency = new Dependency(file);
dependencies.add(dependency); dependencies.add(dependency);
} }
} else { } else {
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
file.toString());
LOGGER.log(Level.FINEST, msg); LOGGER.log(Level.FINEST, msg);
} }
return dependency;
} }
/** /**
@@ -439,8 +481,7 @@ public class Engine implements Serializable {
} catch (UpdateException ex) { } catch (UpdateException ex) {
LOGGER.log(Level.WARNING, LOGGER.log(Level.WARNING,
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities."); "Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
LOGGER.log(Level.FINE, LOGGER.log(Level.FINE, String.format("Unable to update details for %s", source.getClass().getName()), ex);
String.format("Unable to update details for %s", source.getClass().getName()), ex);
} }
} }
} }

View File

@@ -110,7 +110,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
static { static {
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS); final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
if (additionalZipExt != null) { if (additionalZipExt != null) {
final HashSet ext = new HashSet<String>(Arrays.asList(additionalZipExt)); final HashSet<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
ZIPPABLES.addAll(ext); ZIPPABLES.addAll(ext);
} }
EXTENSIONS.addAll(ZIPPABLES); EXTENSIONS.addAll(ZIPPABLES);
@@ -221,9 +221,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
final String displayPath = String.format("%s%s", final String displayPath = String.format("%s%s",
dependency.getFilePath(), dependency.getFilePath(),
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length())); d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
final String displayName = String.format("%s[%s]", final String displayName = String.format("%s: %s",
dependency.getFileName(), dependency.getFileName(),
File.separator,
d.getFileName()); d.getFileName());
d.setFilePath(displayPath); d.setFilePath(displayPath);
d.setFileName(displayName); d.setFileName(displayName);

View File

@@ -188,7 +188,9 @@ public class CPEAnalyzer implements Analyzer {
if (!vendors.isEmpty() && !products.isEmpty()) { if (!vendors.isEmpty() && !products.isEmpty()) {
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(), final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
dependency.getVendorEvidence().getWeighting()); dependency.getVendorEvidence().getWeighting());
if (entries == null) {
continue;
}
boolean identifierAdded = false; boolean identifierAdded = false;
for (IndexEntry e : entries) { for (IndexEntry e : entries) {
if (verifyEntry(e, dependency)) { if (verifyEntry(e, dependency)) {
@@ -250,27 +252,24 @@ public class CPEAnalyzer implements Analyzer {
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field * @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
* @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search * @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search
* @return a list of possible CPE values * @return a list of possible CPE values
* @throws CorruptIndexException when the Lucene index is corrupt
* @throws IOException when the Lucene index is not found
* @throws ParseException when the generated query is not valid
*/ */
protected List<IndexEntry> searchCPE(String vendor, String product, protected List<IndexEntry> searchCPE(String vendor, String product,
Set<String> vendorWeightings, Set<String> productWeightings) Set<String> vendorWeightings, Set<String> productWeightings) {
throws CorruptIndexException, IOException, ParseException {
final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS); final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings); final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
if (searchString == null) { if (searchString == null) {
return ret; return ret;
} }
try {
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS); final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
for (ScoreDoc d : docs.scoreDocs) { for (ScoreDoc d : docs.scoreDocs) {
if (d.score >= 0.08) { if (d.score >= 0.08) {
final Document doc = cpe.getDocument(d.doc); final Document doc = cpe.getDocument(d.doc);
final IndexEntry entry = new IndexEntry(); final IndexEntry entry = new IndexEntry();
entry.setVendor(doc.get(Fields.VENDOR)); entry.setVendor(doc.get(Fields.VENDOR));
entry.setProduct(doc.get(Fields.PRODUCT)); entry.setProduct(doc.get(Fields.PRODUCT));
// if (d.score < 0.08) { // if (d.score < 0.08) {
// System.out.print(entry.getVendor()); // System.out.print(entry.getVendor());
// System.out.print(":"); // System.out.print(":");
@@ -278,13 +277,25 @@ public class CPEAnalyzer implements Analyzer {
// System.out.print(":"); // System.out.print(":");
// System.out.println(d.score); // System.out.println(d.score);
// } // }
entry.setSearchScore(d.score); entry.setSearchScore(d.score);
if (!ret.contains(entry)) { if (!ret.contains(entry)) {
ret.add(entry); ret.add(entry);
}
} }
} }
return ret;
} catch (ParseException ex) {
final String msg = String.format("Unable to parse: %s", searchString);
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.WARNING,
"An error occured querying the CPE data. See the log for more details.");
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.INFO, msg, ex);
} catch (IOException ex) {
final String msg = String.format("IO Error with search string: %s", searchString);
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.WARNING,
"An error occured reading CPE data. See the log for more details.");
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.INFO, msg, ex);
} }
return ret; return null;
} }
/** /**

View File

@@ -73,7 +73,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
public void analyze(Dependency dependency, Engine engine) throws AnalysisException { public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
//strip any path information that may get added by ArchiveAnalyzer, etc. //strip any path information that may get added by ArchiveAnalyzer, etc.
final File f = new File(dependency.getFileName()); final File f = dependency.getActualFile();
String fileName = f.getName(); String fileName = f.getName();
//remove file extension //remove file extension

View File

@@ -327,11 +327,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
final String displayPath = String.format("%s%s%s", final String displayPath = String.format("%s%s%s",
dependency.getFilePath(), dependency.getFilePath(),
File.separator, File.separator,
path); //.replaceAll("[\\/]", File.separator)); path);
final String displayName = String.format("%s%s%s", final String displayName = String.format("%s%s%s",
dependency.getFileName(), dependency.getFileName(),
File.separator, File.separator,
path); //.replaceAll("[\\/]", File.separator)); path);
newDependency.setFileName(displayName); newDependency.setFileName(displayName);
newDependency.setFilePath(displayPath); newDependency.setFilePath(displayPath);

View File

@@ -24,13 +24,13 @@ import java.net.URL;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
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.nexus.MavenArtifact; import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.data.nexus.NexusSearch; import org.owasp.dependencycheck.data.nexus.NexusSearch;
import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.Settings;
/** /**
@@ -152,29 +152,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException { public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
try { try {
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum()); final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) { dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(), Confidence.HIGH);
}
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(), Confidence.HIGH);
}
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
}
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
boolean found = false;
for (Identifier i : dependency.getIdentifiers()) {
if ("maven".equals(i.getType()) && i.getValue().equals(ma.toString())) {
found = true;
i.setConfidence(Confidence.HIGHEST);
i.setUrl(ma.getArtifactUrl());
break;
}
}
if (!found) {
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
}
}
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1")); //dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName())); LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));

View File

@@ -29,10 +29,12 @@ import java.util.logging.Logger;
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
public final class CweDB { public final class CweDB {
/** /**
* The Logger. * The Logger.
*/ */
private static final Logger LOGGER = Logger.getLogger(CweDB.class.getName()); private static final Logger LOGGER = Logger.getLogger(CweDB.class.getName());
/** /**
* Empty private constructor as this is a utility class. * Empty private constructor as this is a utility class.
*/ */
@@ -55,7 +57,9 @@ public final class CweDB {
final String filePath = "data/cwe.hashmap.serialized"; final String filePath = "data/cwe.hashmap.serialized";
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath); final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
oin = new ObjectInputStream(input); oin = new ObjectInputStream(input);
return (HashMap<String, String>) oin.readObject(); @SuppressWarnings("unchecked")
HashMap<String, String> ret = (HashMap<String, String>) oin.readObject();
return ret;
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue."); LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
LOGGER.log(Level.FINE, null, ex); LOGGER.log(Level.FINE, null, ex);

View File

@@ -26,6 +26,7 @@ import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.utils.Checksum; import org.owasp.dependencycheck.utils.Checksum;
import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.FileUtils;
@@ -316,6 +317,39 @@ public class Dependency implements Serializable, Comparable<Dependency> {
this.identifiers.add(i); this.identifiers.add(i);
} }
/**
* Adds the maven artifact as evidence.
*
* @param source The source of the evidence
* @param mavenArtifact The maven artifact
* @param confidence The confidence level of this evidence
*/
public void addAsEvidence(String source, MavenArtifact mavenArtifact, Confidence confidence) {
if (mavenArtifact.getGroupId() != null && !mavenArtifact.getGroupId().isEmpty()) {
this.getVendorEvidence().addEvidence(source, "groupid", mavenArtifact.getGroupId(), confidence);
}
if (mavenArtifact.getArtifactId() != null && !mavenArtifact.getArtifactId().isEmpty()) {
this.getProductEvidence().addEvidence(source, "artifactid", mavenArtifact.getArtifactId(), confidence);
}
if (mavenArtifact.getVersion() != null && !mavenArtifact.getVersion().isEmpty()) {
this.getVersionEvidence().addEvidence(source, "version", mavenArtifact.getVersion(), confidence);
}
if (mavenArtifact.getArtifactUrl() != null && !mavenArtifact.getArtifactUrl().isEmpty()) {
boolean found = false;
for (Identifier i : this.getIdentifiers()) {
if ("maven".equals(i.getType()) && i.getValue().equals(mavenArtifact.toString())) {
found = true;
i.setConfidence(Confidence.HIGHEST);
i.setUrl(mavenArtifact.getArtifactUrl());
break;
}
}
if (!found) {
this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
}
}
}
/** /**
* Adds an entry to the list of detected Identifiers for the dependency file. * Adds an entry to the list of detected Identifiers for the dependency file.
* *
@@ -324,6 +358,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
public void addIdentifier(Identifier identifier) { public void addIdentifier(Identifier identifier) {
this.identifiers.add(identifier); this.identifiers.add(identifier);
} }
/** /**
* A set of identifiers that have been suppressed. * A set of identifiers that have been suppressed.
*/ */
@@ -441,6 +476,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
public EvidenceCollection getVersionEvidence() { public EvidenceCollection getVersionEvidence() {
return this.versionEvidence; return this.versionEvidence;
} }
/** /**
* The description of the JAR file. * The description of the JAR file.
*/ */
@@ -463,6 +499,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
/** /**
* The license that this dependency uses. * The license that this dependency uses.
*/ */
@@ -485,6 +522,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
public void setLicense(String license) { public void setLicense(String license) {
this.license = license; this.license = license;
} }
/** /**
* A list of vulnerabilities for this dependency. * A list of vulnerabilities for this dependency.
*/ */
@@ -540,6 +578,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
public void addVulnerability(Vulnerability vulnerability) { public void addVulnerability(Vulnerability vulnerability) {
this.vulnerabilities.add(vulnerability); this.vulnerabilities.add(vulnerability);
} }
/** /**
* A collection of related dependencies. * A collection of related dependencies.
*/ */

View File

@@ -906,6 +906,6 @@ arising out of or in connection with the use of this tool, the analysis performe
## END SUPPRESSED VULNERABILITIES ## END SUPPRESSED VULNERABILITIES
</div> </div>
</div> </div>
<div><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</div> <div><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</div>
</body> </body>
</html> </html>

View File

@@ -236,6 +236,6 @@ arising out of or in connection with the use of this tool, the analysis performe
</tbody> </tbody>
</table> </table>
</div> </div>
<p><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</p> <p><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</p>
</body> </body>
</html> </html>

View File

@@ -17,7 +17,9 @@
*/ */
package org.owasp.dependencycheck; package org.owasp.dependencycheck;
import java.util.List;
import org.junit.After; import org.junit.After;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -54,8 +56,8 @@ public class EngineIntegrationTest extends BaseTest {
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false); Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
Engine instance = new Engine(); Engine instance = new Engine();
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate); Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
instance.scan(testClasses); List<Dependency> deps = instance.scan(testClasses);
assertTrue(instance.getDependencies().size() > 0); assertFalse(deps.isEmpty());
for (Dependency d : instance.getDependencies()) { for (Dependency d : instance.getDependencies()) {
assertTrue("non-zip file collected " + d.getFileName(), d.getFileName().toLowerCase().endsWith(".zip")); assertTrue("non-zip file collected " + d.getFileName(), d.getFileName().toLowerCase().endsWith(".zip"));
} }
@@ -81,8 +83,7 @@ public class EngineIntegrationTest extends BaseTest {
cveDB.open(); cveDB.open();
DatabaseProperties dbProp = cveDB.getDatabaseProperties(); DatabaseProperties dbProp = cveDB.getDatabaseProperties();
cveDB.close(); cveDB.close();
ReportGenerator rg = new ReportGenerator("DependencyCheck", ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), dbProp);
instance.getDependencies(), instance.getAnalyzers(), dbProp);
rg.generateReports("./target/", "ALL"); rg.generateReports("./target/", "ALL");
instance.cleanup(); instance.cleanup();
} }

View File

@@ -23,10 +23,12 @@ import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
/** /**
* *
@@ -152,7 +154,7 @@ public class DependencyTest {
public void testGetMd5sum() { public void testGetMd5sum() {
File file = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath()); File file = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
Dependency instance = new Dependency(file); Dependency instance = new Dependency(file);
// assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum()); //assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
String expResult = "C30B57142E1CCBC1EFD5CD15F307358F"; String expResult = "C30B57142E1CCBC1EFD5CD15F307358F";
String result = instance.getMd5sum(); String result = instance.getMd5sum();
assertEquals(expResult, result); assertEquals(expResult, result);
@@ -294,4 +296,34 @@ public class DependencyTest {
EvidenceCollection result = instance.getVersionEvidence(); EvidenceCollection result = instance.getVersionEvidence();
assertTrue(true); //this is just a getter setter pair. assertTrue(true); //this is just a getter setter pair.
} }
/**
* Test of addAsEvidence method, of class Dependency.
*/
@Test
public void testAddAsEvidence() {
Dependency instance = new Dependency();
MavenArtifact mavenArtifact = new MavenArtifact("group", "artifact", "version", "url");
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
assertTrue(instance.getEvidence().contains(Confidence.HIGH));
assertFalse(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
assertFalse(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
assertFalse(instance.getEvidence().getEvidence("pom", "version").isEmpty());
assertFalse(instance.getIdentifiers().isEmpty());
}
/**
* Test of addAsEvidence method, of class Dependency.
*/
@Test
public void testAddAsEvidenceWithEmptyArtefact() {
Dependency instance = new Dependency();
MavenArtifact mavenArtifact = new MavenArtifact(null, null, null, null);
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
assertFalse(instance.getEvidence().contains(Confidence.HIGH));
assertTrue(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
assertTrue(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
assertTrue(instance.getEvidence().getEvidence("pom", "version").isEmpty());
assertTrue(instance.getIdentifiers().isEmpty());
}
} }

View File

@@ -46,7 +46,9 @@ import org.apache.maven.settings.Proxy;
import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer; import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Confidence;
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;
@@ -58,9 +60,7 @@ import org.owasp.dependencycheck.utils.Settings;
* *
* @author Jeremy Long <jeremy.long@owasp.org> * @author Jeremy Long <jeremy.long@owasp.org>
*/ */
@Mojo(name = "check", defaultPhase = LifecyclePhase.COMPILE, threadSafe = true, @Mojo(name = "check", defaultPhase = LifecyclePhase.COMPILE, threadSafe = true, requiresDependencyResolution = ResolutionScope.RUNTIME_PLUS_SYSTEM, requiresOnline = true)
requiresDependencyResolution = ResolutionScope.RUNTIME_PLUS_SYSTEM,
requiresOnline = true)
public class DependencyCheckMojo extends ReportAggregationMojo { public class DependencyCheckMojo extends ReportAggregationMojo {
//<editor-fold defaultstate="collapsed" desc="Private fields"> //<editor-fold defaultstate="collapsed" desc="Private fields">
@@ -292,6 +292,7 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
@Parameter(property = "externalReport") @Parameter(property = "externalReport")
@Deprecated @Deprecated
private String externalReport = null; private String externalReport = null;
// </editor-fold> // </editor-fold>
/** /**
* Constructs a new dependency-check-mojo. * Constructs a new dependency-check-mojo.
@@ -326,8 +327,20 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
if (excludeFromScan(a)) { if (excludeFromScan(a)) {
continue; continue;
} }
List<Dependency> deps = localEngine.scan(a.getFile().getAbsoluteFile());
localEngine.scan(a.getFile().getAbsolutePath()); if (deps != null) {
if (deps.size() == 1) {
Dependency d = deps.get(0);
if (d != null) {
MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
d.addAsEvidence("pom", ma, Confidence.HIGHEST);
}
} else {
final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s:%s:%s'",
a.getGroupId(), a.getArtifactId(), a.getVersion());
LOGGER.info(msg);
}
}
} }
localEngine.analyzeDependencies(); localEngine.analyzeDependencies();
@@ -396,8 +409,7 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
} }
if (proxyUrl != null && !proxyUrl.isEmpty()) { if (proxyUrl != null && !proxyUrl.isEmpty()) {
LOGGER.warning("Deprecated configuration detected, proxyUrl will be ignored; use the maven settings " LOGGER.warning("Deprecated configuration detected, proxyUrl will be ignored; use the maven settings " + "to configure the proxy instead");
+ "to configure the proxy instead");
} }
final Proxy proxy = getMavenProxy(); final Proxy proxy = getMavenProxy();
if (proxy != null) { if (proxy != null) {
@@ -510,8 +522,8 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
} }
return null; return null;
} }
//</editor-fold>
//</editor-fold>
/** /**
* Executes the dependency-check and generates the report. * Executes the dependency-check and generates the report.
* *
@@ -530,8 +542,7 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
checkForFailure(engine.getDependencies()); checkForFailure(engine.getDependencies());
} }
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
LOGGER.log(Level.SEVERE, LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
"Unable to connect to the dependency-check database; analysis has stopped");
LOGGER.log(Level.FINE, "", ex); LOGGER.log(Level.FINE, "", ex);
} }
} }
@@ -580,16 +591,15 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
engine = initializeEngine(); engine = initializeEngine();
engine.getDependencies().addAll(deps); engine.getDependencies().addAll(deps);
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check initialization occured while scanning %s", final String msg = String.format("An unrecoverable exception with the dependency-check initialization occured while scanning %s", getProject()
getProject().getName()); .getName());
throw new MavenReportException(msg, ex); throw new MavenReportException(msg, ex);
} }
} else { } else {
try { try {
engine = executeDependencyCheck(); engine = executeDependencyCheck();
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check scan occured while scanning %s", final String msg = String.format("An unrecoverable exception with the dependency-check scan occured while scanning %s", getProject().getName());
getProject().getName());
throw new MavenReportException(msg, ex); throw new MavenReportException(msg, ex);
} }
} }
@@ -612,8 +622,7 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
try { try {
engine = executeDependencyCheck(project); engine = executeDependencyCheck(project);
} catch (DatabaseException ex) { } catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check scan occured while scanning %s", final String msg = String.format("An unrecoverable exception with the dependency-check scan occured while scanning %s", project.getName());
project.getName());
throw new MavenReportException(msg, ex); throw new MavenReportException(msg, ex);
} }
} }
@@ -646,8 +655,7 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
* @return the output name * @return the output name
*/ */
public String getOutputName() { public String getOutputName() {
if ("HTML".equalsIgnoreCase(this.format) if ("HTML".equalsIgnoreCase(this.format) || "ALL".equalsIgnoreCase(this.format)) {
|| "ALL".equalsIgnoreCase(this.format)) {
return "dependency-check-report"; return "dependency-check-report";
} else if ("XML".equalsIgnoreCase(this.format)) { } else if ("XML".equalsIgnoreCase(this.format)) {
return "dependency-check-report.xml#"; return "dependency-check-report.xml#";
@@ -685,8 +693,7 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
* @return the description * @return the description
*/ */
public String getDescription(Locale locale) { public String getDescription(Locale locale) {
return "A report providing details on any published " return "A report providing details on any published " + "vulnerabilities within project dependencies. This report is a best effort but may contain "
+ "vulnerabilities within project dependencies. This report is a best effort but may contain "
+ "false positives and false negatives."; + "false positives and false negatives.";
} }
@@ -740,8 +747,8 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
protected boolean canGenerateAggregateReport() { protected boolean canGenerateAggregateReport() {
return isAggregate() && isLastProject(); return isAggregate() && isLastProject();
} }
// </editor-fold>
// </editor-fold>
//<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary"> //<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
/** /**
* Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the * Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
@@ -807,14 +814,13 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
} }
} }
if (summary.length() > 0) { if (summary.length() > 0) {
final String msg = String.format("%n%n" final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString()); + "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
LOGGER.log(Level.WARNING, msg); LOGGER.log(Level.WARNING, msg);
} }
} }
//</editor-fold>
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Methods to read/write the serialized data file"> //<editor-fold defaultstate="collapsed" desc="Methods to read/write the serialized data file">
/** /**
* Writes the scan data to disk. This is used to serialize the scan data between the "check" and "aggregate" phase. * Writes the scan data to disk. This is used to serialize the scan data between the "check" and "aggregate" phase.