Use enum instead of boolean for TMCH CA mode

Also more narrowly scopes a catch block in TmchCertificateAuthority.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144744847
This commit is contained in:
mcilwain 2017-01-17 12:57:05 -08:00 committed by Ben McIlwain
parent 0dbaa8e5bc
commit a28e0b3ff7
13 changed files with 90 additions and 73 deletions

View file

@ -424,21 +424,36 @@ public final class RegistryConfig {
} }
/** /**
* Returns {@code true} if TMCH certificate authority should be in testing mode. * Returns the mode that TMCH certificate authority should run in.
* *
* @see RegistryConfig#getTmchCaTestingMode() * @see google.registry.tmch.TmchCertificateAuthority
*/ */
@Provides @Provides
@Config("tmchCaTestingMode") @Config("tmchCaMode")
public static boolean provideTmchCaTestingMode() { public static TmchCaMode provideTmchCaMode() {
return RegistryConfig.getTmchCaTestingMode(); switch (RegistryEnvironment.get()) {
case PRODUCTION:
return TmchCaMode.PRODUCTION;
default:
return TmchCaMode.PILOT;
}
}
/** The mode that the {@code TmchCertificateAuthority} operates in. */
public enum TmchCaMode {
/** Production mode, suitable for live environments hosting TLDs. */
PRODUCTION,
/** Pilot mode, for everything else (e.g. sandbox). */
PILOT;
} }
/** /**
* ICANN TMCH Certificate Revocation List URL. * ICANN TMCH Certificate Revocation List URL.
* *
* <p>This file needs to be downloaded at least once a day and verified to make sure it was * <p>This file needs to be downloaded at least once a day and verified to make sure it was
* signed by {@code icann-tmch.crt}. * signed by {@code icann-tmch.crt} or {@code icann-tmch-pilot.crt} depending on TMCH CA mode.
* *
* @see google.registry.tmch.TmchCrlAction * @see google.registry.tmch.TmchCrlAction
* @see <a href="http://tools.ietf.org/html/draft-lozano-tmch-func-spec-08#section-5.2.3.2">TMCH * @see <a href="http://tools.ietf.org/html/draft-lozano-tmch-func-spec-08#section-5.2.3.2">TMCH
@ -1146,20 +1161,6 @@ public final class RegistryConfig {
return Duration.standardDays(30); return Duration.standardDays(30);
} }
/**
* Returns {@code true} if TMCH certificate authority should be in testing mode.
*
* @see google.registry.tmch.TmchCertificateAuthority
*/
public static boolean getTmchCaTestingMode() {
switch (RegistryEnvironment.get()) {
case PRODUCTION:
return false;
default:
return true;
}
}
/** /**
* Returns the address of the Nomulus app HTTP server. * Returns the address of the Nomulus app HTTP server.
* *

View file

@ -14,6 +14,7 @@
package google.registry.tmch; package google.registry.tmch;
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PILOT;
import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration; import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration;
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration; import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
import static google.registry.util.ResourceUtils.readResourceUtf8; import static google.registry.util.ResourceUtils.readResourceUtf8;
@ -23,6 +24,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import google.registry.config.RegistryConfig.Config; import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.model.tmch.TmchCrl; import google.registry.model.tmch.TmchCrl;
import google.registry.util.Clock; import google.registry.util.Clock;
import google.registry.util.NonFinalForTesting; import google.registry.util.NonFinalForTesting;
@ -39,23 +41,26 @@ import javax.inject.Inject;
/** /**
* Helper methods for accessing ICANN's TMCH root certificate and revocation list. * Helper methods for accessing ICANN's TMCH root certificate and revocation list.
* *
* <p>There are two CRLs, a real one for the production environment and a testing one for * <p>There are two CRLs, a real one for the production environment and a pilot one for
* non-production environments. The Datastore singleton {@link TmchCrl} entity is used to cache this * non-production environments. The Datastore singleton {@link TmchCrl} entity is used to cache this
* CRL once loaded and will always contain the proper one corresponding to the environment. * CRL once loaded and will always contain the proper one corresponding to the environment.
*
* <p>The CRTs do not change and are included as files in the codebase that are not refreshed. They
* were downloaded from https://ca.icann.org/tmch.crt and https://ca.icann.org/tmch_pilot.crt
*/ */
@Immutable @Immutable
@ThreadSafe @ThreadSafe
public final class TmchCertificateAuthority { public final class TmchCertificateAuthority {
private static final String ROOT_CRT_FILE = "icann-tmch.crt"; private static final String ROOT_CRT_FILE = "icann-tmch.crt";
private static final String TEST_ROOT_CRT_FILE = "icann-tmch-test.crt"; private static final String ROOT_CRT_PILOT_FILE = "icann-tmch-pilot.crt";
private static final String CRL_FILE = "icann-tmch.crl"; private static final String CRL_FILE = "icann-tmch.crl";
private static final String TEST_CRL_FILE = "icann-tmch-test.crl"; private static final String CRL_PILOT_FILE = "icann-tmch-pilot.crl";
private boolean tmchCaTestingMode; private final TmchCaMode tmchCaMode;
public @Inject TmchCertificateAuthority(@Config("tmchCaTestingMode") boolean tmchCaTestingMode) { public @Inject TmchCertificateAuthority(@Config("tmchCaMode") TmchCaMode tmchCaMode) {
this.tmchCaTestingMode = tmchCaTestingMode; this.tmchCaMode = tmchCaMode;
} }
/** /**
@ -65,28 +70,27 @@ public final class TmchCertificateAuthority {
* string into an X509CRL instance is expensive and should itself be cached. * string into an X509CRL instance is expensive and should itself be cached.
* *
* <p>Note that the stored CRL won't exist for tests, and on deployed environments will always * <p>Note that the stored CRL won't exist for tests, and on deployed environments will always
* correspond to the correct CRL for the given testing mode because {@link TmchCrlAction} can * correspond to the correct CRL for the given TMCH CA mode because {@link TmchCrlAction} can
* only persist the correct one for this given environment. * only persist the correct one for this given environment.
*/ */
private static final LoadingCache<Boolean, X509CRL> CRL_CACHE = private static final LoadingCache<TmchCaMode, X509CRL> CRL_CACHE =
CacheBuilder.newBuilder() CacheBuilder.newBuilder()
.expireAfterWrite(getSingletonCacheRefreshDuration().getMillis(), MILLISECONDS) .expireAfterWrite(getSingletonCacheRefreshDuration().getMillis(), MILLISECONDS)
.build( .build(
new CacheLoader<Boolean, X509CRL>() { new CacheLoader<TmchCaMode, X509CRL>() {
@Override @Override
public X509CRL load(final Boolean tmchCaTestingMode) public X509CRL load(final TmchCaMode tmchCaMode) throws GeneralSecurityException {
throws GeneralSecurityException {
TmchCrl storedCrl = TmchCrl.get(); TmchCrl storedCrl = TmchCrl.get();
try {
String crlContents; String crlContents;
if (storedCrl == null) { if (storedCrl == null) {
String file = tmchCaTestingMode.booleanValue() ? TEST_CRL_FILE : CRL_FILE; String file = (tmchCaMode == PILOT) ? CRL_PILOT_FILE : CRL_FILE;
crlContents = readResourceUtf8(TmchCertificateAuthority.class, file); crlContents = readResourceUtf8(TmchCertificateAuthority.class, file);
} else { } else {
crlContents = storedCrl.getCrl(); crlContents = storedCrl.getCrl();
} }
X509CRL crl = X509Utils.loadCrl(crlContents); X509CRL crl = X509Utils.loadCrl(crlContents);
crl.verify(ROOT_CACHE.get(tmchCaTestingMode).getPublicKey()); try {
crl.verify(ROOT_CACHE.get(tmchCaMode).getPublicKey());
return crl; return crl;
} catch (ExecutionException e) { } catch (ExecutionException e) {
if (e.getCause() instanceof GeneralSecurityException) { if (e.getCause() instanceof GeneralSecurityException) {
@ -98,16 +102,15 @@ public final class TmchCertificateAuthority {
}}); }});
/** A cached function that loads the CRT from a jar resource. */ /** A cached function that loads the CRT from a jar resource. */
private static final LoadingCache<Boolean, X509Certificate> ROOT_CACHE = private static final LoadingCache<TmchCaMode, X509Certificate> ROOT_CACHE =
CacheBuilder.newBuilder() CacheBuilder.newBuilder()
.expireAfterWrite(getSingletonCachePersistDuration().getMillis(), MILLISECONDS) .expireAfterWrite(getSingletonCachePersistDuration().getMillis(), MILLISECONDS)
.build( .build(
new CacheLoader<Boolean, X509Certificate>() { new CacheLoader<TmchCaMode, X509Certificate>() {
@Override @Override
public X509Certificate load(final Boolean tmchCaTestingMode) public X509Certificate load(final TmchCaMode tmchCaMode)
throws GeneralSecurityException { throws GeneralSecurityException {
String file = String file = (tmchCaMode == PILOT) ? ROOT_CRT_PILOT_FILE : ROOT_CRT_FILE;
tmchCaTestingMode.booleanValue() ? TEST_ROOT_CRT_FILE : ROOT_CRT_FILE;
X509Certificate root = X509Certificate root =
X509Utils.loadCertificate( X509Utils.loadCertificate(
readResourceUtf8(TmchCertificateAuthority.class, file)); readResourceUtf8(TmchCertificateAuthority.class, file));
@ -153,7 +156,7 @@ public final class TmchCertificateAuthority {
public X509Certificate getRoot() throws GeneralSecurityException { public X509Certificate getRoot() throws GeneralSecurityException {
try { try {
return ROOT_CACHE.get(tmchCaTestingMode); return ROOT_CACHE.get(tmchCaMode);
} catch (Exception e) { } catch (Exception e) {
if (e.getCause() instanceof GeneralSecurityException) { if (e.getCause() instanceof GeneralSecurityException) {
throw (GeneralSecurityException) e.getCause(); throw (GeneralSecurityException) e.getCause();
@ -166,7 +169,7 @@ public final class TmchCertificateAuthority {
public X509CRL getCrl() throws GeneralSecurityException { public X509CRL getCrl() throws GeneralSecurityException {
try { try {
return CRL_CACHE.get(tmchCaTestingMode); return CRL_CACHE.get(tmchCaMode);
} catch (Exception e) { } catch (Exception e) {
if (e.getCause() instanceof GeneralSecurityException) { if (e.getCause() instanceof GeneralSecurityException) {
throw (GeneralSecurityException) e.getCause(); throw (GeneralSecurityException) e.getCause();

View file

@ -25,6 +25,7 @@ import static org.joda.time.DateTimeZone.UTC;
import static org.joda.time.Duration.standardDays; import static org.joda.time.Duration.standardDays;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.flows.EppTestComponent.FakesAndMocksModule; import google.registry.flows.EppTestComponent.FakesAndMocksModule;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
import google.registry.model.ofy.Ofy; import google.registry.model.ofy.Ofy;
@ -71,7 +72,7 @@ public class EppCommitLogsTest extends ShardableTestCase {
SessionMetadata sessionMetadata = new HttpSessionMetadata(new FakeHttpSession()); SessionMetadata sessionMetadata = new HttpSessionMetadata(new FakeHttpSession());
sessionMetadata.setClientId("TheRegistrar"); sessionMetadata.setClientId("TheRegistrar");
DaggerEppTestComponent.builder() DaggerEppTestComponent.builder()
.fakesAndMocksModule(new FakesAndMocksModule(clock, true)) .fakesAndMocksModule(new FakesAndMocksModule(clock, TmchCaMode.PILOT))
.build() .build()
.startRequest() .startRequest()
.flowComponentBuilder() .flowComponentBuilder()

View file

@ -23,6 +23,7 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.DateTimeZone.UTC;
import com.google.common.net.MediaType; import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.flows.EppTestComponent.FakesAndMocksModule; import google.registry.flows.EppTestComponent.FakesAndMocksModule;
import google.registry.model.ofy.Ofy; import google.registry.model.ofy.Ofy;
import google.registry.testing.FakeClock; import google.registry.testing.FakeClock;
@ -114,7 +115,7 @@ public class EppTestCase extends ShardableTestCase {
FakeResponse response = new FakeResponse(); FakeResponse response = new FakeResponse();
handler.response = response; handler.response = response;
handler.eppController = DaggerEppTestComponent.builder() handler.eppController = DaggerEppTestComponent.builder()
.fakesAndMocksModule(new FakesAndMocksModule(clock, true)) .fakesAndMocksModule(new FakesAndMocksModule(clock, TmchCaMode.PILOT))
.build() .build()
.startRequest() .startRequest()
.eppController(); .eppController();

View file

@ -22,6 +22,7 @@ import dagger.Module;
import dagger.Provides; import dagger.Provides;
import dagger.Subcomponent; import dagger.Subcomponent;
import google.registry.config.RegistryConfig.ConfigModule; import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.dns.DnsQueue; import google.registry.dns.DnsQueue;
import google.registry.flows.custom.CustomLogicFactory; import google.registry.flows.custom.CustomLogicFactory;
import google.registry.flows.custom.TestCustomLogicFactory; import google.registry.flows.custom.TestCustomLogicFactory;
@ -61,14 +62,13 @@ interface EppTestComponent {
final Sleeper sleeper; final Sleeper sleeper;
FakesAndMocksModule() { FakesAndMocksModule() {
this(new FakeClock(), true); this(new FakeClock(), TmchCaMode.PILOT);
} }
FakesAndMocksModule(FakeClock clock, boolean tmchCaTestingMode) { FakesAndMocksModule(FakeClock clock, TmchCaMode tmchCaMode) {
this.clock = clock; this.clock = clock;
this.domainFlowTmchUtils = this.domainFlowTmchUtils =
new DomainFlowTmchUtils( new DomainFlowTmchUtils(new TmchXmlSignature(new TmchCertificateAuthority(tmchCaMode)));
new TmchXmlSignature(new TmchCertificateAuthority(tmchCaTestingMode)));
this.sleeper = new FakeSleeper(clock); this.sleeper = new FakeSleeper(clock);
this.dnsQueue = DnsQueue.create(); this.dnsQueue = DnsQueue.create();
this.metricBuilder = EppMetric.builderForRequest("request-id-1", clock); this.metricBuilder = EppMetric.builderForRequest("request-id-1", clock);

View file

@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.flows.EppTestComponent.FakesAndMocksModule; import google.registry.flows.EppTestComponent.FakesAndMocksModule;
import google.registry.flows.picker.FlowPicker; import google.registry.flows.picker.FlowPicker;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
@ -277,7 +278,7 @@ public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
.isEqualTo(new TypeInstantiator<F>(getClass()){}.getExactType()); .isEqualTo(new TypeInstantiator<F>(getClass()){}.getExactType());
// Run the flow. // Run the flow.
return DaggerEppTestComponent.builder() return DaggerEppTestComponent.builder()
.fakesAndMocksModule(new FakesAndMocksModule(clock, tmchCaTestingMode)) .fakesAndMocksModule(new FakesAndMocksModule(clock, tmchCaMode))
.build() .build()
.startRequest() .startRequest()
.flowComponentBuilder() .flowComponentBuilder()
@ -339,10 +340,10 @@ public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
return output; return output;
} }
private boolean tmchCaTestingMode = true; private TmchCaMode tmchCaMode = TmchCaMode.PILOT;
protected void useTmchProdCert() { protected void useTmchProdCert() {
tmchCaTestingMode = false; tmchCaMode = TmchCaMode.PRODUCTION;
} }
public EppOutput dryRunFlowAssertResponse(String xml, String... ignoredPaths) throws Exception { public EppOutput dryRunFlowAssertResponse(String xml, String... ignoredPaths) throws Exception {

View file

@ -17,6 +17,7 @@ java_library(
"testdata/*/*/*", "testdata/*/*/*",
]), ]),
deps = [ deps = [
"//java/google/registry/config",
"//java/google/registry/model", "//java/google/registry/model",
"//java/google/registry/request", "//java/google/registry/request",
"//java/google/registry/tmch", "//java/google/registry/tmch",

View file

@ -14,6 +14,8 @@
package google.registry.tmch; package google.registry.tmch;
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PILOT;
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PRODUCTION;
import static google.registry.tmch.TmchTestData.loadString; import static google.registry.tmch.TmchTestData.loadString;
import static google.registry.util.ResourceUtils.readResourceUtf8; import static google.registry.util.ResourceUtils.readResourceUtf8;
import static google.registry.util.X509Utils.loadCertificate; import static google.registry.util.X509Utils.loadCertificate;
@ -61,7 +63,7 @@ public class TmchCertificateAuthorityTest {
@Test @Test
public void testFailure_prodRootExpired() throws Exception { public void testFailure_prodRootExpired() throws Exception {
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(false); TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PRODUCTION);
clock.setTo(DateTime.parse("2024-01-01T00:00:00Z")); clock.setTo(DateTime.parse("2024-01-01T00:00:00Z"));
thrown.expectRootCause( thrown.expectRootCause(
CertificateExpiredException.class, "NotAfter: Sun Jul 23 23:59:59 UTC 2023"); CertificateExpiredException.class, "NotAfter: Sun Jul 23 23:59:59 UTC 2023");
@ -70,7 +72,7 @@ public class TmchCertificateAuthorityTest {
@Test @Test
public void testFailure_prodRootNotYetValid() throws Exception { public void testFailure_prodRootNotYetValid() throws Exception {
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(false); TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PRODUCTION);
clock.setTo(DateTime.parse("2000-01-01T00:00:00Z")); clock.setTo(DateTime.parse("2000-01-01T00:00:00Z"));
thrown.expectRootCause(CertificateNotYetValidException.class, thrown.expectRootCause(CertificateNotYetValidException.class,
"NotBefore: Wed Jul 24 00:00:00 UTC 2013"); "NotBefore: Wed Jul 24 00:00:00 UTC 2013");
@ -80,7 +82,7 @@ public class TmchCertificateAuthorityTest {
@Test @Test
public void testFailure_crlDoesntMatchCerts() throws Exception { public void testFailure_crlDoesntMatchCerts() throws Exception {
// Use the prod cl, which won't match our test certificate. // Use the prod cl, which won't match our test certificate.
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(true); TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PILOT);
TmchCrl.set( TmchCrl.set(
readResourceUtf8(TmchCertificateAuthority.class, "icann-tmch.crl"), "http://cert.crl"); readResourceUtf8(TmchCertificateAuthority.class, "icann-tmch.crl"), "http://cert.crl");
thrown.expectRootCause(SignatureException.class, "Signature does not match"); thrown.expectRootCause(SignatureException.class, "Signature does not match");
@ -89,20 +91,20 @@ public class TmchCertificateAuthorityTest {
@Test @Test
public void testSuccess_verify() throws Exception { public void testSuccess_verify() throws Exception {
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(true); TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PILOT);
tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE)); tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE));
} }
@Test @Test
public void testFailure_verifySignatureDoesntMatch() throws Exception { public void testFailure_verifySignatureDoesntMatch() throws Exception {
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(false); TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PRODUCTION);
thrown.expectRootCause(SignatureException.class, "Signature does not match"); thrown.expectRootCause(SignatureException.class, "Signature does not match");
tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE)); tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE));
} }
@Test @Test
public void testFailure_verifyRevoked() throws Exception { public void testFailure_verifyRevoked() throws Exception {
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(true); TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PILOT);
thrown.expect(CertificateRevokedException.class, "revoked, reason: KEY_COMPROMISE"); thrown.expect(CertificateRevokedException.class, "revoked, reason: KEY_COMPROMISE");
tmchCertificateAuthority.verify(loadCertificate(REVOKED_TEST_CERTIFICATE)); tmchCertificateAuthority.verify(loadCertificate(REVOKED_TEST_CERTIFICATE));
} }

View file

@ -19,6 +19,7 @@ import static google.registry.util.ResourceUtils.readResourceBytes;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.security.SignatureException; import java.security.SignatureException;
@ -30,10 +31,10 @@ import org.junit.Test;
/** Unit tests for {@link TmchCrlAction}. */ /** Unit tests for {@link TmchCrlAction}. */
public class TmchCrlActionTest extends TmchActionTestCase { public class TmchCrlActionTest extends TmchActionTestCase {
private TmchCrlAction newTmchCrlAction(boolean tmchCaTestingMode) throws MalformedURLException { private TmchCrlAction newTmchCrlAction(TmchCaMode tmchCaMode) throws MalformedURLException {
TmchCrlAction action = new TmchCrlAction(); TmchCrlAction action = new TmchCrlAction();
action.marksdb = marksdb; action.marksdb = marksdb;
action.tmchCertificateAuthority = new TmchCertificateAuthority(tmchCaTestingMode); action.tmchCertificateAuthority = new TmchCertificateAuthority(tmchCaMode);
action.tmchCrlUrl = new URL("http://sloth.lol/tmch.crl"); action.tmchCrlUrl = new URL("http://sloth.lol/tmch.crl");
return action; return action;
} }
@ -43,7 +44,7 @@ public class TmchCrlActionTest extends TmchActionTestCase {
clock.setTo(DateTime.parse("2013-07-24TZ")); clock.setTo(DateTime.parse("2013-07-24TZ"));
when(httpResponse.getContent()).thenReturn( when(httpResponse.getContent()).thenReturn(
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch.crl").read()); readResourceBytes(TmchCertificateAuthority.class, "icann-tmch.crl").read());
newTmchCrlAction(false).run(); newTmchCrlAction(TmchCaMode.PRODUCTION).run();
verify(httpResponse).getContent(); verify(httpResponse).getContent();
verify(fetchService).fetch(httpRequest.capture()); verify(fetchService).fetch(httpRequest.capture());
assertThat(httpRequest.getValue().getURL().toString()).isEqualTo("http://sloth.lol/tmch.crl"); assertThat(httpRequest.getValue().getURL().toString()).isEqualTo("http://sloth.lol/tmch.crl");
@ -53,8 +54,12 @@ public class TmchCrlActionTest extends TmchActionTestCase {
public void testFailure_crlTooOld() throws Exception { public void testFailure_crlTooOld() throws Exception {
clock.setTo(DateTime.parse("2020-01-01TZ")); clock.setTo(DateTime.parse("2020-01-01TZ"));
when(httpResponse.getContent()).thenReturn( when(httpResponse.getContent()).thenReturn(
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch-test.crl").read()); readResourceBytes(TmchCertificateAuthority.class, "icann-tmch-pilot.crl").read());
TmchCrlAction action = newTmchCrlAction(false); // We use the pilot CRL here only because we know that it was generated more recently than the
// production CRL, and thus attempting to replace it with the production CRL will fail. It
// doesn't matter that the wrong CRT would be used to verify it because that check happens after
// the age check.
TmchCrlAction action = newTmchCrlAction(TmchCaMode.PRODUCTION);
thrown.expectRootCause(CRLException.class, "New CRL is more out of date than our current CRL."); thrown.expectRootCause(CRLException.class, "New CRL is more out of date than our current CRL.");
action.run(); action.run();
} }
@ -65,15 +70,15 @@ public class TmchCrlActionTest extends TmchActionTestCase {
when(httpResponse.getContent()).thenReturn( when(httpResponse.getContent()).thenReturn(
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch.crl").read()); readResourceBytes(TmchCertificateAuthority.class, "icann-tmch.crl").read());
thrown.expectRootCause(SignatureException.class, "Signature does not match."); thrown.expectRootCause(SignatureException.class, "Signature does not match.");
newTmchCrlAction(true).run(); newTmchCrlAction(TmchCaMode.PILOT).run();
} }
@Test @Test
public void testFailure_crlNotYetValid() throws Exception { public void testFailure_crlNotYetValid() throws Exception {
clock.setTo(DateTime.parse("1984-01-01TZ")); clock.setTo(DateTime.parse("1984-01-01TZ"));
when(httpResponse.getContent()).thenReturn( when(httpResponse.getContent()).thenReturn(
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch-test.crl").read()); readResourceBytes(TmchCertificateAuthority.class, "icann-tmch-pilot.crl").read());
thrown.expectRootCause(CertificateNotYetValidException.class); thrown.expectRootCause(CertificateNotYetValidException.class);
newTmchCrlAction(true).run(); newTmchCrlAction(TmchCaMode.PILOT).run();
} }
} }

View file

@ -16,6 +16,7 @@ package google.registry.tmch;
import static google.registry.tmch.TmchTestData.loadSmd; import static google.registry.tmch.TmchTestData.loadSmd;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.testing.AppEngineRule; import google.registry.testing.AppEngineRule;
import google.registry.testing.ExceptionRule; import google.registry.testing.ExceptionRule;
import google.registry.testing.FakeClock; import google.registry.testing.FakeClock;
@ -58,11 +59,11 @@ public class TmchXmlSignatureTest {
@Before @Before
public void before() throws Exception { public void before() throws Exception {
inject.setStaticField(TmchCertificateAuthority.class, "clock", clock); inject.setStaticField(TmchCertificateAuthority.class, "clock", clock);
tmchXmlSignature = new TmchXmlSignature(new TmchCertificateAuthority(true)); tmchXmlSignature = new TmchXmlSignature(new TmchCertificateAuthority(TmchCaMode.PILOT));
} }
public void wrongCertificateAuthority() throws Exception { public void wrongCertificateAuthority() throws Exception {
tmchXmlSignature = new TmchXmlSignature(new TmchCertificateAuthority(false)); tmchXmlSignature = new TmchXmlSignature(new TmchCertificateAuthority(TmchCaMode.PRODUCTION));
smdData = loadSmd("active/Court-Agent-Arabic-Active.smd"); smdData = loadSmd("active/Court-Agent-Arabic-Active.smd");
thrown.expectRootCause(SignatureException.class, "Signature does not match"); thrown.expectRootCause(SignatureException.class, "Signature does not match");
tmchXmlSignature.verify(smdData); tmchXmlSignature.verify(smdData);

View file

@ -15,6 +15,7 @@
package google.registry.tools; package google.registry.tools;
import static com.google.common.io.BaseEncoding.base64; import static com.google.common.io.BaseEncoding.base64;
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PILOT;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newDomainApplication; import static google.registry.testing.DatastoreHelper.newDomainApplication;
@ -69,7 +70,7 @@ public class UpdateSmdCommandTest extends CommandTestCase<UpdateSmdCommand> {
.setEncodedSignedMarks(ImmutableList.of(EncodedSignedMark.create("base64", "garbage"))) .setEncodedSignedMarks(ImmutableList.of(EncodedSignedMark.create("base64", "garbage")))
.build()); .build());
command.tmchUtils = command.tmchUtils =
new DomainFlowTmchUtils(new TmchXmlSignature(new TmchCertificateAuthority(true))); new DomainFlowTmchUtils(new TmchXmlSignature(new TmchCertificateAuthority(PILOT)));
} }
private DomainApplication reloadDomainApplication() { private DomainApplication reloadDomainApplication() {