diff --git a/java/google/registry/flows/EppConsoleAction.java b/java/google/registry/flows/EppConsoleAction.java index 3411892a3..88e875c34 100644 --- a/java/google/registry/flows/EppConsoleAction.java +++ b/java/google/registry/flows/EppConsoleAction.java @@ -41,7 +41,8 @@ public class EppConsoleAction implements Runnable { @Override public void run() { eppRequestHandler.executeEpp( - new HttpSessionMetadata(new GaeUserCredentials(getUserService().getCurrentUser()), session), + new HttpSessionMetadata(session), + new GaeUserCredentials(getUserService().getCurrentUser()), inputXmlBytes); } } diff --git a/java/google/registry/flows/EppController.java b/java/google/registry/flows/EppController.java index 667e83644..be81eab93 100644 --- a/java/google/registry/flows/EppController.java +++ b/java/google/registry/flows/EppController.java @@ -51,7 +51,10 @@ public final class EppController { * Read an EPP envelope from the client, find the matching flow, execute it, and return * the response marshalled to a byte array. */ - public byte[] handleEppCommand(SessionMetadata sessionMetadata, byte[] inputXmlBytes) { + public byte[] handleEppCommand( + SessionMetadata sessionMetadata, + TransportCredentials credentials, + byte[] inputXmlBytes) { Trid trid = null; try { EppInput eppInput = unmarshal(EppInput.class, inputXmlBytes); @@ -68,6 +71,7 @@ public final class EppController { eppInput, trid, sessionMetadata, + credentials, inputXmlBytes, metrics, clock); diff --git a/java/google/registry/flows/EppRequestHandler.java b/java/google/registry/flows/EppRequestHandler.java index 95ea8bf71..8719bd672 100644 --- a/java/google/registry/flows/EppRequestHandler.java +++ b/java/google/registry/flows/EppRequestHandler.java @@ -39,10 +39,13 @@ public class EppRequestHandler { @Inject EppRequestHandler() {} /** Handle an EPP request and write out a servlet response. */ - public void executeEpp(SessionMetadata sessionMetadata, byte[] inputXmlBytes) { + public void executeEpp( + SessionMetadata sessionMetadata, + TransportCredentials credentials, + byte[] inputXmlBytes) { try { response.setPayload(new String( - eppController.handleEppCommand(sessionMetadata, inputXmlBytes), UTF_8)); + eppController.handleEppCommand(sessionMetadata, credentials, inputXmlBytes), UTF_8)); response.setContentType(APPLICATION_EPP_XML); // Note that we always return 200 (OK) even if the EppController returns an error response. // This is because returning an non-OK HTTP status code will cause the proxy server to diff --git a/java/google/registry/flows/EppTlsAction.java b/java/google/registry/flows/EppTlsAction.java index 233f66257..ae4563075 100644 --- a/java/google/registry/flows/EppTlsAction.java +++ b/java/google/registry/flows/EppTlsAction.java @@ -46,7 +46,7 @@ public class EppTlsAction implements Runnable { if (!tlsCredentials.hasSni()) { logger.warning("Request did not include required SNI header."); } - eppRequestHandler.executeEpp(new HttpSessionMetadata(tlsCredentials, session), inputXmlBytes); + eppRequestHandler.executeEpp(new HttpSessionMetadata(session), tlsCredentials, inputXmlBytes); } } diff --git a/java/google/registry/flows/EppToolAction.java b/java/google/registry/flows/EppToolAction.java index 52fc4a701..4a8da23d8 100644 --- a/java/google/registry/flows/EppToolAction.java +++ b/java/google/registry/flows/EppToolAction.java @@ -54,6 +54,7 @@ public class EppToolAction implements Runnable { dryRun, ProtocolDefinition.getVisibleServiceExtensionUris(), SessionSource.TOOL), + new PasswordOnlyTransportCredentials(), xml.getBytes(UTF_8)); } @@ -61,7 +62,7 @@ public class EppToolAction implements Runnable { @Module public static final class EppToolModule { - // TODO(b/29139545): Make parameters consistent across the graph. @Parameter("dryRun") is + // TODO(b/29139545): Make parameters consistent across the graph. @Parameter("dryRun") is // already provided elsewhere in the graph and happens to work for us but that's just luck. @Provides diff --git a/java/google/registry/flows/Flow.java b/java/google/registry/flows/Flow.java index e4b2c6fa0..c65361d2c 100644 --- a/java/google/registry/flows/Flow.java +++ b/java/google/registry/flows/Flow.java @@ -42,6 +42,7 @@ public abstract class Flow { protected EppInput eppInput; protected SessionMetadata sessionMetadata; + protected TransportCredentials credentials; protected Trid trid; protected DateTime now; protected byte[] inputXmlBytes; @@ -101,11 +102,13 @@ public abstract class Flow { EppInput eppInput, Trid trid, SessionMetadata sessionMetadata, + TransportCredentials credentials, DateTime now, byte[] inputXmlBytes) throws EppException { this.eppInput = eppInput; this.trid = trid; this.sessionMetadata = sessionMetadata; + this.credentials = credentials; this.now = now; this.superuser = sessionMetadata.isSuperuser(); this.inputXmlBytes = inputXmlBytes; diff --git a/java/google/registry/flows/FlowRunner.java b/java/google/registry/flows/FlowRunner.java index 6a04791e7..734778666 100644 --- a/java/google/registry/flows/FlowRunner.java +++ b/java/google/registry/flows/FlowRunner.java @@ -36,7 +36,7 @@ import org.joda.time.DateTime; /** Run a flow, either transactionally or not, with logging and retrying as needed. */ public class FlowRunner { - private static final String COMMAND_LOG_FORMAT = "EPP Command" + Strings.repeat("\n\t%s", 4); + private static final String COMMAND_LOG_FORMAT = "EPP Command" + Strings.repeat("\n\t%s", 5); private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); @@ -44,6 +44,7 @@ public class FlowRunner { private final EppInput eppInput; private final Trid trid; private final SessionMetadata sessionMetadata; + private final TransportCredentials credentials; private final byte[] inputXmlBytes; private final EppMetrics metrics; private final Clock clock; @@ -53,13 +54,16 @@ public class FlowRunner { EppInput eppInput, Trid trid, SessionMetadata sessionMetadata, + TransportCredentials credentials, byte[] inputXmlBytes, final EppMetrics metrics, Clock clock) { + credentials.toString(); this.flowClass = flowClass; this.eppInput = eppInput; this.trid = trid; this.sessionMetadata = sessionMetadata; + this.credentials = credentials; this.inputXmlBytes = inputXmlBytes; this.metrics = metrics; this.clock = clock; @@ -72,7 +76,8 @@ public class FlowRunner { trid.getServerTransactionId(), clientId, sessionMetadata, - prettyPrint(inputXmlBytes).replaceAll("\n", "\n\t")); + prettyPrint(inputXmlBytes).replaceAll("\n", "\n\t"), + credentials); if (!isTransactional()) { if (metrics != null) { metrics.incrementAttempts(); @@ -124,6 +129,7 @@ public class FlowRunner { eppInput, trid, sessionMetadata, + credentials, now, inputXmlBytes); } diff --git a/java/google/registry/flows/GaeUserCredentials.java b/java/google/registry/flows/GaeUserCredentials.java index 1bc25191d..a3b4390ee 100644 --- a/java/google/registry/flows/GaeUserCredentials.java +++ b/java/google/registry/flows/GaeUserCredentials.java @@ -38,12 +38,8 @@ public class GaeUserCredentials implements TransportCredentials { } @Override - public boolean performsLoginCheck() { - return true; - } - - @Override - public void validate(Registrar r) throws AuthenticationErrorException { + public void validate(Registrar registrar, String ignoredPassword) + throws AuthenticationErrorException { if (gaeUser == null) { throw new UserNotLoggedInException(); } @@ -53,7 +49,7 @@ public class GaeUserCredentials implements TransportCredentials { } // Check Registrar's contacts to see if any are associated with this gaeUserId. final String gaeUserId = gaeUser.getUserId(); - for (RegistrarContact rc : r.getContacts()) { + for (RegistrarContact rc : registrar.getContacts()) { if (gaeUserId.equals(rc.getGaeUserId())) { return; } diff --git a/java/google/registry/flows/HttpSessionMetadata.java b/java/google/registry/flows/HttpSessionMetadata.java index fb6da53d2..37b6d439e 100644 --- a/java/google/registry/flows/HttpSessionMetadata.java +++ b/java/google/registry/flows/HttpSessionMetadata.java @@ -24,9 +24,8 @@ public class HttpSessionMetadata extends SessionMetadata { private final HttpSession session; private boolean isValid = true; - public HttpSessionMetadata(TransportCredentials credentials, HttpSession session) { + public HttpSessionMetadata(HttpSession session) { this.session = session; - setTransportCredentials(credentials); } @Override diff --git a/java/google/registry/flows/PasswordOnlyTransportCredentials.java b/java/google/registry/flows/PasswordOnlyTransportCredentials.java new file mode 100644 index 000000000..8a0955d2a --- /dev/null +++ b/java/google/registry/flows/PasswordOnlyTransportCredentials.java @@ -0,0 +1,28 @@ +// Copyright 2016 The Domain Registry Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.flows; + +import google.registry.flows.EppException.AuthenticationErrorException; +import google.registry.model.registrar.Registrar; + +/** A transport credentials that validates the registrar's EPP password and nothing else. */ +public class PasswordOnlyTransportCredentials implements TransportCredentials { + @Override + public void validate(Registrar r, String password) throws AuthenticationErrorException { + if (!r.testPassword(password)) { + throw new BadRegistrarPasswordException(); + } + } +} diff --git a/java/google/registry/flows/SessionMetadata.java b/java/google/registry/flows/SessionMetadata.java index e19dc2777..29c1a4b80 100644 --- a/java/google/registry/flows/SessionMetadata.java +++ b/java/google/registry/flows/SessionMetadata.java @@ -46,9 +46,7 @@ public abstract class SessionMetadata { NONE } - private TransportCredentials credentials; - - /** The key used for looking up the current client id on the session object. */ + /** The key used for looking up the current client id on the session object. */ protected static final String CLIENT_ID_KEY = "CLIENT_ID"; /** The key used for looking up the superuser bit on the session object. */ @@ -91,16 +89,6 @@ public abstract class SessionMetadata { return clazz.cast(getProperty(key)); } - public TransportCredentials getTransportCredentials() { - checkValid(); - return credentials; - } - - public void setTransportCredentials(TransportCredentials credentials) { - checkValid(); - this.credentials = credentials; - } - public String getClientId() { return getProperty(String.class, CLIENT_ID_KEY); } @@ -164,7 +152,6 @@ public abstract class SessionMetadata { .add("failedLoginAttempts", getFailedLoginAttempts()) .add("sessionSource", getSessionSource()) .add("serviceExtensionUris", Joiner.on('.').join(nullToEmpty(getServiceExtensionUris()))) - .add("transportCredentials", getTransportCredentials()) .toString(); } } diff --git a/java/google/registry/flows/StatelessRequestSessionMetadata.java b/java/google/registry/flows/StatelessRequestSessionMetadata.java index c3205719e..d34224970 100644 --- a/java/google/registry/flows/StatelessRequestSessionMetadata.java +++ b/java/google/registry/flows/StatelessRequestSessionMetadata.java @@ -68,11 +68,6 @@ public class StatelessRequestSessionMetadata extends SessionMetadata { throw new UnsupportedOperationException(); } - @Override - public void setTransportCredentials(TransportCredentials credentials) { - throw new UnsupportedOperationException(); - } - @Override protected void setProperty(String key, Object value) { throw new UnsupportedOperationException(); diff --git a/java/google/registry/flows/TlsCredentials.java b/java/google/registry/flows/TlsCredentials.java index 0f5d4e3ba..3bdb81a0e 100644 --- a/java/google/registry/flows/TlsCredentials.java +++ b/java/google/registry/flows/TlsCredentials.java @@ -86,20 +86,16 @@ public class TlsCredentials implements TransportCredentials { } } - @Override - public boolean performsLoginCheck() { - return false; - } - /** Returns {@code true} if frontend passed us the requested server name. */ boolean hasSni() { return !isNullOrEmpty(sni); } @Override - public void validate(Registrar registrar) throws AuthenticationErrorException { + public void validate(Registrar registrar, String password) throws AuthenticationErrorException { validateIp(registrar); validateCertificate(registrar); + validatePassword(registrar, password); } /** @@ -160,6 +156,13 @@ public class TlsCredentials implements TransportCredentials { } } + private void validatePassword(Registrar registrar, String password) + throws BadRegistrarPasswordException { + if (!registrar.testPassword(password)) { + throw new BadRegistrarPasswordException(); + } + } + @Override public String toString() { return toStringHelper(getClass()) diff --git a/java/google/registry/flows/TransportCredentials.java b/java/google/registry/flows/TransportCredentials.java index 6b33b9648..02b68aabb 100644 --- a/java/google/registry/flows/TransportCredentials.java +++ b/java/google/registry/flows/TransportCredentials.java @@ -17,23 +17,21 @@ package google.registry.flows; import google.registry.flows.EppException.AuthenticationErrorException; import google.registry.model.registrar.Registrar; -/** - * A marker interface for objects containing registrar credentials provided via an EPP transport. - */ +/** Interface for objects containing registrar credentials provided via an EPP transport. */ public interface TransportCredentials { - /** - * Indicates whether the transport takes the place of EPP login checks, in which case LoginFlow - * will not check the password. Alternatively, if the password should be checked, it MUST match - * the user's and GAE's isUserAdmin should not be used to bypass this check as internal - * connections over RPC will have this property for all registrars. + * Check that these credentials are valid for the registrar and optionally check the password. + * + * Called by {@link google.registry.flows.session.LoginFlow LoginFlow} to check the transport + * credentials against the stored registrar's credentials. If they do not match, throw an + * {@link AuthenticationErrorException}. */ - boolean performsLoginCheck(); + void validate(Registrar registrar, String password) throws AuthenticationErrorException; - /** - * Called by {@link google.registry.flows.session.LoginFlow LoginFlow} - * to check the transport credentials against the stored registrar's credentials. - * If they do not match, throw an AuthenticationErrorException. - */ - void validate(Registrar r) throws AuthenticationErrorException; + /** Registrar password is incorrect. */ + static class BadRegistrarPasswordException extends AuthenticationErrorException { + public BadRegistrarPasswordException() { + super("Registrar password is incorrect"); + } + } } diff --git a/java/google/registry/flows/session/LoginFlow.java b/java/google/registry/flows/session/LoginFlow.java index 5dd7c78f3..7e960915c 100644 --- a/java/google/registry/flows/session/LoginFlow.java +++ b/java/google/registry/flows/session/LoginFlow.java @@ -29,7 +29,6 @@ import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedObjectServiceException; import google.registry.flows.EppException.UnimplementedOptionException; import google.registry.flows.Flow; -import google.registry.flows.TransportCredentials; import google.registry.model.eppcommon.ProtocolDefinition; import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension; import google.registry.model.eppinput.EppInput.Login; @@ -55,9 +54,9 @@ import java.util.Set; * @error {@link google.registry.flows.TlsCredentials.BadRegistrarIpAddressException} * @error {@link google.registry.flows.TlsCredentials.MissingRegistrarCertificateException} * @error {@link google.registry.flows.TlsCredentials.NoSniException} + * @error {@link google.registry.flows.TransportCredentials.BadRegistrarPasswordException} * @error {@link LoginFlow.AlreadyLoggedInException} * @error {@link LoginFlow.BadRegistrarClientIdException} - * @error {@link LoginFlow.BadRegistrarPasswordException} * @error {@link LoginFlow.TooManyFailedLoginsException} * @error {@link LoginFlow.PasswordChangesNotSupportedException} * @error {@link LoginFlow.RegistrarAccountNotActiveException} @@ -114,24 +113,15 @@ public class LoginFlow extends Flow { throw new BadRegistrarClientIdException(login.getClientId()); } - TransportCredentials credentials = sessionMetadata.getTransportCredentials(); // AuthenticationErrorExceptions will propagate up through here. - if (credentials != null) { // Allow no-credential logins, for load-testing and RDE. - try { - credentials.validate(registrar); - } catch (AuthenticationErrorException e) { - sessionMetadata.incrementFailedLoginAttempts(); - throw e; - } - } - - final boolean requiresLoginCheck = credentials == null || !credentials.performsLoginCheck(); - if (requiresLoginCheck && !registrar.testPassword(login.getPassword())) { + try { + credentials.validate(registrar, login.getPassword()); + } catch (AuthenticationErrorException e) { sessionMetadata.incrementFailedLoginAttempts(); if (sessionMetadata.getFailedLoginAttempts() > MAX_FAILED_LOGIN_ATTEMPTS_PER_CONNECTION) { throw new TooManyFailedLoginsException(); } else { - throw new BadRegistrarPasswordException(); + throw e; } } if (registrar.getState().equals(Registrar.State.PENDING)) { @@ -157,13 +147,6 @@ public class LoginFlow extends Flow { } } - /** Registrar password is incorrect. */ - static class BadRegistrarPasswordException extends AuthenticationErrorException { - public BadRegistrarPasswordException() { - super("Registrar password is incorrect"); - } - } - /** Registrar login failed too many times. */ static class TooManyFailedLoginsException extends AuthenticationErrorClosingConnectionException { public TooManyFailedLoginsException() { diff --git a/java/google/registry/tools/ValidateLoginCredentialsCommand.java b/java/google/registry/tools/ValidateLoginCredentialsCommand.java index a22882edf..5fbca7eb8 100644 --- a/java/google/registry/tools/ValidateLoginCredentialsCommand.java +++ b/java/google/registry/tools/ValidateLoginCredentialsCommand.java @@ -104,12 +104,11 @@ final class ValidateLoginCredentialsCommand implements RemoteApiCommand, GtechCo LoginFlow.class, unmarshal(EppInput.class, inputXmlBytes), Trid.create(null), - new HttpSessionMetadata( - new TlsCredentials( - clientCertificateHash, - Optional.of(clientIpAddress), - "placeholder"), // behave as if we have SNI on, since we're validating a cert - new BasicHttpSession()), + new HttpSessionMetadata(new BasicHttpSession()), + new TlsCredentials( + clientCertificateHash, + Optional.of(clientIpAddress), + "placeholder"), // behave as if we have SNI on, since we're validating a cert inputXmlBytes, null, new SystemClock()).run()), UTF_8)); diff --git a/java/google/registry/ui/server/api/CheckApiAction.java b/java/google/registry/ui/server/api/CheckApiAction.java index b67235da1..2f33a072c 100644 --- a/java/google/registry/ui/server/api/CheckApiAction.java +++ b/java/google/registry/ui/server/api/CheckApiAction.java @@ -38,6 +38,7 @@ import dagger.Provides; import google.registry.config.RegistryEnvironment; import google.registry.flows.EppException; import google.registry.flows.FlowRunner; +import google.registry.flows.PasswordOnlyTransportCredentials; import google.registry.flows.SessionMetadata.SessionSource; import google.registry.flows.StatelessRequestSessionMetadata; import google.registry.flows.domain.DomainCheckFlow; @@ -119,6 +120,7 @@ public class CheckApiAction implements Runnable { unmarshal(EppInput.class, inputXmlBytes), Trid.create(getClass().getSimpleName()), sessionMetadata, + new PasswordOnlyTransportCredentials(), inputXmlBytes, null, clock) diff --git a/javatests/google/registry/flows/EppConsoleActionTest.java b/javatests/google/registry/flows/EppConsoleActionTest.java index 2c666838a..b523f9fda 100644 --- a/javatests/google/registry/flows/EppConsoleActionTest.java +++ b/javatests/google/registry/flows/EppConsoleActionTest.java @@ -51,11 +51,14 @@ public class EppConsoleActionTest extends ShardableTestCase { action.session.setAttribute("SUPERUSER", superuser); action.eppRequestHandler = mock(EppRequestHandler.class); action.run(); - ArgumentCaptor captor = ArgumentCaptor.forClass(SessionMetadata.class); - verify(action.eppRequestHandler).executeEpp(captor.capture(), eq(INPUT_XML_BYTES)); - SessionMetadata sessionMetadata = captor.getValue(); - assertThat(((GaeUserCredentials) sessionMetadata.getTransportCredentials()).gaeUser.getEmail()) + ArgumentCaptor credentialsCaptor = + ArgumentCaptor.forClass(TransportCredentials.class); + ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(SessionMetadata.class); + verify(action.eppRequestHandler).executeEpp( + metadataCaptor.capture(), credentialsCaptor.capture(), eq(INPUT_XML_BYTES)); + assertThat(((GaeUserCredentials) credentialsCaptor.getValue()).gaeUser.getEmail()) .isEqualTo("person@example.com"); + SessionMetadata sessionMetadata = metadataCaptor.getValue(); assertThat(sessionMetadata.getClientId()).isEqualTo("ClientIdentifier"); assertThat(sessionMetadata.isDryRun()).isFalse(); // Should always be false for console. assertThat(sessionMetadata.isSuperuser()).isEqualTo(superuser); diff --git a/javatests/google/registry/flows/EppTestCase.java b/javatests/google/registry/flows/EppTestCase.java index c329bcb18..e5dc72597 100644 --- a/javatests/google/registry/flows/EppTestCase.java +++ b/javatests/google/registry/flows/EppTestCase.java @@ -50,8 +50,8 @@ public class EppTestCase extends ShardableTestCase { private final FakeClock clock = new FakeClock(); private TestSessionMetadata sessionMetadata; - private TransportCredentials credentials; - private boolean superuser; + private TransportCredentials credentials = new PasswordOnlyTransportCredentials(); + private boolean isSuperuser; @Before public void initTestCase() { @@ -70,8 +70,8 @@ public class EppTestCase extends ShardableTestCase { this.credentials = credentials; } - protected void setSuperuser(boolean superuser) { - this.superuser = superuser; + protected void setSuperuser(boolean isSuperuser) { + this.isSuperuser = isSuperuser; } String assertCommandAndResponse(String inputFilename, String outputFilename) throws Exception { @@ -95,9 +95,8 @@ public class EppTestCase extends ShardableTestCase { loadFileWithSubstitutions(getClass(), outputFilename, outputSubstitutions); if (sessionMetadata == null) { sessionMetadata = new TestSessionMetadata(); - sessionMetadata.setTransportCredentials(credentials); } - sessionMetadata.setSuperuser(superuser); + sessionMetadata.setSuperuser(isSuperuser); String actualOutput = executeXmlCommand(input); if (!sessionMetadata.isValid()) { sessionMetadata = null; @@ -119,7 +118,7 @@ public class EppTestCase extends ShardableTestCase { handler.eppController = new EppController(); handler.eppController.clock = clock; handler.eppController.metrics = mock(EppMetrics.class); - handler.executeEpp(sessionMetadata, inputXml.getBytes(UTF_8)); + handler.executeEpp(sessionMetadata, credentials, inputXml.getBytes(UTF_8)); assertThat(response.getStatus()).isEqualTo(SC_OK); assertThat(response.getContentType()).isEqualTo(APPLICATION_EPP_XML_UTF8); String result = response.getPayload(); diff --git a/javatests/google/registry/flows/EppTlsActionTest.java b/javatests/google/registry/flows/EppTlsActionTest.java index 2eb1f10ed..d1f8c7c03 100644 --- a/javatests/google/registry/flows/EppTlsActionTest.java +++ b/javatests/google/registry/flows/EppTlsActionTest.java @@ -17,7 +17,8 @@ package google.registry.flows; import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.mockito.Mockito.eq; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -47,12 +48,12 @@ public class EppTlsActionTest extends ShardableTestCase { action.eppRequestHandler = mock(EppRequestHandler.class); action.run(); ArgumentCaptor captor = ArgumentCaptor.forClass(SessionMetadata.class); - verify(action.eppRequestHandler).executeEpp(captor.capture(), eq(INPUT_XML_BYTES)); + verify(action.eppRequestHandler) + .executeEpp(captor.capture(), same(action.tlsCredentials), eq(INPUT_XML_BYTES)); SessionMetadata sessionMetadata = captor.getValue(); assertThat(sessionMetadata.getClientId()).isEqualTo("ClientIdentifier"); assertThat(sessionMetadata.isDryRun()).isFalse(); // Should always be false for TLS. assertThat(sessionMetadata.isSuperuser()).isEqualTo(superuser); - assertThat(sessionMetadata.getTransportCredentials()).isSameAs(action.tlsCredentials); } @Test diff --git a/javatests/google/registry/flows/EppToolActionTest.java b/javatests/google/registry/flows/EppToolActionTest.java index e81377304..fc8cfba2f 100644 --- a/javatests/google/registry/flows/EppToolActionTest.java +++ b/javatests/google/registry/flows/EppToolActionTest.java @@ -16,7 +16,8 @@ package google.registry.flows; import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.mockito.Mockito.eq; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -38,7 +39,10 @@ public class EppToolActionTest { action.xml = ""; action.run(); ArgumentCaptor captor = ArgumentCaptor.forClass(SessionMetadata.class); - verify(action.eppRequestHandler).executeEpp(captor.capture(), eq(action.xml.getBytes(UTF_8))); + verify(action.eppRequestHandler).executeEpp( + captor.capture(), + isA(PasswordOnlyTransportCredentials.class), + eq(action.xml.getBytes(UTF_8))); SessionMetadata sessionMetadata = captor.getValue(); assertThat(sessionMetadata.getClientId()).isEqualTo("ClientIdentifier"); assertThat(sessionMetadata.isDryRun()).isEqualTo(dryRun); diff --git a/javatests/google/registry/flows/FlowTestCase.java b/javatests/google/registry/flows/FlowTestCase.java index a85dbcc8a..2d54cc8d2 100644 --- a/javatests/google/registry/flows/FlowTestCase.java +++ b/javatests/google/registry/flows/FlowTestCase.java @@ -93,6 +93,7 @@ public abstract class FlowTestCase { protected Class flowClass; protected TestSessionMetadata sessionMetadata; protected FakeClock clock = new FakeClock(DateTime.now(UTC)); + protected TransportCredentials credentials = new PasswordOnlyTransportCredentials(); @Before public void init() throws Exception { @@ -141,6 +142,7 @@ public abstract class FlowTestCase { eppInput, getTrid(), sessionMetadata, + credentials, "".getBytes(), null, clock); diff --git a/javatests/google/registry/flows/session/LoginFlowTestCase.java b/javatests/google/registry/flows/session/LoginFlowTestCase.java index ffc0a32d7..9d529e84d 100644 --- a/javatests/google/registry/flows/session/LoginFlowTestCase.java +++ b/javatests/google/registry/flows/session/LoginFlowTestCase.java @@ -22,9 +22,9 @@ import google.registry.flows.EppException.UnimplementedExtensionException; import google.registry.flows.EppException.UnimplementedObjectServiceException; import google.registry.flows.EppException.UnimplementedProtocolVersionException; import google.registry.flows.FlowTestCase; +import google.registry.flows.TransportCredentials.BadRegistrarPasswordException; import google.registry.flows.session.LoginFlow.AlreadyLoggedInException; import google.registry.flows.session.LoginFlow.BadRegistrarClientIdException; -import google.registry.flows.session.LoginFlow.BadRegistrarPasswordException; import google.registry.flows.session.LoginFlow.PasswordChangesNotSupportedException; import google.registry.flows.session.LoginFlow.RegistrarAccountNotActiveException; import google.registry.flows.session.LoginFlow.TooManyFailedLoginsException; diff --git a/javatests/google/registry/flows/session/LoginFlowViaConsoleTest.java b/javatests/google/registry/flows/session/LoginFlowViaConsoleTest.java index 3f47df188..b5497013a 100644 --- a/javatests/google/registry/flows/session/LoginFlowViaConsoleTest.java +++ b/javatests/google/registry/flows/session/LoginFlowViaConsoleTest.java @@ -15,9 +15,9 @@ package google.registry.flows.session; +import static com.google.appengine.api.users.UserServiceFactory.getUserService; import static google.registry.testing.DatastoreHelper.persistResource; -import com.google.appengine.api.users.UserServiceFactory; import com.google.apphosting.api.ApiProxy; import com.google.apphosting.api.ApiProxy.Environment; import com.google.common.collect.ImmutableSet; @@ -150,15 +150,13 @@ public class LoginFlowViaConsoleTest extends LoginFlowTestCase { return envAttr; } }); - sessionMetadata.setTransportCredentials(new GaeUserCredentials( - UserServiceFactory.getUserService().getCurrentUser())); + credentials = new GaeUserCredentials(getUserService().getCurrentUser()); return oldEnv; } void noLogin() { oldEnv = ApiProxy.getCurrentEnvironment(); - sessionMetadata.setTransportCredentials(new GaeUserCredentials( - UserServiceFactory.getUserService().getCurrentUser())); + credentials = new GaeUserCredentials(getUserService().getCurrentUser()); } void persistLinkedAccount(String email, String gaeUserId) { diff --git a/javatests/google/registry/flows/session/LoginFlowViaTlsTest.java b/javatests/google/registry/flows/session/LoginFlowViaTlsTest.java index ec421d906..75d4c401d 100644 --- a/javatests/google/registry/flows/session/LoginFlowViaTlsTest.java +++ b/javatests/google/registry/flows/session/LoginFlowViaTlsTest.java @@ -52,7 +52,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { @Test public void testSuccess_withGoodCredentials() throws Exception { persistResource(getRegistrarBuilder().build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(GOOD_CERT, GOOD_IP, "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, GOOD_IP, "goo.example"); doSuccessfulTest("login_valid.xml"); } @@ -63,8 +63,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { .setIpAddressWhitelist(ImmutableList.of( CidrAddressBlock.create("2001:db8:0:0:0:0:1:1/32"))) .build()); - sessionMetadata.setTransportCredentials( - new TlsCredentials(GOOD_CERT, GOOD_IPV6, "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, GOOD_IPV6, "goo.example"); doSuccessfulTest("login_valid.xml"); } @@ -75,8 +74,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { .setIpAddressWhitelist(ImmutableList.of( CidrAddressBlock.create("2001:db8:0:0:0:0:1:1/32"))) .build()); - sessionMetadata.setTransportCredentials( - new TlsCredentials(GOOD_CERT, GOOD_IPV6, "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, GOOD_IPV6, "goo.example"); doSuccessfulTest("login_valid.xml"); } @@ -87,28 +85,28 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { .setIpAddressWhitelist(ImmutableList.of( CidrAddressBlock.create("192.168.1.255/24"))) .build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(GOOD_CERT, GOOD_IP, "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, GOOD_IP, "goo.example"); doSuccessfulTest("login_valid.xml"); } @Test public void testFailure_incorrectClientCertificateHash() throws Exception { persistResource(getRegistrarBuilder().build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(BAD_CERT, GOOD_IP, "goo.example")); + credentials = new TlsCredentials(BAD_CERT, GOOD_IP, "goo.example"); doFailingTest("login_valid.xml", BadRegistrarCertificateException.class); } @Test public void testFailure_missingClientCertificateHash() throws Exception { persistResource(getRegistrarBuilder().build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(null, GOOD_IP, "goo.example")); + credentials = new TlsCredentials(null, GOOD_IP, "goo.example"); doFailingTest("login_valid.xml", MissingRegistrarCertificateException.class); } @Test public void testFailure_noSniAndCertRequired() throws Exception { persistResource(getRegistrarBuilder().build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(null, GOOD_IP, null)); + credentials = new TlsCredentials(null, GOOD_IP, null); doFailingTest("login_valid.xml", NoSniException.class); } @@ -120,8 +118,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32), CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128))) .build()); - sessionMetadata.setTransportCredentials( - new TlsCredentials(GOOD_CERT, Optional.absent(), "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, Optional.absent(), "goo.example"); doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class); } @@ -133,7 +130,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32), CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128))) .build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(GOOD_CERT, BAD_IP, "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, BAD_IP, "goo.example"); doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class); } @@ -145,7 +142,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase { CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32), CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128))) .build()); - sessionMetadata.setTransportCredentials(new TlsCredentials(GOOD_CERT, BAD_IPV6, "goo.example")); + credentials = new TlsCredentials(GOOD_CERT, BAD_IPV6, "goo.example"); doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class); } } diff --git a/javatests/google/registry/model/EppResourceUtilsTest.java b/javatests/google/registry/model/EppResourceUtilsTest.java index 0db2604c1..0e3aa24d3 100644 --- a/javatests/google/registry/model/EppResourceUtilsTest.java +++ b/javatests/google/registry/model/EppResourceUtilsTest.java @@ -31,6 +31,7 @@ import static org.joda.time.Duration.standardDays; import com.googlecode.objectify.Key; import google.registry.flows.FlowRunner; +import google.registry.flows.PasswordOnlyTransportCredentials; import google.registry.flows.SessionMetadata; import google.registry.model.domain.DomainResource; import google.registry.model.eppcommon.Trid; @@ -84,6 +85,7 @@ public class EppResourceUtilsTest { eppLoader.getEpp(), Trid.create(null, "server-trid"), sessionMetadata, + new PasswordOnlyTransportCredentials(), "".getBytes(), null, clock)