Validate Certificate on Login (#919)

* Check certificate matches saved one on login

* Add tests

* refactoring

* fix warning messages
This commit is contained in:
sarahcaseybot 2021-01-19 17:06:26 -05:00 committed by GitHub
parent 9b5805f145
commit 3b679058b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 148 additions and 40 deletions

View file

@ -42,6 +42,9 @@ import javax.servlet.http.HttpServletRequest;
* <dl> * <dl>
* <dt>X-SSL-Certificate * <dt>X-SSL-Certificate
* <dd>This field should contain a base64 encoded digest of the client's TLS certificate. It is * <dd>This field should contain a base64 encoded digest of the client's TLS certificate. It is
* used only if the validation of the full certificate fails.
* <dt>X-SSL-Full-Certificate
* <dd>This field should contain a base64 encoding of the client's TLS certificate. It is
* validated during an EPP login command against a known good value that is transmitted out of * validated during an EPP login command against a known good value that is transmitted out of
* band. * band.
* <dt>X-Forwarded-For * <dt>X-Forwarded-For
@ -55,15 +58,18 @@ public class TlsCredentials implements TransportCredentials {
private final boolean requireSslCertificates; private final boolean requireSslCertificates;
private final Optional<String> clientCertificateHash; private final Optional<String> clientCertificateHash;
private final Optional<String> clientCertificate;
private final Optional<InetAddress> clientInetAddr; private final Optional<InetAddress> clientInetAddr;
@Inject @Inject
public TlsCredentials( public TlsCredentials(
@Config("requireSslCertificates") boolean requireSslCertificates, @Config("requireSslCertificates") boolean requireSslCertificates,
@Header("X-SSL-Certificate") Optional<String> clientCertificateHash, @Header("X-SSL-Certificate") Optional<String> clientCertificateHash,
@Header("X-SSL-Full-Certificate") Optional<String> clientCertificate,
@Header("X-Forwarded-For") Optional<String> clientAddress) { @Header("X-Forwarded-For") Optional<String> clientAddress) {
this.requireSslCertificates = requireSslCertificates; this.requireSslCertificates = requireSslCertificates;
this.clientCertificateHash = clientCertificateHash; this.clientCertificateHash = clientCertificateHash;
this.clientCertificate = clientCertificate;
this.clientInetAddr = clientAddress.map(TlsCredentials::parseInetAddress); this.clientInetAddr = clientAddress.map(TlsCredentials::parseInetAddress);
} }
@ -91,7 +97,7 @@ public class TlsCredentials implements TransportCredentials {
ImmutableList<CidrAddressBlock> ipAddressAllowList = registrar.getIpAddressAllowList(); ImmutableList<CidrAddressBlock> ipAddressAllowList = registrar.getIpAddressAllowList();
if (ipAddressAllowList.isEmpty()) { if (ipAddressAllowList.isEmpty()) {
logger.atInfo().log( logger.atInfo().log(
"Skipping IP allow list check because %s doesn't have an IP allow list", "Skipping IP allow list check because %s doesn't have an IP allow list.",
registrar.getClientId()); registrar.getClientId());
return; return;
} }
@ -115,11 +121,46 @@ public class TlsCredentials implements TransportCredentials {
/** /**
* Verifies client SSL certificate is permitted to issue commands as {@code registrar}. * Verifies client SSL certificate is permitted to issue commands as {@code registrar}.
* *
* @throws MissingRegistrarCertificateException if frontend didn't send certificate hash header * @throws MissingRegistrarCertificateException if frontend didn't send certificate header
* @throws BadRegistrarCertificateException if registrar requires certificate and it didn't match * @throws BadRegistrarCertificateException if registrar requires certificate and it didn't match
*/ */
@VisibleForTesting @VisibleForTesting
void validateCertificate(Registrar registrar) throws AuthenticationErrorException { void validateCertificate(Registrar registrar) throws AuthenticationErrorException {
// Check that certificate is present in registrar object
if (!registrar.getClientCertificate().isPresent()
&& !registrar.getFailoverClientCertificate().isPresent()) {
// Log an error and validate using certificate hash instead
// TODO(sarahbot): throw a RegistrarCertificateNotConfiguredException once hash is no longer
// used as failover
logger.atWarning().log(
"There is no certificate configured for registrar %s.", registrar.getClientId());
}
// Check that the request included the full certificate
else if (!clientCertificate.isPresent()) {
// Log an error and validate using certificate hash instead
// TODO(sarahbot): throw a MissingRegistrarCertificateException once hash is no longer used as
// failover
logger.atWarning().log(
"Request from registrar %s did not include X-SSL-Full-Certificate.",
registrar.getClientId());
} else {
// Check if the certificate is equal to the one on file for the registrar.
if (clientCertificate.equals(registrar.getClientCertificate())
|| clientCertificate.equals(registrar.getFailoverClientCertificate())) {
// successfully validated, return here since hash validation is not necessary
return;
}
// Log an error and validate using certificate hash instead
// TODO(sarahbot): throw a BadRegistrarCertificateException once hash is no longer used as
// failover
logger.atWarning().log("Non-matching certificate for registrar %s.", registrar.getClientId());
}
validateCertificateHash(registrar);
}
private void validateCertificateHash(Registrar registrar) throws AuthenticationErrorException {
// Check the certificate hash as a failover
// TODO(sarahbot): Remove hash checks once certificate checks are working.
if (!registrar.getClientCertificateHash().isPresent() if (!registrar.getClientCertificateHash().isPresent()
&& !registrar.getFailoverClientCertificateHash().isPresent()) { && !registrar.getFailoverClientCertificateHash().isPresent()) {
if (requireSslCertificates) { if (requireSslCertificates) {
@ -130,14 +171,17 @@ public class TlsCredentials implements TransportCredentials {
return; return;
} }
} }
// Check that the request included the certificate hash
if (!clientCertificateHash.isPresent()) { if (!clientCertificateHash.isPresent()) {
logger.atInfo().log("Request did not include X-SSL-Certificate"); logger.atInfo().log(
"Request from registrar %s did not include X-SSL-Certificate.", registrar.getClientId());
throw new MissingRegistrarCertificateException(); throw new MissingRegistrarCertificateException();
} }
// Check if the certificate hash is equal to the one on file for the registrar.
if (!clientCertificateHash.equals(registrar.getClientCertificateHash()) if (!clientCertificateHash.equals(registrar.getClientCertificateHash())
&& !clientCertificateHash.equals(registrar.getFailoverClientCertificateHash())) { && !clientCertificateHash.equals(registrar.getFailoverClientCertificateHash())) {
logger.atWarning().log( logger.atWarning().log(
"bad certificate hash (%s) for %s, wanted either %s or %s", "Non-matching certificate hash (%s) for %s, wanted either %s or %s.",
clientCertificateHash, clientCertificateHash,
registrar.getClientId(), registrar.getClientId(),
registrar.getClientCertificateHash(), registrar.getClientCertificateHash(),
@ -202,6 +246,14 @@ public class TlsCredentials implements TransportCredentials {
return extractOptionalHeader(req, "X-SSL-Certificate"); return extractOptionalHeader(req, "X-SSL-Certificate");
} }
@Provides
@Header("X-SSL-Full-Certificate")
static Optional<String> provideClientCertificate(HttpServletRequest req) {
// Note: This header is actually required, we just want to handle its absence explicitly
// by throwing an EPP exception rather than a generic Bad Request exception.
return extractOptionalHeader(req, "X-SSL-Full_Certificate");
}
@Provides @Provides
@Header("X-Forwarded-For") @Header("X-Forwarded-For")
static Optional<String> provideForwardedFor(HttpServletRequest req) { static Optional<String> provideForwardedFor(HttpServletRequest req) {

View file

@ -55,6 +55,7 @@ final class ValidateLoginCredentialsCommand implements CommandWithRemoteApi {
validateWith = PathParameter.InputFile.class) validateWith = PathParameter.InputFile.class)
private Path clientCertificatePath; private Path clientCertificatePath;
// TODO(sarahbot@): Remove this after hash fallback is removed
@Nullable @Nullable
@Parameter( @Parameter(
names = {"-h", "--cert_hash"}, names = {"-h", "--cert_hash"},
@ -72,15 +73,19 @@ final class ValidateLoginCredentialsCommand implements CommandWithRemoteApi {
checkArgument( checkArgument(
clientCertificatePath == null || isNullOrEmpty(clientCertificateHash), clientCertificatePath == null || isNullOrEmpty(clientCertificateHash),
"Can't specify both --cert_hash and --cert_file"); "Can't specify both --cert_hash and --cert_file");
String clientCertificate = "";
if (clientCertificatePath != null) { if (clientCertificatePath != null) {
clientCertificateHash = getCertificateHash( clientCertificate = new String(Files.readAllBytes(clientCertificatePath), US_ASCII);
loadCertificate(new String(Files.readAllBytes(clientCertificatePath), US_ASCII))); clientCertificateHash = getCertificateHash(loadCertificate(clientCertificate));
} }
Registrar registrar = Registrar registrar =
checkArgumentPresent( checkArgumentPresent(
Registrar.loadByClientId(clientId), "Registrar %s not found", clientId); Registrar.loadByClientId(clientId), "Registrar %s not found", clientId);
new TlsCredentials( new TlsCredentials(
true, Optional.ofNullable(clientCertificateHash), Optional.ofNullable(clientIpAddress)) true,
Optional.ofNullable(clientCertificateHash),
Optional.ofNullable(clientCertificate),
Optional.ofNullable(clientIpAddress))
.validate(registrar, password); .validate(registrar, password);
checkState( checkState(
registrar.isLive(), "Registrar %s has non-live state: %s", clientId, registrar.getState()); registrar.isLive(), "Registrar %s has non-live state: %s", clientId, registrar.getState());

View file

@ -34,10 +34,13 @@ class EppLoginTlsTest extends EppTestCase {
final AppEngineExtension appEngine = final AppEngineExtension appEngine =
AppEngineExtension.builder().withDatastoreAndCloudSql().build(); AppEngineExtension.builder().withDatastoreAndCloudSql().build();
void setClientCertificateHash(String clientCertificateHash) { void setCredentials(String clientCertificateHash, String clientCertificate) {
setTransportCredentials( setTransportCredentials(
new TlsCredentials( new TlsCredentials(
true, Optional.ofNullable(clientCertificateHash), Optional.of("192.168.1.100:54321"))); true,
Optional.ofNullable(clientCertificateHash),
Optional.ofNullable(clientCertificate),
Optional.of("192.168.1.100:54321")));
} }
@BeforeEach @BeforeEach
@ -57,14 +60,14 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testLoginLogout() throws Exception { void testLoginLogout() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT_HASH); setCredentials(CertificateSamples.SAMPLE_CERT_HASH, CertificateSamples.SAMPLE_CERT);
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2"); assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
} }
@Test @Test
void testLogin_wrongPasswordFails() throws Exception { void testLogin_wrongPasswordFails() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT_HASH); setCredentials(CertificateSamples.SAMPLE_CERT_HASH, CertificateSamples.SAMPLE_CERT);
// For TLS login, we also check the epp xml password. // For TLS login, we also check the epp xml password.
assertThatLogin("NewRegistrar", "incorrect") assertThatLogin("NewRegistrar", "incorrect")
.hasResponse( .hasResponse(
@ -74,7 +77,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testMultiLogin() throws Exception { void testMultiLogin() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT_HASH); setCredentials(CertificateSamples.SAMPLE_CERT_HASH, CertificateSamples.SAMPLE_CERT);
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2"); assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2"); assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
@ -88,7 +91,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testNonAuthedLogin_fails() throws Exception { void testNonAuthedLogin_fails() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT_HASH); setCredentials(CertificateSamples.SAMPLE_CERT_HASH, CertificateSamples.SAMPLE_CERT);
assertThatLogin("TheRegistrar", "password2") assertThatLogin("TheRegistrar", "password2")
.hasResponse( .hasResponse(
"response_error.xml", "response_error.xml",
@ -98,7 +101,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testBadCertificate_failsBadCertificate2200() throws Exception { void testBadCertificate_failsBadCertificate2200() throws Exception {
setClientCertificateHash("laffo"); setCredentials("laffo", "cert");
assertThatLogin("NewRegistrar", "foo-BAR2") assertThatLogin("NewRegistrar", "foo-BAR2")
.hasResponse( .hasResponse(
"response_error.xml", "response_error.xml",
@ -108,7 +111,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testGfeDidntProvideClientCertificate_failsMissingCertificate2200() throws Exception { void testGfeDidntProvideClientCertificate_failsMissingCertificate2200() throws Exception {
setClientCertificateHash(null); setCredentials(null, null);
assertThatLogin("NewRegistrar", "foo-BAR2") assertThatLogin("NewRegistrar", "foo-BAR2")
.hasResponse( .hasResponse(
"response_error.xml", "response_error.xml",
@ -117,7 +120,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testGoodPrimaryCertificate() throws Exception { void testGoodPrimaryCertificate() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT_HASH); setCredentials(CertificateSamples.SAMPLE_CERT_HASH, CertificateSamples.SAMPLE_CERT);
DateTime now = DateTime.now(UTC); DateTime now = DateTime.now(UTC);
persistResource( persistResource(
loadRegistrar("NewRegistrar") loadRegistrar("NewRegistrar")
@ -130,7 +133,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testGoodFailoverCertificate() throws Exception { void testGoodFailoverCertificate() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT2_HASH); setCredentials(CertificateSamples.SAMPLE_CERT2_HASH, CertificateSamples.SAMPLE_CERT2);
DateTime now = DateTime.now(UTC); DateTime now = DateTime.now(UTC);
persistResource( persistResource(
loadRegistrar("NewRegistrar") loadRegistrar("NewRegistrar")
@ -143,7 +146,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testMissingPrimaryCertificateButHasFailover_usesFailover() throws Exception { void testMissingPrimaryCertificateButHasFailover_usesFailover() throws Exception {
setClientCertificateHash(CertificateSamples.SAMPLE_CERT2_HASH); setCredentials(CertificateSamples.SAMPLE_CERT2_HASH, CertificateSamples.SAMPLE_CERT2);
DateTime now = DateTime.now(UTC); DateTime now = DateTime.now(UTC);
persistResource( persistResource(
loadRegistrar("NewRegistrar") loadRegistrar("NewRegistrar")
@ -156,7 +159,7 @@ class EppLoginTlsTest extends EppTestCase {
@Test @Test
void testRegistrarHasNoCertificatesOnFile_fails() throws Exception { void testRegistrarHasNoCertificatesOnFile_fails() throws Exception {
setClientCertificateHash("laffo"); setCredentials("laffo", "cert");
DateTime now = DateTime.now(UTC); DateTime now = DateTime.now(UTC);
persistResource( persistResource(
loadRegistrar("NewRegistrar") loadRegistrar("NewRegistrar")

View file

@ -138,7 +138,8 @@ class FlowRunnerTest {
@Test @Test
void testRun_loggingStatement_tlsCredentials() throws Exception { void testRun_loggingStatement_tlsCredentials() throws Exception {
flowRunner.credentials = flowRunner.credentials =
new TlsCredentials(true, Optional.of("abc123def"), Optional.of("127.0.0.1")); new TlsCredentials(
true, Optional.of("abc123def"), Optional.of("cert"), Optional.of("127.0.0.1"));
flowRunner.run(eppMetricBuilder); flowRunner.run(eppMetricBuilder);
assertThat(Splitter.on("\n\t").split(findFirstLogMessageByPrefix(handler, "EPP Command\n\t"))) assertThat(Splitter.on("\n\t").split(findFirstLogMessageByPrefix(handler, "EPP Command\n\t")))
.contains("TlsCredentials{clientCertificateHash=abc123def, clientAddress=/127.0.0.1}"); .contains("TlsCredentials{clientCertificateHash=abc123def, clientAddress=/127.0.0.1}");

View file

@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.TlsCredentials.BadRegistrarIpAddressException; import google.registry.flows.TlsCredentials.BadRegistrarIpAddressException;
import google.registry.flows.TlsCredentials.MissingRegistrarCertificateException; import google.registry.flows.TlsCredentials.MissingRegistrarCertificateException;
import google.registry.flows.TlsCredentials.RegistrarCertificateNotConfiguredException;
import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar;
import google.registry.testing.AppEngineExtension; import google.registry.testing.AppEngineExtension;
import google.registry.util.CidrAddressBlock; import google.registry.util.CidrAddressBlock;
@ -50,8 +51,9 @@ final class TlsCredentialsTest {
} }
@Test @Test
void testClientCertificateHash_missing() { void testClientCertificateAndHash_missing() {
TlsCredentials tls = new TlsCredentials(true, Optional.empty(), Optional.of("192.168.1.1")); TlsCredentials tls =
new TlsCredentials(true, Optional.empty(), Optional.empty(), Optional.of("192.168.1.1"));
persistResource( persistResource(
loadRegistrar("TheRegistrar") loadRegistrar("TheRegistrar")
.asBuilder() .asBuilder()
@ -64,7 +66,8 @@ final class TlsCredentialsTest {
@Test @Test
void test_missingIpAddress_doesntAllowAccess() { void test_missingIpAddress_doesntAllowAccess() {
TlsCredentials tls = new TlsCredentials(false, Optional.of("certHash"), Optional.empty()); TlsCredentials tls =
new TlsCredentials(false, Optional.of("certHash"), Optional.empty(), Optional.empty());
persistResource( persistResource(
loadRegistrar("TheRegistrar") loadRegistrar("TheRegistrar")
.asBuilder() .asBuilder()
@ -79,7 +82,41 @@ final class TlsCredentialsTest {
@Test @Test
void test_validateCertificate_canBeConfiguredToBypassCertHashes() throws Exception { void test_validateCertificate_canBeConfiguredToBypassCertHashes() throws Exception {
TlsCredentials tls = TlsCredentials tls =
new TlsCredentials(false, Optional.of("certHash"), Optional.of("192.168.1.1")); new TlsCredentials(
false, Optional.of("certHash"), Optional.of("cert"), Optional.of("192.168.1.1"));
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
.setClientCertificate(null, DateTime.now(UTC))
.setFailoverClientCertificate(null, DateTime.now(UTC))
.build());
// This would throw a RegistrarCertificateNotConfiguredException if cert hashes were not
// bypassed
tls.validateCertificate(Registrar.loadByClientId("TheRegistrar").get());
}
void testProvideClientCertificate() {
HttpServletRequest req = mock(HttpServletRequest.class);
when(req.getHeader("X-SSL-Full-Certificate")).thenReturn("data");
assertThat(TlsCredentials.EppTlsModule.provideClientCertificate(req)).isEqualTo("data");
}
@Test
void testClientCertificate_notConfigured() {
TlsCredentials tls =
new TlsCredentials(
true, Optional.of("hash"), Optional.of(SAMPLE_CERT), Optional.of("192.168.1.1"));
persistResource(loadRegistrar("TheRegistrar").asBuilder().build());
assertThrows(
RegistrarCertificateNotConfiguredException.class,
() -> tls.validateCertificate(Registrar.loadByClientId("TheRegistrar").get()));
}
@Test
void test_validateCertificate_canBeConfiguredToBypassCerts() throws Exception {
TlsCredentials tls =
new TlsCredentials(
false, Optional.of("certHash"), Optional.of("cert"), Optional.of("192.168.1.1"));
persistResource( persistResource(
loadRegistrar("TheRegistrar") loadRegistrar("TheRegistrar")
.asBuilder() .asBuilder()

View file

@ -33,9 +33,11 @@ import org.junit.jupiter.api.Test;
/** Unit tests for {@link LoginFlow} when accessed via a TLS transport. */ /** Unit tests for {@link LoginFlow} when accessed via a TLS transport. */
public class LoginFlowViaTlsTest extends LoginFlowTestCase { public class LoginFlowViaTlsTest extends LoginFlowTestCase {
private static final Optional<String> GOOD_CERT = private static final Optional<String> GOOD_CERT = Optional.of(CertificateSamples.SAMPLE_CERT);
private static final Optional<String> GOOD_CERT_HASH =
Optional.of(CertificateSamples.SAMPLE_CERT_HASH); Optional.of(CertificateSamples.SAMPLE_CERT_HASH);
private static final Optional<String> BAD_CERT = private static final Optional<String> BAD_CERT = Optional.of(CertificateSamples.SAMPLE_CERT2);
private static final Optional<String> BAD_CERT_HASH =
Optional.of(CertificateSamples.SAMPLE_CERT2_HASH); Optional.of(CertificateSamples.SAMPLE_CERT2_HASH);
private static final Optional<String> GOOD_IP = Optional.of("192.168.1.1"); private static final Optional<String> GOOD_IP = Optional.of("192.168.1.1");
private static final Optional<String> BAD_IP = Optional.of("1.1.1.1"); private static final Optional<String> BAD_IP = Optional.of("1.1.1.1");
@ -53,7 +55,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
@Test @Test
void testSuccess_withGoodCredentials() throws Exception { void testSuccess_withGoodCredentials() throws Exception {
persistResource(getRegistrarBuilder().build()); persistResource(getRegistrarBuilder().build());
credentials = new TlsCredentials(true, GOOD_CERT, GOOD_IP); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, GOOD_IP);
doSuccessfulTest("login_valid.xml"); doSuccessfulTest("login_valid.xml");
} }
@ -64,7 +66,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
.setIpAddressAllowList( .setIpAddressAllowList(
ImmutableList.of(CidrAddressBlock.create("2001:db8:0:0:0:0:1:1/32"))) ImmutableList.of(CidrAddressBlock.create("2001:db8:0:0:0:0:1:1/32")))
.build()); .build());
credentials = new TlsCredentials(true, GOOD_CERT, GOOD_IPV6); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, GOOD_IPV6);
doSuccessfulTest("login_valid.xml"); doSuccessfulTest("login_valid.xml");
} }
@ -75,7 +77,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
.setIpAddressAllowList( .setIpAddressAllowList(
ImmutableList.of(CidrAddressBlock.create("2001:db8:0:0:0:0:1:1/32"))) ImmutableList.of(CidrAddressBlock.create("2001:db8:0:0:0:0:1:1/32")))
.build()); .build());
credentials = new TlsCredentials(true, GOOD_CERT, GOOD_IPV6); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, GOOD_IPV6);
doSuccessfulTest("login_valid.xml"); doSuccessfulTest("login_valid.xml");
} }
@ -85,21 +87,29 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
getRegistrarBuilder() getRegistrarBuilder()
.setIpAddressAllowList(ImmutableList.of(CidrAddressBlock.create("192.168.1.255/24"))) .setIpAddressAllowList(ImmutableList.of(CidrAddressBlock.create("192.168.1.255/24")))
.build()); .build());
credentials = new TlsCredentials(true, GOOD_CERT, GOOD_IP); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, GOOD_IP);
doSuccessfulTest("login_valid.xml"); doSuccessfulTest("login_valid.xml");
} }
@Test @Test
void testFailure_incorrectClientCertificateHash() { void testFailure_incorrectClientCertificateHash() {
persistResource(getRegistrarBuilder().build()); persistResource(getRegistrarBuilder().build());
credentials = new TlsCredentials(true, BAD_CERT, GOOD_IP); credentials = new TlsCredentials(true, BAD_CERT_HASH, BAD_CERT, GOOD_IP);
doFailingTest("login_valid.xml", BadRegistrarCertificateException.class); doFailingTest("login_valid.xml", BadRegistrarCertificateException.class);
} }
@Test @Test
void testFailure_missingClientCertificateHash() { // TODO(Sarahbot): This should fail once hash fallback is removed
void testSuccess_missingClientCertificate() throws Exception {
persistResource(getRegistrarBuilder().build()); persistResource(getRegistrarBuilder().build());
credentials = new TlsCredentials(true, Optional.empty(), GOOD_IP); credentials = new TlsCredentials(true, GOOD_CERT_HASH, Optional.empty(), GOOD_IP);
doSuccessfulTest("login_valid.xml");
}
@Test
void testFailure_missingClientCertificateAndHash() {
persistResource(getRegistrarBuilder().build());
credentials = new TlsCredentials(true, Optional.empty(), Optional.empty(), GOOD_IP);
doFailingTest("login_valid.xml", MissingRegistrarCertificateException.class); doFailingTest("login_valid.xml", MissingRegistrarCertificateException.class);
} }
@ -112,7 +122,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32), CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32),
CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128))) CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128)))
.build()); .build());
credentials = new TlsCredentials(true, GOOD_CERT, Optional.empty()); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, Optional.empty());
doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class); doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class);
} }
@ -125,7 +135,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32), CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32),
CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128))) CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128)))
.build()); .build());
credentials = new TlsCredentials(true, GOOD_CERT, BAD_IP); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, BAD_IP);
doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class); doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class);
} }
@ -138,7 +148,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32), CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32),
CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128))) CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128)))
.build()); .build());
credentials = new TlsCredentials(true, GOOD_CERT, BAD_IPV6); credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, BAD_IPV6);
doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class); doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class);
} }
} }

View file

@ -64,7 +64,7 @@ class ValidateLoginCredentialsCommandTest extends CommandTestCase<ValidateLoginC
runCommand( runCommand(
"--client=NewRegistrar", "--client=NewRegistrar",
"--password=" + PASSWORD, "--password=" + PASSWORD,
"--cert_hash=" + CERT_HASH, "--cert_file=" + getCertFilename(CertificateSamples.SAMPLE_CERT),
"--ip_address=" + CLIENT_IP); "--ip_address=" + CLIENT_IP);
} }
@ -83,7 +83,7 @@ class ValidateLoginCredentialsCommandTest extends CommandTestCase<ValidateLoginC
runCommand( runCommand(
"--client=NewRegistrar", "--client=NewRegistrar",
"--password=" + PASSWORD, "--password=" + PASSWORD,
"--cert_hash=" + CERT_HASH, "--cert_file=" + getCertFilename(CertificateSamples.SAMPLE_CERT),
"--ip_address=" + CLIENT_IP)); "--ip_address=" + CLIENT_IP));
assertThat(thrown) assertThat(thrown)
.hasMessageThat() .hasMessageThat()
@ -91,7 +91,7 @@ class ValidateLoginCredentialsCommandTest extends CommandTestCase<ValidateLoginC
} }
@Test @Test
void testFailure_loginWithBadPassword() { void testFailure_loginWithBadPassword() throws Exception {
EppException thrown = EppException thrown =
assertThrows( assertThrows(
BadRegistrarPasswordException.class, BadRegistrarPasswordException.class,
@ -99,7 +99,7 @@ class ValidateLoginCredentialsCommandTest extends CommandTestCase<ValidateLoginC
runCommand( runCommand(
"--client=NewRegistrar", "--client=NewRegistrar",
"--password=" + new StringBuilder(PASSWORD).reverse(), "--password=" + new StringBuilder(PASSWORD).reverse(),
"--cert_hash=" + CERT_HASH, "--cert_file=" + getCertFilename(CertificateSamples.SAMPLE_CERT),
"--ip_address=" + CLIENT_IP)); "--ip_address=" + CLIENT_IP));
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }