Skip to content

Commit

Permalink
feat: Use Maven settings decryption API for decrypting secrets from s…
Browse files Browse the repository at this point in the history
…ettings.xml (#7284)
  • Loading branch information
aikebah authored Jan 4, 2025
1 parent 538c7e6 commit 505ddff
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 79 deletions.
4 changes: 2 additions & 2 deletions maven/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<artifactId>maven-reporting-api</artifactId>
</dependency>
<dependency>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-sec-dispatcher</artifactId>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings-builder</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.building.SettingsProblem;
import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
import org.apache.maven.settings.crypto.SettingsDecrypter;
import org.apache.maven.settings.crypto.SettingsDecryptionResult;
import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate;
import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException;
Expand Down Expand Up @@ -74,12 +78,8 @@
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
Expand Down Expand Up @@ -885,11 +885,13 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
@SuppressWarnings("CanBeFinal")
@Parameter(defaultValue = "${settings}", readonly = true, required = true)
private org.apache.maven.settings.Settings settingsXml;

/**
* The security dispatcher that can decrypt passwords in the settings.xml.
* The settingsDecryptor from Maven to decrypt passwords from Settings.xml servers section
*/
@Component(role = SecDispatcher.class, hint = "default")
private SecDispatcher securityDispatcher;
@Component
private SettingsDecrypter settingsDecrypter;

/**
* The database user name.
*/
Expand Down Expand Up @@ -2559,12 +2561,15 @@ private void configureCredentials(String serverId, String usernameValue, String
* @throws InitializationException When both serverId and at least one other property value are filled.
*/
private void configureFromServer(Server server, String userKey, String passwordKey, String tokenKey, String serverId) throws InitializationException {
final SettingsDecryptionResult result = settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(server));
final String username = server.getUsername();
String password = server.getPassword();
try {
password = decryptPasswordFromSettings(password);
} catch (SecDispatcherException ex) {
password = handleSecDispatcherException("server", serverId, server.getPassword(), ex);
final String password;
if (result.getProblems().isEmpty()) {
password = result.getServer().getPassword();
} else {
logProblems(result.getProblems(), "server setting for " + serverId);
getLog().debug("Using raw password from settings.xml for server " + serverId);
password = server.getPassword();
}
if (username != null) {
if (userKey != null && passwordKey != null) {
Expand Down Expand Up @@ -2600,13 +2605,16 @@ private void setProxyServerSysPropsFromMavenProxy(Proxy mavenProxy, String proto
if (mavenProxy.getUsername() != null && !mavenProxy.getUsername().isEmpty()) {
System.setProperty(protocol + ".proxyUser", mavenProxy.getUsername());
}
String password = mavenProxy.getPassword();
final SettingsDecryptionResult result = settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(mavenProxy));
final String password;
if (result.getProblems().isEmpty()) {
password = result.getProxy().getPassword();
} else {
logProblems(result.getProblems(), "proxy settings for " + mavenProxy.getId());
getLog().debug("Using raw password from settings.xml for proxy " + mavenProxy.getId());
password = mavenProxy.getPassword();
}
if (password != null && !password.isEmpty()) {
try {
password = decryptPasswordFromSettings(password);
} catch (SecDispatcherException ex) {
password = handleSecDispatcherException("proxy", mavenProxy.getId(), password, ex);
}
System.setProperty(protocol + ".proxyPassword", password);
}
}
Expand Down Expand Up @@ -2645,62 +2653,27 @@ private void configureServerCredentialsApiKey(String serverId, String apiKeySett
}

/**
* Decrypts a password from the Maven settings if it needs to be decrypted.
* If it's not encrypted the input password will be returned unchanged.
* Logs the problems encountered during settings decryption of a {@code <}server>} or {@code <proxy>} config
* from the maven settings.<br/>
* Logs a generic message about decryption problems at WARN level. If debug logging is enabled a additional message is logged at DEBUG level
* detailing all the encountered problems and their underlying exceptions.
*
* @param password the original password value from the settings.xml
* @return the decrypted password from the Maven configuration
* @throws SecDispatcherException thrown if there is an error decrypting the
* password
*/
private String decryptPasswordFromSettings(String password) throws SecDispatcherException {
//The following fix was copied from:
// https://github.com/bsorrentino/maven-confluence-plugin/blob/master/maven-confluence-reporting-plugin/src/main/java/org/bsc/maven/confluence/plugin/AbstractBaseConfluenceMojo.java
//
// FIX to resolve
// org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException:
// java.io.FileNotFoundException: ~/.settings-security.xml (No such file or directory)
//
if (securityDispatcher instanceof DefaultSecDispatcher) {
((DefaultSecDispatcher) securityDispatcher).setConfigurationFile("~/.m2/settings-security.xml");
}

return securityDispatcher.decrypt(password);
}

/**
* Handles a SecDispatcherException that was thrown at an attempt to decrypt
* an encrypted password from the Maven settings.
*
* @param settingsElementName - "server" or "proxy"
* @param settingsElementId - value of the id attribute of the proxy resp.
* server element to which the password belongs
* @param passwordValueFromSettings - original, undecrypted password value
* from the settings
* @param ex - the Exception to handle
* @return the password fallback value to go on with, might be a not working
* one.
*/
private String handleSecDispatcherException(String settingsElementName, String settingsElementId, String passwordValueFromSettings,
SecDispatcherException ex) {
String password = passwordValueFromSettings;
if (ex.getCause() instanceof FileNotFoundException
|| (ex.getCause() != null && ex.getCause().getCause() instanceof FileNotFoundException)) {
//maybe its not encrypted?
final String tmp = passwordValueFromSettings;
if (tmp.startsWith("{") && tmp.endsWith("}")) {
getLog().error(String.format(
"Unable to decrypt the %s password for %s id '%s' in settings.xml%n\tCause: %s",
settingsElementName, settingsElementName, settingsElementId, ex.getMessage()));
} else {
password = tmp;
* @param problems The problems as reported by the settingsDecrypter.
* @param credentialDesc an identification of what was attempted to be decrypted
*/
private void logProblems(List<SettingsProblem> problems, String credentialDesc) {
final String message = "Problems while decrypting " + credentialDesc;
getLog().warn(message);
if (getLog().isDebugEnabled()) {
final StringBuilder dbgMessage = new StringBuilder("Problems while decrypting ").append(credentialDesc).append(": ");
boolean first = true;
for (SettingsProblem problem : problems) {
dbgMessage.append(first ? "" : ", ").append(problem.getMessage());
dbgMessage.append("caused by ").append(problem.getException());
first = false;
}
} else {
getLog().error(String.format(
"Unable to decrypt the %s password for %s id '%s' in settings.xml%n\tCause: %s",
settingsElementName, settingsElementName, settingsElementId, ex.getMessage()));
getLog().debug(dbgMessage.toString());
}
return password;
}

/**
Expand Down
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ Copyright (c) 2012 - Jeremy Long
<maven-plugin-annotations.version>3.15.1</maven-plugin-annotations.version>
<maven-reporting-api.version>4.0.0</maven-reporting-api.version>
<org.apache.velocity.version>2.4.1</org.apache.velocity.version>
<plexus-sec-dispatcher.version>1.4</plexus-sec-dispatcher.version>
<maven-dependency-tree.version>3.3.0</maven-dependency-tree.version>
<org.glassfish.javax.json.version>1.1.4</org.glassfish.javax.json.version>
<maven-artifact-transfer.version>0.13.1</maven-artifact-transfer.version>
Expand Down Expand Up @@ -1191,6 +1190,12 @@ Copyright (c) 2012 - Jeremy Long
<version>${maven.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings-builder</artifactId>
<version>${maven.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
Expand All @@ -1217,11 +1222,6 @@ Copyright (c) 2012 - Jeremy Long
<artifactId>velocity-engine-core</artifactId>
<version>${org.apache.velocity.version}</version>
</dependency>
<dependency>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-sec-dispatcher</artifactId>
<version>${plexus-sec-dispatcher.version}</version>
</dependency>
<!-- upgrading beyond 2.2 requires reworking the dependency resolution -->
<dependency>
<groupId>org.apache.maven.shared</groupId>
Expand Down

0 comments on commit 505ddff

Please sign in to comment.