Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions ant/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>io.github.jeremylong</groupId>
<artifactId>jcs3-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
*/
package org.owasp.dependencycheck.taskdefs;

import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -128,9 +127,6 @@ public final void execute() throws BuildException {
* Hacky method of muting the noisy logging from JCS.
*/
private void muteNoisyLoggers() {
System.setProperty("jcs.logSystem", "slf4j");
Slf4jAdapter.muteLogging(true);

final String[] noisyLoggers = {
"org.apache.hc"
};
Expand Down
43 changes: 16 additions & 27 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<archive>
<manifest>
<mainClass>org.owasp.dependencycheck.App</mainClass>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>org.owasp.dependencycheck.PluginLoader</Premain-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
Expand All @@ -79,6 +83,11 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<program>
<mainClass>org.owasp.dependencycheck.App</mainClass>
<id>dependency-check</id>
<commandLineArguments>
<commandLineArgument>-javaagent:@REPO@/${project.artifactId}-${project.version}.jar=@BASEDIR@/plugins</commandLineArgument>
<commandLineArgument>-jar</commandLineArgument>
<commandLineArgument>@REPO@/${project.artifactId}-${project.version}.jar</commandLineArgument>
</commandLineArguments>
</program>
</programs>
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
Expand All @@ -88,10 +97,8 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
</binFileExtensions>
<repositoryLayout>flat</repositoryLayout>
<repositoryName>lib</repositoryName>
<useWildcardClassPath>true</useWildcardClassPath>
<configurationDirectory>plugins/*</configurationDirectory>
<includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
<unixScriptTemplate>${project.basedir}/src/main/conf/unixBinTemplate</unixScriptTemplate>
<unixScriptTemplate>${project.basedir}/src/main/conf/unixBinTemplate.sh</unixScriptTemplate>
<windowsScriptTemplate>${project.basedir}/src/main/conf/windowsBinTemplate.bat</windowsScriptTemplate>
<!--
enable-native-access=ALL-UNNAMED
Java 21+: Needed by Lucene indexes unless we do -Dorg.apache.lucene.store.MMapDirectory.enableMemorySegments=false
Expand All @@ -110,25 +117,6 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>fix-windows-shell-script</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<!-- Hack/workaround for https://github.com/mojohaus/appassembler/issues/114 -->
<target>
<replace file="${project.build.directory}/release/bin/dependency-check.bat" token="%JAVACMD% %JAVA_OPTS%" value="&quot;%JAVACMD%&quot; %JAVA_OPTS%" failOnNoReplacements="true" />
</target>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
Expand Down Expand Up @@ -179,10 +167,6 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>io.github.jeremylong</groupId>
<artifactId>jcs3-slf4j</artifactId>
</dependency>
<dependency>
<!-- not visible in imports due to method chaining, but App code uses classes from this library -->
<groupId>io.github.jeremylong</groupId>
Expand All @@ -202,5 +186,10 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ fi
# For Cygwin and MINGW, ensure paths are in UNIX format before anything is touched
if $cygwin || $mingw; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi

# If a specific java binary isn't specified search for the standard 'java' binary
Expand Down Expand Up @@ -81,20 +80,8 @@ then
REPO="$BASEDIR"/@REPO@
fi

CLASSPATH=@CLASSPATH@

ENDORSED_DIR=@ENDORSED_DIR@
if [ -n "$ENDORSED_DIR" ] ; then
CLASSPATH=$BASEDIR/$ENDORSED_DIR/*:$CLASSPATH
fi

if [ -n "$CLASSPATH_PREFIX" ] ; then
CLASSPATH=$CLASSPATH_PREFIX:$CLASSPATH
fi

# For Cygwin and Mingw, switch paths to Windows format before running java
if $cygwin || $mingw; then
[ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
[ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
Expand All @@ -110,11 +97,9 @@ fi
done

exec "$JAVACMD" $JAVA_OPTS $DEBUG @EXTRA_JVM_ARGUMENTS@ \
-classpath "$CLASSPATH" \
-Dapp.name="@APP_NAME@" \
-Dapp.pid="$$" \
-Dapp.repo="$REPO" \
-Dapp.home="$BASEDIR" \
-Dbasedir="$BASEDIR" \
@MAINCLASS@ \
@APP_ARGUMENTS@"$@"@UNIX_BACKGROUND@
88 changes: 88 additions & 0 deletions cli/src/main/conf/windowsBinTemplate.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#LICENSE_HEADER#
@echo off

set ERROR_CODE=0

:init
@REM Decide how to startup depending on the version of windows

@REM -- Win98ME
if NOT "%OS%"=="Windows_NT" goto Win9xArg

@REM set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" @setlocal

@REM -- 4NT shell
if "%eval[2+2]" == "4" goto 4NTArgs

@REM -- Regular WinNT shell
set CMD_LINE_ARGS=%*
goto WinNTGetScriptDir

@REM The 4NT Shell from jp software
:4NTArgs
set CMD_LINE_ARGS=%$
goto WinNTGetScriptDir

:Win9xArg
@REM Slurp the command line arguments. This loop allows for an unlimited number
@REM of arguments (up to the command line limit, anyway).
set CMD_LINE_ARGS=
:Win9xApp
if %1a==a goto Win9xGetScriptDir
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto Win9xApp

:Win9xGetScriptDir
set SAVEDIR=%CD%
%0\
cd %0\..\..
set BASEDIR=%CD%
cd %SAVEDIR%
set SAVE_DIR=
goto repoSetup

:WinNTGetScriptDir
for %%i in ("%~dp0..") do set "BASEDIR=%%~fi"

:repoSetup
set REPO=
#ENV_SETUP#

if "%JAVACMD%"=="" set JAVACMD=#JAVA_BINARY#

if "%REPO%"=="" set REPO=%BASEDIR%\#REPO#

@REM Reaching here means variables are defined and arguments have been captured
:endInit

"%JAVACMD%" %JAVA_OPTS% #EXTRA_JVM_ARGUMENTS# -Dapp.name="#APP_NAME#" -Dapp.repo="%REPO%" -Dapp.home="%BASEDIR%" -Dbasedir="%BASEDIR%" #APP_ARGUMENTS#%CMD_LINE_ARGS%
if %ERRORLEVEL% NEQ 0 goto error
goto end

:error
if "%OS%"=="Windows_NT" @endlocal
set ERROR_CODE=%ERRORLEVEL%

:end
@REM set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" goto endNT

@REM For old DOS remove the set variables from ENV - we assume they were not set
@REM before we started - at least we don't leave any baggage around
set CMD_LINE_ARGS=
goto postExec

:endNT
@REM If error code is set to 1 then the endlocal was done already in :error.
if %ERROR_CODE% EQU 0 @endlocal


:postExec

if "%FORCE_EXIT_ON_ERROR%" == "on" (
if %ERROR_CODE% NEQ 0 exit %ERROR_CODE%
)

exit /B %ERROR_CODE%
4 changes: 0 additions & 4 deletions cli/src/main/java/org/owasp/dependencycheck/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ public class App {
*/
@SuppressWarnings("squid:S4823")
public static void main(String[] args) {
System.setProperty("jcs.logSystem", "slf4j");
if (!LOGGER.isDebugEnabled()) {
Slf4jAdapter.muteLogging(true);
}
final int exitCode;
final App app = new App();
exitCode = app.run(args);
Expand Down
38 changes: 38 additions & 0 deletions cli/src/main/java/org/owasp/dependencycheck/PluginLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.owasp.dependencycheck;

import java.io.File;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;

/**
* Java agent for loading plugin JARs from a specified directory into the system classpath
* before the main application starts. This allows additional plugins to be available at runtime
* by appending their JAR files to the system class loader search path; while allowing use of an
* executable jar with deterministic classpath ordering.
* <p/>
* To use, specify this class as a Java agent and provide the plugins directory as the -javaagent argument
*/
public class PluginLoader {
/**
* Java agent entry point. Loads all JAR files from the specified plugins directory
* and appends them to the system class loader search path.
*
* @param agentArg the path to the plugins directory containing JAR files to load, e.g `-javaagent:cli.jar=/usr/share/dependency-check/plugins`
* @param inst the instrumentation instance provided by the JVM
*/
public static void premain(String agentArg, Instrumentation inst) {
File pluginsDir = new File(agentArg);
if (pluginsDir.isDirectory()) {
File[] files = pluginsDir.listFiles((dir, name) -> name.endsWith(".jar"));
for (File file : files == null ? new File[0] : files) {
try (JarFile jar = new JarFile(file)) {
inst.appendToSystemClassLoaderSearch(jar);
} catch (IOException e) {
System.err.printf("[WARN] Failed to read plugin jar file at %s. Jar will not be available on classpath: %s%n", file, e);
e.printStackTrace(System.err);
}
}
}
}
}
2 changes: 1 addition & 1 deletion cli/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</appender>

<logger name="org.apache.lucene" level="ERROR" />
<logger name="org.apache.commons.jcs" level="ERROR" />
<logger name="org.apache.commons.jcs3" level="FATAL" />
<logger name="org.apache.hc" level="ERROR" />

<root level="INFO">
Expand Down
72 changes: 72 additions & 0 deletions cli/src/test/java/org/owasp/dependencycheck/PluginLoaderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.owasp.dependencycheck;

import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.instrument.Instrumentation;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.regex.Pattern;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.matchesPattern;
import static org.mockito.ArgumentMatchers.assertArg;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

class PluginLoaderTest {

private final Instrumentation instrumentation = Mockito.mock(Instrumentation.class);

@TempDir
Path tempDir;

@Test
void shouldDoNothingIfDirectoryDoesntExist() {
PluginLoader.premain("blah", instrumentation);
verifyNoInteractions(instrumentation);
}

@Test
void shouldDoNothingIfDirectoryIsEmpty() {
PluginLoader.premain(tempDir.toString(), instrumentation);
verifyNoInteractions(instrumentation);
}

@Test
void shouldAddJarToClassPath() throws Exception {
createEmptyValidJar();
createEmptyValidJar();
PluginLoader.premain(tempDir.toString(), instrumentation);
verify(instrumentation, times(2))
.appendToSystemClassLoaderSearch(assertArg(jar -> assertThat(jar.getName(), matchesPattern(".*/dummy.*\\.jar"))));
}

@Test
void shouldStopLoadingPluginsOnBadJarButSucceed() throws Exception {
PrintStream originalErr = System.err;
ByteArrayOutputStream errContent = new ByteArrayOutputStream();
System.setErr(new PrintStream(errContent));
try {
createEmptyBadJar();
PluginLoader.premain(tempDir.toString(), instrumentation);
assertThat(errContent.toString(), matchesPattern(Pattern.compile("\\[WARN\\] Failed to read plugin jar file at .*/dummy.*\\.jar\\. Jar will not be available on classpath.*zip file is empty.*", Pattern.DOTALL)));
} finally {
System.setErr(originalErr);
}
}

private Path createEmptyBadJar() throws IOException {
return Files.createTempFile(tempDir, "dummy", ".jar");
}

private void createEmptyValidJar() throws IOException {
new ZipArchiveOutputStream(createEmptyBadJar().toFile()).close();
}
}
10 changes: 5 additions & 5 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<groupId>org.whitesource</groupId>
<artifactId>pecoff4j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jcs3-core</artifactId>
</dependency>
<!-- JCS 3 logging adapter; intentionally higher on classpath than JCS itself -->
<dependency>
<groupId>io.github.jeremylong</groupId>
<artifactId>jcs3-slf4j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jcs3-core</artifactId>
</dependency>
<dependency>
<groupId>com.github.package-url</groupId>
Expand Down
Loading