diff --git a/java/google/registry/proxy/CertificateModule.java b/java/google/registry/proxy/CertificateModule.java
index 2a6e7fca3..a8ad05bac 100644
--- a/java/google/registry/proxy/CertificateModule.java
+++ b/java/google/registry/proxy/CertificateModule.java
@@ -19,10 +19,12 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
+import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
-import google.registry.proxy.ProxyModule.PemBytes;
+import google.registry.proxy.ProxyConfig.Environment;
import google.registry.util.FormattingLogger;
+import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -32,6 +34,7 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.function.Function;
import javax.inject.Named;
+import javax.inject.Qualifier;
import javax.inject.Singleton;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
@@ -44,18 +47,32 @@ import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
/**
* Dagger module that provides bindings needed to inject EPP SSL certificate chain and private key.
*
- *
The certificates and private key are stored in a .pem file that is encrypted by Cloud KMS. The
- * .pem file can be generated by concatenating the .crt certificate files on the chain and the .key
- * private file.
+ *
The production certificates and private key are stored in a .pem file that is encrypted by
+ * Cloud KMS. The .pem file can be generated by concatenating the .crt certificate files on the
+ * chain and the .key private file.
*
- *
The certificates in the .pem file must be stored in order, where the next certificate's
- * subject is the previous certificate's issuer.
+ *
The production certificates in the .pem file must be stored in order, where the next
+ * certificate's subject is the previous certificate's issuer.
+ *
+ *
When running the proxy locally or in test, a self signed certificate is used.
*
* @see Cloud Key Management Service
*/
@Module
public class CertificateModule {
+ /** Dagger qualifier to provide bindings related to EPP certificates */
+ @Qualifier
+ public @interface EppCertificates {}
+
+ /** Dagger qualifier to provide bindings when running locally. */
+ @Qualifier
+ public @interface Local {}
+
+ /** Dagger qualifier to provide bindings when running in production. */
+ @Qualifier
+ public @interface Prod {}
+
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
static {
@@ -79,12 +96,56 @@ public class CertificateModule {
.collect(toImmutableList());
}
+ @Singleton
+ @Provides
+ @EppCertificates
+ static X509Certificate[] provideCertificates(
+ Environment env,
+ @Local Lazy localCertificates,
+ @Prod Lazy prodCertificates) {
+ return (env == Environment.LOCAL) ? localCertificates.get() : prodCertificates.get();
+ }
+
+ @Singleton
+ @Provides
+ @EppCertificates
+ static PrivateKey providePrivateKey(
+ Environment env,
+ @Local Lazy localPrivateKey,
+ @Prod Lazy prodPrivateKey) {
+ return (env == Environment.LOCAL) ? localPrivateKey.get() : prodPrivateKey.get();
+ }
+
+ @Singleton
+ @Provides
+ static SelfSignedCertificate provideSelfSignedCertificate() {
+ try {
+ return new SelfSignedCertificate();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Singleton
+ @Provides
+ @Local
+ static PrivateKey provideLocalPrivateKey(SelfSignedCertificate ssc) {
+ return ssc.key();
+ }
+
+ @Singleton
+ @Provides
+ @Local
+ static X509Certificate[] provideLocalCertificates(SelfSignedCertificate ssc) {
+ return new X509Certificate[] {ssc.cert()};
+ }
+
@Singleton
@Provides
@Named("pemObjects")
- static ImmutableList providePemObjects(PemBytes pemBytes) {
+ static ImmutableList providePemObjects(@Named("pemBytes") byte[] pemBytes) {
PEMParser pemParser =
- new PEMParser(new InputStreamReader(new ByteArrayInputStream(pemBytes.getBytes()), UTF_8));
+ new PEMParser(new InputStreamReader(new ByteArrayInputStream(pemBytes), UTF_8));
ImmutableList.Builder listBuilder = new ImmutableList.Builder<>();
Object obj;
// PEMParser returns an object (private key, certificate, etc) each time readObject() is called,
@@ -107,7 +168,8 @@ public class CertificateModule {
@Singleton
@Provides
- static PrivateKey providePrivateKey(@Named("pemObjects") ImmutableList pemObjects) {
+ @Prod
+ static PrivateKey provideProdPrivateKey(@Named("pemObjects") ImmutableList pemObjects) {
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
Function privateKeyConverter =
pemKeyPair -> {
@@ -129,8 +191,8 @@ public class CertificateModule {
@Singleton
@Provides
- @Named("eppServerCertificates")
- static X509Certificate[] provideCertificates(
+ @Prod
+ static X509Certificate[] provideProdCertificates(
@Named("pemObjects") ImmutableList pemObject) {
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider("BC");
Function certificateConverter =
diff --git a/java/google/registry/proxy/HttpsRelayProtocolModule.java b/java/google/registry/proxy/HttpsRelayProtocolModule.java
index 230d0db1f..c575ae7da 100644
--- a/java/google/registry/proxy/HttpsRelayProtocolModule.java
+++ b/java/google/registry/proxy/HttpsRelayProtocolModule.java
@@ -28,7 +28,6 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.logging.LoggingHandler;
import java.security.cert.X509Certificate;
import javax.annotation.Nullable;
-import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Qualifier;
@@ -44,7 +43,7 @@ public class HttpsRelayProtocolModule {
/** Dagger qualifier to provide https relay protocol related handlers and other bindings. */
@Qualifier
- @interface HttpsRelayProtocol {}
+ public @interface HttpsRelayProtocol {}
private static final String PROTOCOL_NAME = "https_relay";
@@ -89,7 +88,7 @@ public class HttpsRelayProtocolModule {
@Nullable
@Provides
- @Named("relayTrustedCertificates")
+ @HttpsRelayProtocol
public static X509Certificate[] provideTrustedCertificates() {
// null uses the system default trust store.
return null;
diff --git a/java/google/registry/proxy/ProxyModule.java b/java/google/registry/proxy/ProxyModule.java
index e78a6519f..a8964ec52 100644
--- a/java/google/registry/proxy/ProxyModule.java
+++ b/java/google/registry/proxy/ProxyModule.java
@@ -232,7 +232,8 @@ public class ProxyModule {
@Singleton
@Provides
- static PemBytes providePemBytes(
+ @Named("pemBytes")
+ static byte[] providePemBytes(
CloudKMS cloudKms, @Named("encryptedPemBytes") byte[] encryptedPemBytes, ProxyConfig config) {
String cryptoKeyUrl =
String.format(
@@ -240,15 +241,14 @@ public class ProxyModule {
config.projectId, config.kms.location, config.kms.keyRing, config.kms.cryptoKey);
try {
DecryptRequest decryptRequest = new DecryptRequest().encodeCiphertext(encryptedPemBytes);
- return PemBytes.create(
- cloudKms
- .projects()
- .locations()
- .keyRings()
- .cryptoKeys()
- .decrypt(cryptoKeyUrl, decryptRequest)
- .execute()
- .decodePlaintext());
+ return cloudKms
+ .projects()
+ .locations()
+ .keyRings()
+ .cryptoKeys()
+ .decrypt(cryptoKeyUrl, decryptRequest)
+ .execute()
+ .decodePlaintext();
} catch (IOException e) {
logger.severefmt(e, "PEM file decryption failed using CryptoKey: %s", cryptoKeyUrl);
throw new RuntimeException(e);
@@ -283,31 +283,6 @@ public class ProxyModule {
return getProxyConfig(env);
}
- /**
- * A wrapper class for decrypted bytes of the PEM file.
- *
- * Note that this should not be an @AutoValue class because we need a clone of the bytes to be
- * returned, otherwise the wrapper class becomes mutable.
- */
- // TODO: remove this class once FOSS build can use @BindsInstance to bind a byte[]
- // (https://github.com/bazelbuild/bazel/issues/4138)
- static class PemBytes {
-
- private final byte[] bytes;
-
- static PemBytes create(byte[] bytes) {
- return new PemBytes(bytes);
- }
-
- private PemBytes(byte[] bytes) {
- this.bytes = bytes;
- }
-
- byte[] getBytes() {
- return bytes.clone();
- }
- }
-
/** Root level component that exposes the port-to-protocol map. */
@Singleton
@Component(
diff --git a/java/google/registry/proxy/config/proxy-config-test.yaml b/java/google/registry/proxy/config/proxy-config-test.yaml
deleted file mode 100644
index 70d433c07..000000000
--- a/java/google/registry/proxy/config/proxy-config-test.yaml
+++ /dev/null
@@ -1 +0,0 @@
-# This file is for test only. Leave it blank.
diff --git a/java/google/registry/proxy/handler/SslClientInitializer.java b/java/google/registry/proxy/handler/SslClientInitializer.java
index 419c06aab..792ae34f7 100644
--- a/java/google/registry/proxy/handler/SslClientInitializer.java
+++ b/java/google/registry/proxy/handler/SslClientInitializer.java
@@ -17,6 +17,7 @@ package google.registry.proxy.handler;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.proxy.Protocol.PROTOCOL_KEY;
+import google.registry.proxy.HttpsRelayProtocolModule.HttpsRelayProtocol;
import google.registry.proxy.Protocol.BackendProtocol;
import google.registry.util.FormattingLogger;
import io.netty.channel.Channel;
@@ -29,7 +30,6 @@ import io.netty.handler.ssl.SslProvider;
import java.security.cert.X509Certificate;
import javax.annotation.Nullable;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
@@ -51,8 +51,7 @@ public class SslClientInitializer extends ChannelInitializer<
@Inject
SslClientInitializer(
- SslProvider sslProvider,
- @Nullable @Named("relayTrustedCertificates") X509Certificate... trustCertificates) {
+ SslProvider sslProvider, @Nullable @HttpsRelayProtocol X509Certificate... trustCertificates) {
logger.infofmt("Client SSL Provider: %s", sslProvider);
this.sslProvider = sslProvider;
this.trustedCertificates = trustCertificates;
diff --git a/java/google/registry/proxy/handler/SslServerInitializer.java b/java/google/registry/proxy/handler/SslServerInitializer.java
index a7b54acdb..abb185326 100644
--- a/java/google/registry/proxy/handler/SslServerInitializer.java
+++ b/java/google/registry/proxy/handler/SslServerInitializer.java
@@ -14,6 +14,7 @@
package google.registry.proxy.handler;
+import google.registry.proxy.CertificateModule.EppCertificates;
import google.registry.util.FormattingLogger;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
@@ -30,7 +31,6 @@ import io.netty.util.concurrent.Promise;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -66,8 +66,8 @@ public class SslServerInitializer extends ChannelInitializer<
@Inject
SslServerInitializer(
SslProvider sslProvider,
- PrivateKey privateKey,
- @Named("eppServerCertificates") X509Certificate... certificates) {
+ @EppCertificates PrivateKey privateKey,
+ @EppCertificates X509Certificate... certificates) {
logger.infofmt("Server SSL Provider: %s", sslProvider);
this.sslProvider = sslProvider;
this.privateKey = privateKey;
diff --git a/java/google/registry/repositories.bzl b/java/google/registry/repositories.bzl
index b8765b46f..1535bff72 100644
--- a/java/google/registry/repositories.bzl
+++ b/java/google/registry/repositories.bzl
@@ -1147,10 +1147,10 @@ def com_google_code_findbugs_jsr305():
def com_google_dagger():
java_import_external(
name = "com_google_dagger",
- jar_sha256 = "b2142693bc7413f0b74330f0a92ca44ea95a12a22b659972ed6aa9832e8352e4",
+ jar_sha256 = "1f14720ffc3152a4207e374edb2ce114d94625058a6ef48a35cb67764dac4756",
jar_urls = [
- "http://repo1.maven.org/maven2/com/google/dagger/dagger/2.13/dagger-2.13.jar",
- "http://maven.ibiblio.org/maven2/com/google/dagger/dagger/2.13/dagger-2.13.jar",
+ "http://repo1.maven.org/maven2/com/google/dagger/dagger/2.15/dagger-2.15.jar",
+ "http://maven.ibiblio.org/maven2/com/google/dagger/dagger/2.15/dagger-2.15.jar",
],
licenses = ["notice"], # Apache 2.0
deps = ["@javax_inject"],
@@ -1170,10 +1170,10 @@ def com_google_dagger():
def com_google_dagger_compiler():
java_import_external(
name = "com_google_dagger_compiler",
- jar_sha256 = "8b711253c9cbb58bd2c019cb38afb32ee79f283e1bb3030c8c85b645c7a6d25f",
+ jar_sha256 = "ecd1e8ee0224312ae29203767fb8ec70af13e4f2724df2174ba0d2867cd2de78",
jar_urls = [
- "http://maven.ibiblio.org/maven2/com/google/dagger/dagger-compiler/2.13/dagger-compiler-2.13.jar",
- "http://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.13/dagger-compiler-2.13.jar",
+ "http://maven.ibiblio.org/maven2/com/google/dagger/dagger-compiler/2.15/dagger-compiler-2.15.jar",
+ "http://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.15/dagger-compiler-2.15.jar",
],
licenses = ["notice"], # Apache 2.0
deps = [
@@ -1204,10 +1204,10 @@ def com_google_dagger_compiler():
def com_google_dagger_producers():
java_import_external(
name = "com_google_dagger_producers",
- jar_sha256 = "cf35b21c634939917eee9ffcd72a9f5f6e261ad57a4c0f0d15cf6f1430262bb0",
+ jar_sha256 = "eb189206f80df260de4331bb51e92a94e06f5cbf5ef3d1492d34c5e139e92eb1",
jar_urls = [
- "http://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.13/dagger-producers-2.13.jar",
- "http://maven.ibiblio.org/maven2/com/google/dagger/dagger-producers/2.13/dagger-producers-2.13.jar",
+ "http://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.15/dagger-producers-2.15.jar",
+ "http://maven.ibiblio.org/maven2/com/google/dagger/dagger-producers/2.15/dagger-producers-2.15.jar",
],
licenses = ["notice"], # Apache 2.0
deps = [
diff --git a/javatests/google/registry/proxy/CertificateModuleTest.java b/javatests/google/registry/proxy/CertificateModuleTest.java
index 5151440a2..841c0c265 100644
--- a/javatests/google/registry/proxy/CertificateModuleTest.java
+++ b/javatests/google/registry/proxy/CertificateModuleTest.java
@@ -20,9 +20,10 @@ import static google.registry.proxy.handler.SslInitializerTestUtils.signKeyPair;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.fail;
-import dagger.BindsInstance;
import dagger.Component;
-import google.registry.proxy.ProxyModule.PemBytes;
+import dagger.Module;
+import dagger.Provides;
+import google.registry.proxy.CertificateModule.Prod;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
@@ -59,9 +60,9 @@ public class CertificateModuleTest {
}
/** Create a component with bindings to the given bytes[] as the contents from a PEM file. */
- private TestComponent createComponent(byte[] bytes) {
+ private TestComponent createComponent(byte[] pemBytes) {
return DaggerCertificateModuleTest_TestComponent.builder()
- .pemBytes(PemBytes.create(bytes))
+ .pemBytesModule(new PemBytesModule(pemBytes))
.build();
}
@@ -137,22 +138,36 @@ public class CertificateModuleTest {
}
}
- @Singleton
- @Component(modules = {CertificateModule.class})
- interface TestComponent {
+ @Module
+ static class PemBytesModule {
+ private final byte[] pemBytes;
- PrivateKey privateKey();
+ PemBytesModule(byte[] pemBytes) {
+ this.pemBytes = pemBytes;
+ }
- @Named("eppServerCertificates")
- X509Certificate[] certificates();
-
- @Component.Builder
- interface Builder {
-
- @BindsInstance
- Builder pemBytes(PemBytes pemBytes);
-
- TestComponent build();
+ @Provides
+ @Named("pemBytes")
+ byte[] providePemBytes() {
+ return pemBytes;
}
}
+
+ /**
+ * Test component that exposes prod certificate and key.
+ *
+ * Local certificate and key are not tested because they are directly extracted from a
+ * self-signed certificate. Here we want to test that we can correctly parse and create
+ * certificate and keys from a .pem file.
+ */
+ @Singleton
+ @Component(modules = {CertificateModule.class, PemBytesModule.class})
+ interface TestComponent {
+
+ @Prod
+ PrivateKey privateKey();
+
+ @Prod
+ X509Certificate[] certificates();
+ }
}
diff --git a/javatests/google/registry/proxy/ProtocolModuleTest.java b/javatests/google/registry/proxy/ProtocolModuleTest.java
index 7f1b222d8..161687bdd 100644
--- a/javatests/google/registry/proxy/ProtocolModuleTest.java
+++ b/javatests/google/registry/proxy/ProtocolModuleTest.java
@@ -15,7 +15,7 @@
package google.registry.proxy;
import static com.google.common.collect.ImmutableList.toImmutableList;
-import static google.registry.proxy.ProxyConfig.Environment.TEST;
+import static google.registry.proxy.ProxyConfig.Environment.LOCAL;
import static google.registry.proxy.ProxyConfig.getProxyConfig;
import com.google.common.base.Suppliers;
@@ -28,6 +28,7 @@ import dagger.Provides;
import google.registry.proxy.EppProtocolModule.EppProtocol;
import google.registry.proxy.HealthCheckProtocolModule.HealthCheckProtocol;
import google.registry.proxy.HttpsRelayProtocolModule.HttpsRelayProtocol;
+import google.registry.proxy.ProxyConfig.Environment;
import google.registry.proxy.WhoisProtocolModule.WhoisProtocol;
import google.registry.proxy.handler.BackendMetricsHandler;
import google.registry.proxy.handler.ProxyProtocolHandler;
@@ -45,10 +46,7 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslProvider;
-import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.timeout.ReadTimeoutHandler;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -74,7 +72,7 @@ import org.junit.Before;
*/
public abstract class ProtocolModuleTest {
- protected static final ProxyConfig PROXY_CONFIG = getProxyConfig(TEST);
+ protected static final ProxyConfig PROXY_CONFIG = getProxyConfig(LOCAL);
protected TestComponent testComponent;
@@ -179,6 +177,7 @@ public abstract class ProtocolModuleTest {
@Component(
modules = {
TestModule.class,
+ CertificateModule.class,
WhoisProtocolModule.class,
EppProtocolModule.class,
HealthCheckProtocolModule.class,
@@ -224,7 +223,7 @@ public abstract class ProtocolModuleTest {
@Singleton
@Provides
static ProxyConfig provideProxyConfig() {
- return getProxyConfig(TEST);
+ return getProxyConfig(LOCAL);
}
@Singleton
@@ -246,29 +245,6 @@ public abstract class ProtocolModuleTest {
return new LoggingHandler();
}
- @Singleton
- @Provides
- static SelfSignedCertificate provideSelfSignedCertificate() {
- try {
- return new SelfSignedCertificate();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Singleton
- @Provides
- @Named("eppServerCertificates")
- static X509Certificate[] provideCertificate(SelfSignedCertificate ssc) {
- return new X509Certificate[] {ssc.cert()};
- }
-
- @Singleton
- @Provides
- static PrivateKey providePrivateKey(SelfSignedCertificate ssc) {
- return ssc.key();
- }
-
@Singleton
@Provides
Clock provideFakeClock() {
@@ -277,14 +253,29 @@ public abstract class ProtocolModuleTest {
@Singleton
@Provides
- ExecutorService provideExecutorService() {
+ static ExecutorService provideExecutorService() {
return MoreExecutors.newDirectExecutorService();
}
@Singleton
@Provides
- ScheduledExecutorService provideScheduledExecutorService() {
+ static ScheduledExecutorService provideScheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
+
+ @Singleton
+ @Provides
+ static Environment provideEnvironment() {
+ return Environment.LOCAL;
+ }
+
+ // This method is only here to satisfy Dagger binding, but is never used. In test environment,
+ // it is the self-signed certificate and its key that end up being used.
+ @Singleton
+ @Provides
+ @Named("pemBytes")
+ static byte[] providePemBytes() {
+ return new byte[0];
+ }
}
}
diff --git a/javatests/google/registry/proxy/ProxyModuleTest.java b/javatests/google/registry/proxy/ProxyModuleTest.java
index 3bbb4373a..46fd10383 100644
--- a/javatests/google/registry/proxy/ProxyModuleTest.java
+++ b/javatests/google/registry/proxy/ProxyModuleTest.java
@@ -15,7 +15,7 @@
package google.registry.proxy;
import static com.google.common.truth.Truth.assertThat;
-import static google.registry.proxy.ProxyConfig.Environment.TEST;
+import static google.registry.proxy.ProxyConfig.Environment.LOCAL;
import static google.registry.proxy.ProxyConfig.getProxyConfig;
import static google.registry.testing.JUnitBackports.assertThrows;
import static org.junit.Assert.fail;
@@ -30,7 +30,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ProxyModuleTest {
- private static final ProxyConfig PROXY_CONFIG = getProxyConfig(TEST);
+ private static final ProxyConfig PROXY_CONFIG = getProxyConfig(LOCAL);
private final ProxyModule proxyModule = new ProxyModule();
@Test
@@ -41,7 +41,7 @@ public class ProxyModuleTest {
assertThat(proxyModule.provideEppPort(PROXY_CONFIG)).isEqualTo(PROXY_CONFIG.epp.port);
assertThat(proxyModule.provideHealthCheckPort(PROXY_CONFIG))
.isEqualTo(PROXY_CONFIG.healthCheck.port);
- assertThat(proxyModule.provideEnvironment()).isEqualTo(Environment.LOCAL);
+ assertThat(proxyModule.provideEnvironment()).isEqualTo(LOCAL);
assertThat(proxyModule.log).isFalse();
}