aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsimonbrandhof <simon.brandhof@gmail.com>2010-11-09 14:36:57 +0000
committersimonbrandhof <simon.brandhof@gmail.com>2010-11-09 14:36:57 +0000
commitf24c8ebe314d5278287558577aafb790fea98bd4 (patch)
tree8ddbf6acf4342adc29e9b3e0b77993e0b1f4ceea
parentb064bef048b04fc3b5d6ca4dfe6311bf90230836 (diff)
downloadsonarqube-f24c8ebe314d5278287558577aafb790fea98bd4.tar.gz
sonarqube-f24c8ebe314d5278287558577aafb790fea98bd4.zip
SONAR-1943 Add proxy authentication support for update center
-rw-r--r--sonar-application/src/main/assembly/conf/sonar.properties21
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java110
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java27
-rw-r--r--sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java44
-rw-r--r--sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java33
5 files changed, 146 insertions, 89 deletions
diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties
index 8702cdb73a7..6aeedbba695 100644
--- a/sonar-application/src/main/assembly/conf/sonar.properties
+++ b/sonar-application/src/main/assembly/conf/sonar.properties
@@ -112,9 +112,20 @@ sonar.jdbc.timeBetweenEvictionRunsMillis: 30000
#---------------------------------------------------------
# The Update Center requires an internet connection to request http://update.sonarsource.org
-# If needed, HTTP proxy can be configured with standard Java environment variables : -Dhttp.proxyHost
-# and -Dhttp.proxyPort. System configuration can also be used with -Djava.net.useSystemProxies=true.
-# These properties can not be set in this file.
-
-# Update Center is activated by default.
+# It is activated by default:
#sonar.updatecenter.activate=true
+
+# HTTP proxy (default none)
+#http.proxyHost=
+#http.proxyPort=
+
+# NT domain name if NTLM proxy is used
+#http.auth.ntlm.domain=
+
+# SOCKS proxy (default none)
+#socksProxyHost=
+#socksProxyPort=
+
+# proxy authentication. The 2 following properties are used for HTTP and SOCKS proxies.
+#http.proxyUser=
+#http.proxyPassword= \ No newline at end of file
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java
index 670707c3f0c..7b0e96a11ca 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java
@@ -19,6 +19,10 @@
*/
package org.sonar.api.utils;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.LoggerFactory;
@@ -30,25 +34,93 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URI;
+import java.net.*;
+import java.util.List;
/**
- * Simple class to download a file from a HTTP repository.
- *
+ * This component downloads HTTP files. It currently does not reuse maven proxy configuration on the batch side.
+ *
* @since 2.2
*/
public class HttpDownloader implements BatchComponent, ServerComponent {
public static final int TIMEOUT_MILLISECONDS = 20 * 1000;
+
+ private String userAgent;
+
+ public HttpDownloader(Server server, Configuration configuration) {
+ this(configuration, server.getVersion());
+ }
+
+ public HttpDownloader(Configuration configuration) {
+ this(configuration, null);
+ }
+
+ /**
+ * for unit tests
+ */
+ HttpDownloader() {
+ this(new PropertiesConfiguration(), null);
+ }
- private Server server = null;
+ private HttpDownloader(Configuration configuration, String userAgent) {
+ initProxy(configuration);
+ initUserAgent(userAgent);
+ }
+
+ private void initProxy(Configuration configuration) {
+ propagateProxySystemProperties(configuration);
+ if (requiresProxyAuthentication(configuration)) {
+ registerProxyCredentials(configuration);
+ }
+ }
- public HttpDownloader(Server server) {
- this.server = server;
+ private void initUserAgent(String sonarVersion) {
+ String userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion));
+ System.setProperty("http.agent", userAgent);
+ this.userAgent = userAgent;
}
- public HttpDownloader() {
+ public String getProxySynthesis(URI uri) {
+ return getProxySynthesis(uri, ProxySelector.getDefault());
+ }
+
+ static String getProxySynthesis(URI uri, ProxySelector proxySelector) {
+ List<String> descriptions = Lists.newArrayList();
+ List<Proxy> proxies = proxySelector.select(uri);
+ if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) {
+ descriptions.add("no proxy");
+ } else {
+ for (Proxy proxy : proxies) {
+ if (!proxy.type().equals(Proxy.Type.DIRECT)) {
+ descriptions.add("proxy: " + proxy.address().toString());
+ }
+ }
+ }
+ return Joiner.on(", ").join(descriptions);
+ }
+
+ private void registerProxyCredentials(Configuration configuration) {
+ Authenticator.setDefault(new ProxyAuthenticator(configuration.getString("http.proxyUser"), configuration.getString("http.proxyPassword")));
+ }
+
+ private boolean requiresProxyAuthentication(Configuration configuration) {
+ return configuration.getString("http.proxyUser") != null;
+ }
+
+ private void propagateProxySystemProperties(Configuration configuration) {
+ propagateSystemProperty(configuration, "http.proxyHost");
+ propagateSystemProperty(configuration, "http.proxyPort");
+ propagateSystemProperty(configuration, "http.nonProxyHosts");
+ propagateSystemProperty(configuration, "http.auth.ntlm.domain");
+ propagateSystemProperty(configuration, "socksProxyHost");
+ propagateSystemProperty(configuration, "socksProxyPort");
+ }
+
+ private void propagateSystemProperty(Configuration configuration, String key) {
+ if (configuration.getString(key) != null) {
+ System.setProperty(key, configuration.getString(key));
+ }
}
public void download(URI uri, File toFile) {
@@ -63,7 +135,7 @@ public class HttpDownloader implements BatchComponent, ServerComponent {
} catch (Exception e) {
IOUtils.closeQuietly(output);
FileUtils.deleteQuietly(toFile);
- throw new SonarException("Fail to download the file: " + uri, e);
+ throw new SonarException("Fail to download the file: " + uri + getProxySynthesis(uri), e);
} finally {
IOUtils.closeQuietly(input);
@@ -79,7 +151,7 @@ public class HttpDownloader implements BatchComponent, ServerComponent {
return IOUtils.toByteArray(input);
} catch (Exception e) {
- throw new SonarException("Fail to download the file: " + uri, e);
+ throw new SonarException("Fail to download the file: " + uri + getProxySynthesis(uri), e);
} finally {
IOUtils.closeQuietly(input);
@@ -92,22 +164,30 @@ public class HttpDownloader implements BatchComponent, ServerComponent {
return connection.getInputStream();
} catch (Exception e) {
- throw new SonarException("Fail to download the file: " + uri, e);
+ throw new SonarException("Fail to download the file: " + uri + getProxySynthesis(uri), e);
}
}
private HttpURLConnection newHttpConnection(URI uri) throws IOException {
- LoggerFactory.getLogger(getClass()).info("Download: " + uri);
+ LoggerFactory.getLogger(getClass()).info("Download: " + uri + getProxySynthesis(uri));
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
connection.setConnectTimeout(TIMEOUT_MILLISECONDS);
connection.setReadTimeout(TIMEOUT_MILLISECONDS);
connection.setUseCaches(true);
- connection.setRequestProperty("User-Agent", getUserAgent());
connection.setInstanceFollowRedirects(true);
+ connection.setRequestProperty("User-Agent", userAgent);
return connection;
}
+}
+
+class ProxyAuthenticator extends Authenticator {
+ private PasswordAuthentication auth;
+
+ ProxyAuthenticator(String user, String password) {
+ auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray());
+ }
- private String getUserAgent() {
- return (server != null ? "Sonar " + server.getVersion() : "Sonar");
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return auth;
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java
index 9b89c49ce72..a61c858516c 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java
@@ -19,6 +19,7 @@
*/
package org.sonar.api.utils;
+import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.After;
@@ -29,14 +30,15 @@ import org.sonar.api.platform.Server;
import java.io.File;
import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.net.*;
+import java.util.Arrays;
import java.util.Properties;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.internal.matchers.StringContains.containsString;
+import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -104,7 +106,7 @@ public class HttpDownloaderTest {
Server server = mock(Server.class);
when(server.getVersion()).thenReturn("2.2");
- byte[] bytes = new HttpDownloader(server).download(new URI(baseUrl));
+ byte[] bytes = new HttpDownloader(server, new PropertiesConfiguration()).download(new URI(baseUrl));
Properties props = new Properties();
props.load(IOUtils.toInputStream(new String(bytes)));
assertThat(props.getProperty("agent"), is("Sonar 2.2"));
@@ -114,6 +116,25 @@ public class HttpDownloaderTest {
public void followRedirect() throws URISyntaxException {
byte[] bytes = new HttpDownloader().download(new URI(baseUrl + "/redirect/"));
assertThat(new String(bytes), containsString("count"));
+ }
+
+ @Test
+ public void shouldGetDirectProxySynthesis() throws URISyntaxException {
+ ProxySelector proxySelector = mock(ProxySelector.class);
+ when(proxySelector.select((URI)anyObject())).thenReturn(Arrays.asList(Proxy.NO_PROXY));
+ assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector), is("no proxy"));
+ }
+
+ @Test
+ public void shouldGetProxySynthesis() throws URISyntaxException {
+ ProxySelector proxySelector = mock(ProxySelector.class);
+ when(proxySelector.select((URI)anyObject())).thenReturn(Arrays.asList((Proxy)new FakeProxy()));
+ assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector), is("proxy: http://proxy_url:4040"));
+ }
+}
+class FakeProxy extends Proxy {
+ public FakeProxy() {
+ super(Type.HTTP, new InetSocketAddress("http://proxy_url", 4040));
}
}
diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java b/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java
index 84e2c8707ca..a85570f1a01 100644
--- a/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java
+++ b/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java
@@ -19,25 +19,19 @@
*/
package org.sonar.server.plugins;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.io.IOUtils;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerComponent;
import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.Logs;
-import org.sonar.api.utils.SonarException;
import org.sonar.updatecenter.common.UpdateCenter;
import org.sonar.updatecenter.common.UpdateCenterDeserializer;
import java.io.InputStream;
-import java.net.Proxy;
-import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
-import java.util.List;
import java.util.Properties;
/**
@@ -51,7 +45,7 @@ public class UpdateCenterClient implements ServerComponent {
public static final String DEFAULT_URL = "http://update.sonarsource.org/update-center.properties";
public static final int PERIOD_IN_MILLISECONDS = 60 * 60 * 1000;
- private String url;
+ private URI uri;
private UpdateCenter center = null;
private long lastRefreshDate = 0;
private HttpDownloader downloader;
@@ -59,14 +53,14 @@ public class UpdateCenterClient implements ServerComponent {
/**
* for unit tests
*/
- UpdateCenterClient(HttpDownloader downloader, String url) {
+ UpdateCenterClient(HttpDownloader downloader, URI uri) {
this.downloader = downloader;
- this.url = url;
- Logs.INFO.info("Update center: " + url + " (" + sumUpProxyConfiguration(url) + ")");
+ this.uri = uri;
+ Logs.INFO.info("Update center: " + uri + " (" + downloader.getProxySynthesis(uri) + ")");
}
- public UpdateCenterClient(HttpDownloader downloader, Configuration configuration) {
- this(downloader, configuration.getString(URL_PROPERTY, DEFAULT_URL));
+ public UpdateCenterClient(HttpDownloader downloader, Configuration configuration) throws URISyntaxException {
+ this(downloader, new URI(configuration.getString(URL_PROPERTY, DEFAULT_URL)));
}
public UpdateCenter getCenter() {
@@ -92,7 +86,7 @@ public class UpdateCenterClient implements ServerComponent {
private UpdateCenter download() {
InputStream input = null;
try {
- input = downloader.openStream(new URI(url));
+ input = downloader.openStream(uri);
if (input != null) {
Properties properties = new Properties();
properties.load(input);
@@ -107,28 +101,4 @@ public class UpdateCenterClient implements ServerComponent {
}
return null;
}
-
- private static String sumUpProxyConfiguration(String url) {
- return sumUpProxyConfiguration(url, ProxySelector.getDefault());
- }
-
- static String sumUpProxyConfiguration(String url, ProxySelector proxySelector) {
- try {
- List<String> descriptions = Lists.newArrayList();
- List<Proxy> proxies = proxySelector.select(new URI(url));
- if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) {
- descriptions.add("no HTTP proxy");
- } else {
- for (Proxy proxy : proxies) {
- if (!proxy.type().equals(Proxy.Type.DIRECT)) {
- descriptions.add("proxy: " + proxy.address().toString());
- }
- }
- }
- return Joiner.on(", ").join(descriptions);
-
- } catch (URISyntaxException e) {
- throw new SonarException("Can not load configuration of HTTP proxies");
- }
- }
}
diff --git a/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java b/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java
index 1186e26e252..1031c88fd23 100644
--- a/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java
@@ -24,15 +24,13 @@ import org.junit.Before;
import org.junit.Test;
import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.SonarException;
-import org.sonar.server.plugins.UpdateCenterClient;
import org.sonar.updatecenter.common.UpdateCenter;
import org.sonar.updatecenter.common.Version;
-import java.net.*;
-import java.util.Arrays;
+import java.net.URI;
+import java.net.URISyntaxException;
import static junit.framework.Assert.assertNull;
-import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.internal.matchers.IsCollectionContaining.hasItems;
import static org.mockito.Matchers.anyObject;
@@ -47,7 +45,7 @@ public class UpdateCenterClientTest {
@Before
public void startServer() throws Exception {
downloader = mock(HttpDownloader.class);
- client = new UpdateCenterClient(downloader, BASE_URL);
+ client = new UpdateCenterClient(downloader, new URI(BASE_URL));
}
@Test
@@ -84,27 +82,4 @@ public class UpdateCenterClientTest {
verify(downloader, times(2)).openStream(new URI(BASE_URL));
}
-
- @Test
- public void shouldSumUpDirectProxyConfiguration() {
- ProxySelector proxySelector = mock(ProxySelector.class);
- when(proxySelector.select((URI)anyObject())).thenReturn(Arrays.asList(Proxy.NO_PROXY));
- assertThat(UpdateCenterClient.sumUpProxyConfiguration("http://updatecenter", proxySelector), is("no HTTP proxy"));
- }
-
- @Test
- public void shouldSumUpProxyConfiguration() {
- ProxySelector proxySelector = mock(ProxySelector.class);
- when(proxySelector.select((URI)anyObject())).thenReturn(Arrays.asList((Proxy)new FakeProxy()));
- assertThat(UpdateCenterClient.sumUpProxyConfiguration("http://updatecenter", proxySelector), is("proxy: http://updatecenter:80"));
- }
-
-
-}
-
-class FakeProxy extends Proxy {
-
- public FakeProxy() {
- super(Type.HTTP, new InetSocketAddress("http://updatecenter", 80));
- }
-}
+} \ No newline at end of file