diff --git a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTask.java b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTask.java index 83d85d0fe..2e65813ef 100644 --- a/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTask.java +++ b/dependency-check-ant/src/main/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTask.java @@ -741,47 +741,57 @@ public class DependencyCheckTask extends Task { validateConfiguration(); populateSettings(); - final Engine engine = new Engine(); - - for (Resource resource : path) { - final FileProvider provider = resource.as(FileProvider.class); - if (provider != null) { - final File file = provider.getFile(); - if (file != null && file.exists()) { - engine.scan(file); - } - } - } + Engine engine = null; try { - engine.analyzeDependencies(); - DatabaseProperties prop = null; - CveDB cve = null; - try { - cve = new CveDB(); - cve.open(); - prop = cve.getDatabaseProperties(); - } catch (DatabaseException ex) { - Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex); - } finally { - if (cve != null) { - cve.close(); + engine = new Engine(); + + for (Resource resource : path) { + final FileProvider provider = resource.as(FileProvider.class); + if (provider != null) { + final File file = provider.getFile(); + if (file != null && file.exists()) { + engine.scan(file); + } } } - final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop); - reporter.generateReports(reportOutputDirectory, reportFormat); + try { + engine.analyzeDependencies(); + DatabaseProperties prop = null; + CveDB cve = null; + try { + cve = new CveDB(); + cve.open(); + prop = cve.getDatabaseProperties(); + } catch (DatabaseException ex) { + Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex); + } finally { + if (cve != null) { + cve.close(); + } + } + final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop); + reporter.generateReports(reportOutputDirectory, reportFormat); - if (this.failBuildOnCVSS <= 10) { - checkForFailure(engine.getDependencies()); + if (this.failBuildOnCVSS <= 10) { + checkForFailure(engine.getDependencies()); + } + if (this.showSummary) { + showSummary(engine.getDependencies()); + } + } catch (IOException ex) { + Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to generate dependency-check report", ex); + throw new BuildException("Unable to generate dependency-check report", ex); + } catch (Exception ex) { + Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "An exception occurred; unable to continue task", ex); + throw new BuildException("An exception occurred; unable to continue task", ex); } - if (this.showSummary) { - showSummary(engine.getDependencies()); + } catch (DatabaseException ex) { + Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped"); + Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "", ex); + } finally { + if (engine != null) { + engine.cleanup(); } - } catch (IOException ex) { - Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to generate dependency-check report", ex); - throw new BuildException("Unable to generate dependency-check report", ex); - } catch (Exception ex) { - Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "An exception occurred; unable to continue task", ex); - throw new BuildException("An exception occurred; unable to continue task", ex); } } diff --git a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java index 08b4ca1b3..6afc096b0 100644 --- a/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java +++ b/dependency-check-cli/src/main/java/org/owasp/dependencycheck/App.java @@ -98,36 +98,46 @@ public class App { * @param files the files/directories to scan */ private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files, String extraExtensions) { - final Engine scanner = new Engine(); - - for (String file : files) { - scanner.scan(file); - } - - scanner.analyzeDependencies(); - final List dependencies = scanner.getDependencies(); - DatabaseProperties prop = null; - CveDB cve = null; + Engine scanner = null; try { - cve = new CveDB(); - cve.open(); - prop = cve.getDatabaseProperties(); - } catch (DatabaseException ex) { - Logger.getLogger(App.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex); - } finally { - if (cve != null) { - cve.close(); + scanner = new Engine(); + + for (String file : files) { + scanner.scan(file); + } + + scanner.analyzeDependencies(); + final List dependencies = scanner.getDependencies(); + DatabaseProperties prop = null; + CveDB cve = null; + try { + cve = new CveDB(); + cve.open(); + prop = cve.getDatabaseProperties(); + } catch (DatabaseException ex) { + Logger.getLogger(App.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex); + } finally { + if (cve != null) { + cve.close(); + } + } + final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop); + try { + report.generateReports(reportDirectory, outputFormat); + } catch (IOException ex) { + Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an IO error while attempting to generate the report."); + Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex); + } catch (Exception ex) { + Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an error while attempting to generate the report."); + Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex); + } + } catch (DatabaseException ex) { + Logger.getLogger(App.class.getName()).log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped"); + Logger.getLogger(App.class.getName()).log(Level.FINE, "", ex); + } finally { + if (scanner != null) { + scanner.cleanup(); } - } - final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop); - try { - report.generateReports(reportDirectory, outputFormat); - } catch (IOException ex) { - Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an IO error while attempting to generate the report."); - Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex); - } catch (Exception ex) { - Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an error while attempting to generate the report."); - Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex); } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java index b8b4ea5b7..d582cea5c 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java @@ -32,6 +32,7 @@ import org.owasp.dependencycheck.analyzer.AnalyzerService; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex; import org.owasp.dependencycheck.data.cpe.IndexException; +import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory; import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.update.CachedWebDataSource; @@ -67,11 +68,14 @@ public class Engine { /** * Creates a new Engine. + * + * @throws DatabaseException thrown if there is an error connecting to the database */ - public Engine() { + public Engine() throws DatabaseException { this.extensions = new HashSet(); this.dependencies = new ArrayList(); this.analyzers = new EnumMap>(AnalysisPhase.class); + ConnectionFactory.initialize(); boolean autoUpdate = true; try { @@ -85,6 +89,13 @@ public class Engine { loadAnalyzers(); } + /** + * Properly cleans up resources allocated during analysis. + */ + public void cleanup() { + ConnectionFactory.cleanup(); + } + /** * Loads the analyzers specified in the configuration file (or system properties). */ diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java index 2cca38cb3..c54a2deec 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java @@ -173,7 +173,9 @@ public final class ConnectionFactory { } /** - * Cleans up resources and unloads any registered database drivers. + * Cleans up resources and unloads any registered database drivers. This needs to be called to ensure the driver is + * unregistered prior to the finalize method being called as during shutdown the class loader used to load the + * driver may be unloaded prior to the driver being de-registered. */ public static synchronized void cleanup() { if (driver != null) { diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java index 4a4319f70..1b2b64b4c 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/EngineIntegrationTest.java @@ -69,5 +69,6 @@ public class EngineIntegrationTest { ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), dbProp); rg.generateReports("./target/", "ALL"); + instance.cleanup(); } } diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerTest.java index 554923f0c..b9a3adced 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerTest.java @@ -160,6 +160,8 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase { instance.analyze(dependency, engine); int ending_size = engine.getDependencies().size(); + engine.cleanup(); + assertTrue(initial_size < ending_size); } finally { @@ -186,6 +188,7 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase { int initial_size = engine.getDependencies().size(); instance.analyze(dependency, engine); int ending_size = engine.getDependencies().size(); + engine.cleanup(); assertTrue(initial_size < ending_size); @@ -214,7 +217,7 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase { engine.scan(file); engine.analyzeDependencies(); int ending_size = engine.getDependencies().size(); - + engine.cleanup(); assertTrue(initial_size < ending_size); } finally { @@ -261,7 +264,7 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase { engine.scan(file); engine.analyzeDependencies(); int ending_size = engine.getDependencies().size(); - + engine.cleanup(); assertTrue(initial_size < ending_size); } finally { @@ -292,6 +295,7 @@ public class ArchiveAnalyzerTest extends BaseIndexTestCase { // } // assertTrue(failed); int ending_size = engine.getDependencies().size(); + engine.cleanup(); assertEquals(initial_size, ending_size); } finally { instance.close(); diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorTest.java index 09b126540..dd0d7da50 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/reporting/ReportGeneratorTest.java @@ -150,6 +150,8 @@ public class ReportGeneratorTest { ReportGenerator generator = new ReportGenerator("Test Report", engine.getDependencies(), engine.getAnalyzers(), dbProp); generator.generateReport(templateName, writeTo); + engine.cleanup(); + InputStream xsdStream = ReportGenerator.class.getClassLoader().getResourceAsStream("schema/DependencyCheck.xsd"); StreamSource xsdSource = new StreamSource(xsdStream); StreamSource xmlSource = new StreamSource(new File(writeTo)); diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/DependencyCheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/DependencyCheckMojo.java index cf4174215..31831e96a 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/DependencyCheckMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/DependencyCheckMojo.java @@ -280,30 +280,37 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR * * @return the Engine used to scan the dependencies. */ - private Engine executeDependencyCheck() { + private Engine executeDependencyCheck() throws DatabaseException { final InputStream in = DependencyCheckMojo.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE); LogUtils.prepareLogger(in, logFile); populateSettings(); - final Engine engine = new Engine(); - final Set artifacts = project.getArtifacts(); - for (Artifact a : artifacts) { - if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) { - continue; - } + Engine engine = null; + try { + engine = new Engine(); + final Set artifacts = project.getArtifacts(); + for (Artifact a : artifacts) { + if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) { + continue; + } - if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) { - continue; - } + if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) { + continue; + } - if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) { - continue; - } + if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) { + continue; + } - engine.scan(a.getFile().getAbsolutePath()); + engine.scan(a.getFile().getAbsolutePath()); + } + engine.analyzeDependencies(); + } finally { + if (engine != null) { + engine.cleanup(); + } } - engine.analyzeDependencies(); return engine; } @@ -794,13 +801,23 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR * @throws MojoFailureException thrown if a CVSS score is found that is higher then the configured level */ public void execute() throws MojoExecutionException, MojoFailureException { - final Engine engine = executeDependencyCheck(); - generateExternalReports(engine); - if (this.showSummary) { - showSummary(engine.getDependencies()); - } - if (this.failBuildOnCVSS <= 10) { - checkForFailure(engine.getDependencies()); + Engine engine = null; + try { + engine = executeDependencyCheck(); + generateExternalReports(engine); + if (this.showSummary) { + showSummary(engine.getDependencies()); + } + if (this.failBuildOnCVSS <= 10) { + checkForFailure(engine.getDependencies()); + } + } catch (DatabaseException ex) { + Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped"); + Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.FINE, "", ex); + } finally { + if (engine != null) { + engine.cleanup(); + } } } @@ -825,8 +842,18 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR * @throws MavenReportException if a maven report exception occurs */ public void generate(Sink sink, SinkFactory sinkFactory, Locale locale) throws MavenReportException { - final Engine engine = executeDependencyCheck(); - generateMavenSiteReport(engine, sink); + Engine engine = null; + try { + engine = executeDependencyCheck(); + generateMavenSiteReport(engine, sink); + } catch (DatabaseException ex) { + Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped"); + Logger.getLogger(DependencyCheckMojo.class.getName()).log(Level.FINE, "", ex); + } finally { + if (engine != null) { + engine.cleanup(); + } + } } //