diff --git a/src/main/java/org/owasp/dependencycheck/data/cpe/Index.java b/src/main/java/org/owasp/dependencycheck/data/cpe/Index.java index 1040cc68b..20b9b1c69 100644 --- a/src/main/java/org/owasp/dependencycheck/data/cpe/Index.java +++ b/src/main/java/org/owasp/dependencycheck/data/cpe/Index.java @@ -20,7 +20,6 @@ package org.owasp.dependencycheck.data.cpe; import java.io.File; import java.io.IOException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; import org.apache.lucene.analysis.Analyzer; @@ -37,6 +36,7 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; import org.owasp.dependencycheck.data.lucene.AbstractIndex; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.data.lucene.FieldAnalyzer; import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer; @@ -70,16 +70,7 @@ public class Index extends AbstractIndex { */ public File getDataDirectory() throws IOException { final String fileName = Settings.getString(Settings.KEYS.CPE_INDEX); - final String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - final String decodedPath = URLDecoder.decode(filePath, "UTF-8"); - File exePath = new File(decodedPath); - if (exePath.getName().toLowerCase().endsWith(".jar")) { - exePath = exePath.getParentFile(); - } else { - exePath = new File("."); - } - File path = new File(exePath.getCanonicalFile() + File.separator + fileName); - path = new File(path.getCanonicalPath()); + File path = FileUtils.getDataDirectory(fileName, Index.class); if (!path.exists()) { if (!path.mkdirs()) { throw new IOException("Unable to create CPE Data directory"); diff --git a/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java index c7c064da5..cd517f91c 100644 --- a/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java +++ b/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java @@ -21,7 +21,6 @@ package org.owasp.dependencycheck.data.nvdcve; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; @@ -37,6 +36,7 @@ import org.owasp.dependencycheck.data.cwe.CweDB; import org.owasp.dependencycheck.dependency.Reference; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.VulnerableSoftware; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; /** @@ -408,18 +408,7 @@ public class CveDB { */ public static File getDataDirectory() throws IOException { final String fileName = Settings.getString(Settings.KEYS.CVE_INDEX); - final String filePath = CveDB.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - final String decodedPath = URLDecoder.decode(filePath, "UTF-8"); - File exePath = new File(decodedPath); - - if (exePath.getName().toLowerCase().endsWith(".jar")) { - exePath = exePath.getParentFile(); - } else { - exePath = new File("."); - } - File path = new File(exePath.getCanonicalFile() + File.separator + fileName); - path = new File(path.getCanonicalPath()); - + File path = FileUtils.getDataDirectory(fileName, CveDB.class); if (!path.exists()) { if (!path.mkdirs()) { throw new IOException("Unable to create NVD CVE Data directory"); diff --git a/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java b/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java index 544a97eca..144437c56 100644 --- a/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java +++ b/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java @@ -100,6 +100,7 @@ public class ReportGenerator { */ private VelocityEngine createVelocityEngine() { final VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName()); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); return ve; diff --git a/src/main/java/org/owasp/dependencycheck/reporting/VelocityLoggerRedirect.java b/src/main/java/org/owasp/dependencycheck/reporting/VelocityLoggerRedirect.java new file mode 100644 index 000000000..9bd5bff14 --- /dev/null +++ b/src/main/java/org/owasp/dependencycheck/reporting/VelocityLoggerRedirect.java @@ -0,0 +1,93 @@ +/* + * This file is part of Dependency-Check. + * + * Dependency-Check is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Dependency-Check is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * Dependency-Check. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.reporting; + +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.runtime.log.LogChute; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * DependencyCheck uses {@link java.util.logging.Logger} as a logging framework, + * and Apache Velocity uses a custom logging implementation that outputs to a + * file named velocity.log by default. This class is an implementation of a + * custom Velocity logger that redirects all velocity logging to the Java Logger + * class. + *

+ * This class was written to address permission issues when using DependencyCheck + * in a server environment (such as the Jenkins plugin). In some circumstances, + * Velocity would attempt to create velocity.log in an un-writable directory. + * + * @author Steve Springett (steve.springett@owasp.org) + */ +public class VelocityLoggerRedirect implements LogChute { + + /** + * This will be invoked once by the LogManager + */ + public void init(RuntimeServices rsvc) { + // do nothing + } + + /** + * Given a Velocity log level and message, this method will + * call the appropriate Logger level and log the specified values. + */ + public void log(int level, String message) { + Logger.getLogger(Velocity.class.getName()).log(getLevel(level), message); + } + + /** + * Given a Velocity log level, message and Throwable, this method will + * call the appropriate Logger level and log the specified values. + */ + public void log(int level, String message, Throwable t) { + Logger.getLogger(Velocity.class.getName()).log(getLevel(level), message, t); + } + + /** + * Will always return true. The property file will decide what level to log. + */ + public boolean isLevelEnabled(int level) { + return true; + } + + /** + * Maps Velocity log levels to {@link Logger} values. + */ + private Level getLevel(int velocityLevel) { + switch (velocityLevel) { + case TRACE_ID: + return Level.ALL; + case DEBUG_ID: + return Level.FINE; + case INFO_ID: + return Level.INFO; + case WARN_ID: + return Level.WARNING; + case ERROR_ID: + return Level.SEVERE; + default: + return Level.INFO; + } + } + +} diff --git a/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java b/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java index 0d48eb8d1..1949b8d83 100644 --- a/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java +++ b/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java @@ -21,6 +21,7 @@ package org.owasp.dependencycheck.utils; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.net.URLDecoder; /** * A collection of utilities for processing information about files. @@ -67,4 +68,34 @@ public final class FileUtils { throw new FileNotFoundException("Failed to delete file: " + file); } } + + /** + * Returns the data directory. If a path was specified in dependencycheck.properties + * or was specified using the Settings object, and the path exists, that path will be + * returned as a File object. If it does not exist, then a File object will be created + * based on the file location of the JAR containing the specified class. + * + * @param configuredFilePath the configured relative or absolute path + * @param clazz the class whos path will be resolved + * @return a File object + * @throws IOException is thrown if the path could not be decoded + */ + public static File getDataDirectory(String configuredFilePath, Class clazz) throws IOException { + File file = new File(configuredFilePath); + if (file.exists() && file.isDirectory() && file.canWrite()) { + return new File(file.getCanonicalPath()); + } else { + final String filePath = clazz.getProtectionDomain().getCodeSource().getLocation().getPath(); + final String decodedPath = URLDecoder.decode(filePath, "UTF-8"); + File exePath = new File(decodedPath); + if (exePath.getName().toLowerCase().endsWith(".jar")) { + exePath = exePath.getParentFile(); + } else { + exePath = new File("."); + } + File path = new File(exePath.getCanonicalFile() + File.separator + configuredFilePath); + return new File(path.getCanonicalPath()); + } + } + } diff --git a/src/test/java/org/owasp/dependencycheck/data/cpe/BaseIndexTestCase.java b/src/test/java/org/owasp/dependencycheck/data/cpe/BaseIndexTestCase.java index ba61280c6..a61e11ebd 100644 --- a/src/test/java/org/owasp/dependencycheck/data/cpe/BaseIndexTestCase.java +++ b/src/test/java/org/owasp/dependencycheck/data/cpe/BaseIndexTestCase.java @@ -18,20 +18,19 @@ */ package org.owasp.dependencycheck.data.cpe; -import org.owasp.dependencycheck.data.cpe.Index; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.net.URLDecoder; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; /** @@ -59,17 +58,7 @@ public abstract class BaseIndexTestCase { protected static File getDataDirectory() throws IOException { String fileName = Settings.getString(Settings.KEYS.CPE_INDEX); - String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - String decodedPath = URLDecoder.decode(filePath, "UTF-8"); - File exePath = new File(decodedPath); - if (exePath.getName().toLowerCase().endsWith(".jar")) { - exePath = exePath.getParentFile(); - } else { - exePath = new File("."); - } - File path = new File(exePath.getCanonicalFile() + File.separator + fileName); - path = new File(path.getCanonicalPath()); - return path; + return FileUtils.getDataDirectory(fileName, Index.class); } public static void ensureIndexExists() throws Exception { diff --git a/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java b/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java index d0cc33c84..2c579de86 100644 --- a/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java +++ b/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java @@ -25,10 +25,10 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.net.URLDecoder; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import junit.framework.TestCase; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; /** @@ -49,17 +49,7 @@ public abstract class BaseDBTestCase extends TestCase { protected static File getDataDirectory() throws IOException { String fileName = Settings.getString(Settings.KEYS.CVE_INDEX); - String filePath = Index.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - String decodedPath = URLDecoder.decode(filePath, "UTF-8"); - File exePath = new File(decodedPath); - if (exePath.getName().toLowerCase().endsWith(".jar")) { - exePath = exePath.getParentFile(); - } else { - exePath = new File("."); - } - File path = new File(exePath.getCanonicalFile() + File.separator + fileName); - path = new File(path.getCanonicalPath()); - return path; + return FileUtils.getDataDirectory(fileName, Index.class); } public static void ensureDBExists() throws Exception {