From 20570f275c8a996939c264bf032615554e784fc5 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Thu, 10 Mar 2016 23:14:01 +0100 Subject: [PATCH] SONAR-7465 Support encryption of HTTP proxy properties Removing the calls to Settings.getProperties() as it keeps encrypted properties values. --- .../core/util/DefaultHttpDownloader.java | 75 +++++++++---------- .../core/util/DefaultHttpDownloaderTest.java | 48 +++++++++++- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java b/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java index 13e27f72a43..69c2f14aa4a 100644 --- a/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java +++ b/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java @@ -19,7 +19,6 @@ */ package org.sonar.core.util; - import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Strings; @@ -41,7 +40,6 @@ import java.net.URI; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.List; -import java.util.Map; import java.util.zip.GZIPInputStream; import javax.annotation.Nullable; import org.apache.commons.codec.binary.Base64; @@ -52,6 +50,7 @@ import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.SonarException; import org.sonar.api.utils.log.Loggers; +import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.sonar.core.util.FileUtils.deleteQuietly; /** @@ -60,6 +59,7 @@ import static org.sonar.core.util.FileUtils.deleteQuietly; * @since 2.2 */ public class DefaultHttpDownloader extends HttpDownloader { + private final BaseHttpDownloader downloader; private final Integer readTimeout; private final Integer connectTimeout; @@ -75,7 +75,7 @@ public class DefaultHttpDownloader extends HttpDownloader { public DefaultHttpDownloader(Server server, Settings settings, @Nullable Integer connectTimeout, @Nullable Integer readTimeout) { this.readTimeout = readTimeout; this.connectTimeout = connectTimeout; - downloader = new BaseHttpDownloader(settings.getProperties(), server.getVersion()); + downloader = new BaseHttpDownloader(new ProxySystem(), settings, server.getVersion()); } public DefaultHttpDownloader(Settings settings) { @@ -89,7 +89,7 @@ public class DefaultHttpDownloader extends HttpDownloader { public DefaultHttpDownloader(Settings settings, @Nullable Integer connectTimeout, @Nullable Integer readTimeout) { this.readTimeout = readTimeout; this.connectTimeout = connectTimeout; - downloader = new BaseHttpDownloader(settings.getProperties(), null); + downloader = new BaseHttpDownloader(new ProxySystem(), settings, null); } @Override @@ -157,7 +157,17 @@ public class DefaultHttpDownloader extends HttpDownloader { throw new SonarException(String.format("Fail to download: %s (%s)", uri, getProxySynthesis(uri)), e); } - public static class BaseHttpDownloader { + static class ProxySystem { + public void setProperty(String key, String value) { + System.setProperty(key, value); + } + + public void setDefaultAuthenticator(Authenticator authenticator) { + Authenticator.setDefault(authenticator); + } + } + + static class BaseHttpDownloader { private static final String GET = "GET"; private static final String HTTP_PROXY_USER = "http.proxyUser"; @@ -169,15 +179,22 @@ public class DefaultHttpDownloader extends HttpDownloader { private String userAgent; - public BaseHttpDownloader(Map settings, @Nullable String userAgent) { - initProxy(settings); + BaseHttpDownloader(ProxySystem system, Settings settings, @Nullable String userAgent) { + initProxy(system, settings); initUserAgent(userAgent); } - private void initProxy(Map settings) { - propagateProxySystemProperties(settings); - if (requiresProxyAuthentication(settings)) { - registerProxyCredentials(settings); + private void initProxy(ProxySystem system, Settings settings) { + // propagate system properties + for (String key : PROXY_SETTINGS) { + if (settings.hasKey(key)) { + system.setProperty(key, settings.getString(key)); + } + } + // register credentials + String login = settings.getString(HTTP_PROXY_USER); + if (isNotEmpty(login)) { + system.setDefaultAuthenticator(new ProxyAuthenticator(login, settings.getString(HTTP_PROXY_PASSWORD))); } } @@ -207,24 +224,6 @@ public class DefaultHttpDownloader extends HttpDownloader { return Joiner.on(", ").join(descriptions); } - private static void registerProxyCredentials(Map settings) { - Authenticator.setDefault(new ProxyAuthenticator( - settings.get(HTTP_PROXY_USER), - settings.get(HTTP_PROXY_PASSWORD))); - } - - private boolean requiresProxyAuthentication(Map settings) { - return settings.containsKey(HTTP_PROXY_USER); - } - - private void propagateProxySystemProperties(Map settings) { - for (String key : PROXY_SETTINGS) { - if (settings.containsKey(key)) { - System.setProperty(key, settings.get(key)); - } - } - } - public InputSupplier newInputSupplier(URI uri) { return newInputSupplier(uri, GET, null, null, null, null); } @@ -357,18 +356,18 @@ public class DefaultHttpDownloader extends HttpDownloader { return resultingInputStream; } } + } - private static class ProxyAuthenticator extends Authenticator { - private final PasswordAuthentication auth; + static class ProxyAuthenticator extends Authenticator { + private final PasswordAuthentication auth; - ProxyAuthenticator(String user, String password) { - auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray()); - } + ProxyAuthenticator(String user, @Nullable String password) { + auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray()); + } - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return auth; - } + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return auth; } } diff --git a/sonar-core/src/test/java/org/sonar/core/util/DefaultHttpDownloaderTest.java b/sonar-core/src/test/java/org/sonar/core/util/DefaultHttpDownloaderTest.java index 23aa73b4fc7..d25429bbc78 100644 --- a/sonar-core/src/test/java/org/sonar/core/util/DefaultHttpDownloaderTest.java +++ b/sonar-core/src/test/java/org/sonar/core/util/DefaultHttpDownloaderTest.java @@ -22,7 +22,9 @@ package org.sonar.core.util; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.Authenticator; import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; import java.net.Proxy; import java.net.ProxySelector; import java.net.SocketAddress; @@ -33,9 +35,9 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Properties; import java.util.zip.GZIPOutputStream; - import org.hamcrest.BaseMatcher; import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -52,9 +54,13 @@ import org.simpleframework.transport.connect.SocketConnection; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; import org.sonar.api.utils.SonarException; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class DefaultHttpDownloaderTest { @@ -247,6 +253,46 @@ public class DefaultHttpDownloaderTest { String description = new DefaultHttpDownloader(new Settings()).description(new URI("http://sonarsource.org")); assertThat(description).matches("http://sonarsource.org \\(.*\\)"); } + + @Test + public void configure_http_proxy() { + DefaultHttpDownloader.ProxySystem system = mock(DefaultHttpDownloader.ProxySystem.class); + Settings settings = new Settings(); + settings.setProperty("http.proxyHost", "1.2.3.4"); + settings.setProperty("http.proxyPort", "80"); + + new DefaultHttpDownloader.BaseHttpDownloader(system, settings, null); + + verify(system).setProperty("http.proxyHost", "1.2.3.4"); + verify(system).setProperty("http.proxyPort", "80"); + verify(system, never()).setDefaultAuthenticator(any(Authenticator.class)); + } + + @Test + public void configure_http_proxy_credentials() { + DefaultHttpDownloader.ProxySystem system = mock(DefaultHttpDownloader.ProxySystem.class); + Settings settings = new Settings(); + settings.setProperty("https.proxyHost", "1.2.3.4"); + settings.setProperty("http.proxyUser", "the_login"); + settings.setProperty("http.proxyPassword", "the_passwd"); + + new DefaultHttpDownloader.BaseHttpDownloader(system, settings, null); + + verify(system).setDefaultAuthenticator(argThat(new TypeSafeMatcher() { + @Override + protected boolean matchesSafely(Authenticator authenticator) { + DefaultHttpDownloader.ProxyAuthenticator a = (DefaultHttpDownloader.ProxyAuthenticator) authenticator; + PasswordAuthentication authentication = a.getPasswordAuthentication(); + return authentication.getUserName().equals("the_login") && + new String(authentication.getPassword()).equals("the_passwd"); + } + + @Override + public void describeTo(Description description) { + } + })); + } + } class FakeProxy extends Proxy { -- 2.39.5