diff --git a/cli/build.gradle b/cli/build.gradle index 490ddde5..8994bf8f 100644 --- a/cli/build.gradle +++ b/cli/build.gradle @@ -22,6 +22,7 @@ dependencies { testCompile 'junit:junit:4.12' testCompile 'com.squareup.okhttp:mockwebserver:2.4.0' testCompile 'org.assertj:assertj-core:1.7.1' // last version supporting JDK 7 + testCompile 'com.github.stefanbirkner:system-rules:1.12.0' } // create a self-contained jar that is executable diff --git a/cli/src/main/java/denominator/cli/Denominator.java b/cli/src/main/java/denominator/cli/Denominator.java index c0eaf6aa..55700bac 100644 --- a/cli/src/main/java/denominator/cli/Denominator.java +++ b/cli/src/main/java/denominator/cli/Denominator.java @@ -1,5 +1,6 @@ package denominator.cli; +import com.google.common.base.Ascii; import com.google.common.base.CaseFormat; import com.google.common.base.Charsets; import com.google.common.base.Function; @@ -23,31 +24,6 @@ import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jce.provider.X509CertParser; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.yaml.snakeyaml.Yaml; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.lang.reflect.Type; -import java.security.KeyFactory; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.inject.Singleton; - import dagger.ObjectGraph; import dagger.Provides; import denominator.Credentials; @@ -86,6 +62,30 @@ import io.airlift.airline.Help; import io.airlift.airline.Option; import io.airlift.airline.OptionType; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.provider.X509CertParser; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.yaml.snakeyaml.Yaml; + +import javax.inject.Singleton; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyFactory; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import static com.google.common.base.Preconditions.checkArgument; import static denominator.CredentialsConfiguration.credentials; @@ -274,6 +274,8 @@ public static abstract class DenominatorCommand implements Runnable { @SuppressWarnings("unchecked") public void run() { + setProxyFromEnv(); + if (providerName != null && credentialArgs != null) { credentials = ListCredentials.from(Lists.transform(credentialArgs, decodeAnyPems)); } else if (providerConfigurationName != null) { @@ -426,6 +428,34 @@ void overrideFromEnv(Map env) { } } + void setProxyFromEnv() { + setProtocolProxyFromEnv("http"); + setProtocolProxyFromEnv("https"); + } + + void setProtocolProxyFromEnv(String proto) { + String envProxy = getEnv(Ascii.toUpperCase(proto) + "_PROXY"); + if (envProxy != null && !envProxy.isEmpty()) { + try { + URL proxyUrl = new URL(envProxy); + + String proxyHost = System.getProperty(proto + ".proxyHost"); + if ((proxyHost == null || proxyHost.isEmpty())) { + System.setProperty(proto + ".proxyHost", proxyUrl.getHost()); + System.setProperty(proto + ".proxyPort", + Integer.toString( + proxyUrl.getPort() == -1 ? proxyUrl.getDefaultPort() : proxyUrl.getPort())); + } + } catch (MalformedURLException e) { + System.err.println("invalid " + proto + " proxy configuration: " + e.getMessage()); + System.exit(1); + } + } + } + String getEnv(String name) { + return System.getenv(name); + } + /** * return a lazy iterator where possible to improve the perceived responsiveness of the cli */ diff --git a/cli/src/test/java/denominator/cli/DenominatorTest.java b/cli/src/test/java/denominator/cli/DenominatorTest.java index 9d73a3d4..fa838869 100644 --- a/cli/src/test/java/denominator/cli/DenominatorTest.java +++ b/cli/src/test/java/denominator/cli/DenominatorTest.java @@ -1,21 +1,5 @@ package denominator.cli; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.IOException; -import java.net.URL; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; - import denominator.AllProfileResourceRecordSetApi; import denominator.Credentials.ListCredentials; import denominator.Credentials.MapCredentials; @@ -47,6 +31,25 @@ import denominator.model.rdata.AData; import denominator.model.rdata.CNAMEData; import denominator.route53.AliasTarget; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.Assertion; +import org.junit.contrib.java.lang.system.ExpectedSystemExit; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.contrib.java.lang.system.SystemErrRule; +import org.junit.rules.ExpectedException; + +import java.io.IOException; +import java.net.URL; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; import static denominator.assertj.ModelAssertions.assertThat; import static denominator.model.ResourceRecordSets.a; @@ -60,6 +63,17 @@ public class DenominatorTest { @Rule public final ExpectedException thrown = ExpectedException.none(); + @Rule + public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + // Use this to make sure the message logged + @Rule + public final SystemErrRule systemErrRule = new SystemErrRule().enableLog(); + + // use this to test exit occurred on malformed + @Rule + public final ExpectedSystemExit exit = ExpectedSystemExit.none(); + DNSApiManager mgr = denominator.Denominator.create(new MockProvider()); @Test // denominator providers @@ -1200,6 +1214,110 @@ public void testGeoResourceRecordSetAddRegionsBadJson() { .isEqualTo(old); } + @Test + public void testProxySettingsWithPort() { + Denominator.DenominatorCommand cmd = new Denominator.DenominatorCommand() { + @Override + protected Iterator doRun(DNSApiManager mgr) { + return null; + } + @Override + String getEnv(String name) { + if (name.equals("HTTPS_PROXY")) { + return "https://10.0.0.1:8989"; + } else if (name.equals("HTTP_PROXY")) { + return "http://localhost:7878"; + } + return null; + } + }; + cmd.setProxyFromEnv(); + assertThat(System.getProperty("http.proxyHost")).isEqualTo("localhost"); + assertThat(System.getProperty("http.proxyPort")).isEqualTo("7878"); + assertThat(System.getProperty("https.proxyHost")).isEqualTo("10.0.0.1"); + assertThat(System.getProperty("https.proxyPort")).isEqualTo("8989"); + } + @Test + public void testProxySettingsWithDefaultPorts() { + Denominator.DenominatorCommand cmd = new Denominator.DenominatorCommand() { + @Override + protected Iterator doRun(DNSApiManager mgr) { + return null; + } + @Override + String getEnv(String name) { + if (name.equals("HTTPS_PROXY")) { + return "https://10.0.0.1"; + } else if (name.equals("HTTP_PROXY")) { + return "http://localhost"; + } + return null; + } + }; + cmd.setProxyFromEnv(); + assertThat(System.getProperty("http.proxyHost")).isEqualTo("localhost"); + assertThat(System.getProperty("http.proxyPort")).isEqualTo("80"); + assertThat(System.getProperty("https.proxyHost")).isEqualTo("10.0.0.1"); + assertThat(System.getProperty("https.proxyPort")).isEqualTo("443"); + } + + @Test + public void testProxySettingsFromProperties() { + System.setProperty("http.proxyHost", "192.168.0.1"); + System.setProperty("https.proxyHost", "192.168.0.2"); + Denominator.DenominatorCommand cmd = new Denominator.DenominatorCommand() { + @Override + protected Iterator doRun(DNSApiManager mgr) { + return null; + } + @Override + String getEnv(String name) { + if (name.equals("HTTPS_PROXY")) { + return "https://10.0.0.1"; + } else if (name.equals("HTTP_PROXY")) { + return "http://localhost"; + } + return null; + } + }; + cmd.setProxyFromEnv(); + assertThat(System.getProperty("http.proxyHost")).isEqualTo("192.168.0.1"); + assertThat(System.getProperty("http.proxyPort")).isNull(); + assertThat(System.getProperty("https.proxyHost")).isEqualTo("192.168.0.2"); + assertThat(System.getProperty("https.proxyPort")).isNull(); + } + + @Test + public void testInvalidEnvProxySettings() { + exit.expectSystemExitWithStatus(1); + exit.checkAssertionAfterwards(new Assertion() { + @Override + public void checkAssertion() throws Exception { + assertThat(System.getProperty("http.proxyHost")).isEqualTo("localhost"); + assertThat(System.getProperty("http.proxyPort")).isEqualTo("80"); + assertThat(System.getProperty("https.proxyHost")).isNull(); + assertThat(System.getProperty("https.proxyPort")).isNull(); + assertThat(systemErrRule.getLog()) + .isEqualToIgnoringCase( + "invalid https proxy configuration: no protocol: 10.0.0.1:8443\n"); + } + }); + Denominator.DenominatorCommand cmd = new Denominator.DenominatorCommand() { + @Override + protected Iterator doRun(DNSApiManager mgr) { + return null; + } + @Override + String getEnv(String name) { + if (name.equals("HTTPS_PROXY")) { + return "10.0.0.1:8443"; + } + return "http://localhost"; + } + }; + cmd.setProxyFromEnv(); + } + @Before public void stockRecords() { {