Skip to content

Commit

Permalink
SCANMAVEN-183 The scanner for Maven takes HTTPS proxies into account (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dorian-burihabwa-sonarsource committed May 16, 2024
1 parent dd5762e commit be505e3
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
*/
package org.sonarsource.scanner.maven.bootstrap;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecution;
Expand All @@ -32,6 +36,8 @@
import org.sonarsource.scanner.api.LogOutput;

public class ScannerFactory {
private static final String UNKNOWN_PROXY_PROTOCOL_MESSAGE = "Setting proxy properties:" +
" one or multiple protocols of the active proxy (id: %s) are not supported (protocols: %s).";

private final LogOutput logOutput;
private final RuntimeInformation runtimeInformation;
Expand Down Expand Up @@ -77,16 +83,53 @@ public Map<String, String> createGlobalProperties() {
return p;
}

/**
* Set proxy properties from Maven settings
*/
public void setProxySystemProperties() {
Proxy activeProxy = session.getSettings().getActiveProxy();
if (activeProxy == null) {
log.debug("Skipping proxy settings: No active proxy detected.");
return;
}

String protocol = activeProxy.getProtocol();
if (protocol == null) {
log.warn("Skipping proxy settings: an active proxy was detected (id: " + activeProxy.getId() + ") but the protocol is null.");
return;
}

Set<String> protocols = Arrays.stream(activeProxy.getProtocol().trim().split("\\|"))
.map(proto -> proto.trim().toLowerCase(Locale.ROOT))
.filter(proto -> !proto.isEmpty())
.collect(Collectors.toSet());

if (protocols.isEmpty()) {
log.warn("Skipping proxy settings: an active proxy was detected (id: " + activeProxy.getId() + ") but the protocol was not recognized.");
return;
}

if (activeProxy != null && activeProxy.getProtocol() != null && activeProxy.getProtocol().contains("http")) {
log.debug("Setting proxy properties");
log.debug("Setting proxy properties");
if (protocols.remove("http")) {
System.setProperty("http.proxyHost", activeProxy.getHost());
System.setProperty("http.proxyPort", String.valueOf(activeProxy.getPort()));
System.setProperty("http.proxyUser", StringUtils.defaultString(activeProxy.getUsername(), ""));
System.setProperty("http.proxyPassword", StringUtils.defaultString(activeProxy.getPassword(), ""));
System.setProperty("http.nonProxyHosts", StringUtils.defaultString(activeProxy.getNonProxyHosts(), ""));
setCommonHttpProperties(activeProxy);
}
if (protocols.remove("https")) {
System.setProperty("https.proxyHost", activeProxy.getHost());
System.setProperty("https.proxyPort", String.valueOf(activeProxy.getPort()));
setCommonHttpProperties(activeProxy);
}

if (!protocols.isEmpty()) {
String remainingProtocols = String.join(", ", protocols);
log.warn(String.format(UNKNOWN_PROXY_PROTOCOL_MESSAGE, activeProxy.getId(), remainingProtocols));
}
}

private static void setCommonHttpProperties(Proxy proxy) {
System.setProperty("http.proxyUser", StringUtils.defaultString(proxy.getUsername(), ""));
System.setProperty("http.proxyPassword", StringUtils.defaultString(proxy.getPassword(), ""));
System.setProperty("http.nonProxyHosts", StringUtils.defaultString(proxy.getNonProxyHosts(), ""));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import java.util.Collections;
import java.util.Properties;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.rtinfo.RuntimeInformation;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.logging.console.ConsoleLogger;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -39,6 +41,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand All @@ -51,6 +55,8 @@ class ScannerFactoryTest {
private PropertyDecryptor propertyDecryptor;
private Properties envProps;

private Proxy httpsProxy;

@BeforeEach
public void setUp() {
logOutput = mock(LogOutput.class);
Expand All @@ -75,23 +81,35 @@ public void setUp() {
when(rootProject.getProperties()).thenReturn(root);
when(mavenSession.getCurrentProject()).thenReturn(rootProject);
propertyDecryptor = new PropertyDecryptor(mock(Log.class), mock(SecDispatcher.class));

// Set up default proxy
httpsProxy = new Proxy();
httpsProxy.setActive(true);
httpsProxy.setProtocol("https");
httpsProxy.setPort(443);
httpsProxy.setHost("myhost");
httpsProxy.setUsername("toto");
httpsProxy.setPassword("some-secret");
httpsProxy.setNonProxyHosts("sonarcloud.io|*.sonarsource.com");
}

@AfterEach
@BeforeEach
public void clearProxyProperties() {
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
System.clearProperty("https.proxyHost");
System.clearProperty("https.proxyPort");
System.clearProperty("http.proxyUser");
System.clearProperty("http.proxyPassword");
System.clearProperty("http.nonProxyHosts");
}

@Test
void testProxy() {
void http_proxy_properties_are_derived_from_maven_settings() {
Proxy proxy = new Proxy();
proxy.setActive(true);
proxy.setProtocol("https");
proxy.setProtocol("http");
proxy.setHost("myhost");
Settings settings = new Settings();
settings.setProxies(Collections.singletonList(proxy));
Expand All @@ -101,6 +119,123 @@ void testProxy() {
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();
assertThat(System.getProperty("http.proxyHost")).isEqualTo("myhost");
assertThat(System.getProperty("https.proxyHost")).isNull();
}

@Test
void https_proxy_properties_are_derived_from_maven_settings() {
Settings settings = new Settings();
settings.setProxies(Collections.singletonList(httpsProxy));
when(mavenSession.getSettings()).thenReturn(settings);

Log log = mock(Log.class);
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();
assertThat(System.getProperty("https.proxyHost")).isEqualTo("myhost");
assertThat(System.getProperty("https.proxyPort")).isEqualTo("443");
assertThat(System.getProperty("http.proxyUser")).isEqualTo("toto");
assertThat(System.getProperty("http.proxyPassword")).isEqualTo("some-secret");
assertThat(System.getProperty("http.nonProxyHosts")).isEqualTo("sonarcloud.io|*.sonarsource.com");

assertThat(System.getProperty("http.proxyHost")).isNull();
assertThat(System.getProperty("http.proxyPort")).isNull();
}


@Test
void http_and_https_proxy_properties_are_derived_from_maven_settings() {
Proxy proxyWithBothProtocols = httpsProxy.clone();
proxyWithBothProtocols.setProtocol("http|https");
Settings settings = new Settings();
settings.setProxies(Collections.singletonList(proxyWithBothProtocols));
when(mavenSession.getSettings()).thenReturn(settings);

Log log = mock(Log.class);
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();
assertThat(System.getProperty("https.proxyHost")).isEqualTo("myhost");
assertThat(System.getProperty("https.proxyPort")).isEqualTo("443");
assertThat(System.getProperty("http.proxyHost")).isEqualTo("myhost");
assertThat(System.getProperty("http.proxyPort")).isEqualTo("443");
assertThat(System.getProperty("http.proxyUser")).isEqualTo("toto");
assertThat(System.getProperty("http.proxyPassword")).isEqualTo("some-secret");
assertThat(System.getProperty("http.nonProxyHosts")).isEqualTo("sonarcloud.io|*.sonarsource.com");
}

@Test
void proxy_properties_are_not_set_when_no_active_proxy_is_provided() {
Settings settings = new Settings();
when(mavenSession.getSettings()).thenReturn(settings);

Log log = spy(new DefaultLog(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG, "no-proxy")));
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();

assertProxySettingsAreNotSet();

verify(log, times(1)).debug("Skipping proxy settings: No active proxy detected.");
}

@Test
void proxy_properties_are_not_set_when_protocol_is_null() {
Proxy proxyWithNullProtocol = httpsProxy.clone();
proxyWithNullProtocol.setProtocol(null);
proxyWithNullProtocol.setId("null-protocol-proxy");

Settings settings = new Settings();
settings.setProxies(Collections.singletonList(proxyWithNullProtocol));
when(mavenSession.getSettings()).thenReturn(settings);

Log log = spy(new DefaultLog(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG, "null-protocol-proxy")));
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();

assertProxySettingsAreNotSet();

verify(log, times(1)).warn("Skipping proxy settings: an active proxy was detected (id: null-protocol-proxy) but the protocol is null.");
}

@Test
void proxy_properties_are_not_set_when_protocol_is_blank() {
Proxy proxyWithNullProtocol = httpsProxy.clone();
proxyWithNullProtocol.setProtocol(" | |");
proxyWithNullProtocol.setId("null-protocol-proxy");

Settings settings = new Settings();
settings.setProxies(Collections.singletonList(proxyWithNullProtocol));
when(mavenSession.getSettings()).thenReturn(settings);

Log log = spy(new DefaultLog(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG, "null-protocol-proxy")));
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();

assertProxySettingsAreNotSet();

verify(log, times(1)).warn("Skipping proxy settings: an active proxy was detected (id: null-protocol-proxy) but the protocol was not recognized.");
}

@Test
void a_warning_is_logged_when_a_proxy_protocol_is_not_supported() {
Settings settings = new Settings();
Proxy proxyWithUnrecognizableProtocol = httpsProxy.clone();
proxyWithUnrecognizableProtocol.setId("unknown-protocol-proxy");
proxyWithUnrecognizableProtocol.setProtocol("unknown-proto|https");
settings.setProxies(Collections.singletonList(proxyWithUnrecognizableProtocol));
when(mavenSession.getSettings()).thenReturn(settings);

Log log = spy(new DefaultLog(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG, "unrecognizable-protocol")));
ScannerFactory factory = new ScannerFactory(logOutput, log, runtimeInformation, mojoExecution, mavenSession, envProps, propertyDecryptor);
factory.create();

assertThat(System.getProperty("https.proxyHost")).isEqualTo("myhost");
assertThat(System.getProperty("https.proxyPort")).isEqualTo("443");
assertThat(System.getProperty("http.proxyUser")).isEqualTo("toto");
assertThat(System.getProperty("http.proxyPassword")).isEqualTo("some-secret");
assertThat(System.getProperty("http.nonProxyHosts")).isEqualTo("sonarcloud.io|*.sonarsource.com");

verify(log, times(1)).isDebugEnabled();
verify(log, times(1)).debug("Setting proxy properties");
verify(log, times(1)).warn("Setting proxy properties: one or multiple protocols of the active proxy (id: unknown-protocol-proxy) are not supported (protocols: unknown-proto).");
}

@Test
Expand Down Expand Up @@ -130,4 +265,14 @@ void testDebug() {
assertThat(scannerDebug.globalProperties()).contains(entry("sonar.verbose", "true"));
assertThat(scanner.globalProperties()).doesNotContain(entry("sonar.verbose", "true"));
}

static void assertProxySettingsAreNotSet() {
assertThat(System.getProperty("https.proxyHost")).isNull();
assertThat(System.getProperty("https.proxyPort")).isNull();
assertThat(System.getProperty("http.proxyUser")).isNull();
assertThat(System.getProperty("http.proxyPassword")).isNull();
assertThat(System.getProperty("http.nonProxyHosts")).isNull();
assertThat(System.getProperty("http.proxyHost")).isNull();
assertThat(System.getProperty("http.proxyPort")).isNull();
}
}

0 comments on commit be505e3

Please sign in to comment.