1
0
mirror of https://github.com/google/nomulus synced 2026-04-26 11:10:48 +00:00

Add console backend for EPP password change (#2396)

This commit is contained in:
Pavlo Tkach
2024-04-20 06:44:26 -04:00
committed by GitHub
parent b5629ff16f
commit 4de2bd5901
7 changed files with 352 additions and 2 deletions

View File

@@ -110,6 +110,7 @@ import google.registry.tools.server.ToolsServerModule;
import google.registry.tools.server.VerifyOteAction;
import google.registry.ui.server.console.ConsoleDomainGetAction;
import google.registry.ui.server.console.ConsoleDomainListAction;
import google.registry.ui.server.console.ConsoleEppPasswordAction;
import google.registry.ui.server.console.ConsoleUserDataAction;
import google.registry.ui.server.console.RegistrarsAction;
import google.registry.ui.server.console.settings.ContactAction;
@@ -178,6 +179,8 @@ interface RequestComponent {
ConsoleDomainListAction consoleDomainListAction();
ConsoleEppPasswordAction consoleEppPasswordAction();
ConsoleOteSetupAction consoleOteSetupAction();
ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();

View File

@@ -27,6 +27,7 @@ import google.registry.request.RequestModule;
import google.registry.request.RequestScope;
import google.registry.ui.server.console.ConsoleDomainGetAction;
import google.registry.ui.server.console.ConsoleDomainListAction;
import google.registry.ui.server.console.ConsoleEppPasswordAction;
import google.registry.ui.server.console.ConsoleUserDataAction;
import google.registry.ui.server.console.RegistrarsAction;
import google.registry.ui.server.console.settings.ContactAction;
@@ -58,6 +59,8 @@ public interface FrontendRequestComponent {
ConsoleDomainListAction consoleDomainListAction();
ConsoleEppPasswordAction consoleEppPasswordAction();
ConsoleOteSetupAction consoleOteSetupAction();
ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();
ConsoleUiAction consoleUiAction();

View File

@@ -49,6 +49,7 @@ public abstract class ConsoleApiAction implements Runnable {
}
}
protected void postHandler(User user) {
throw new UnsupportedOperationException("Console API POST handler not implemented");
}
@@ -57,6 +58,11 @@ public abstract class ConsoleApiAction implements Runnable {
throw new UnsupportedOperationException("Console API GET handler not implemented");
}
protected void setFailedResponse(String message, int code) {
consoleApiParams.response().setStatus(code);
consoleApiParams.response().setPayload(message);
}
private boolean verifyXSRF() {
Optional<Cookie> maybeCookie =
Arrays.stream(consoleApiParams.request().getCookies())

View File

@@ -0,0 +1,126 @@
// Copyright 2024 The Nomulus 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.ui.server.console;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import com.google.api.client.http.HttpStatusCodes;
import com.google.common.base.Throwables;
import com.google.common.flogger.FluentLogger;
import google.registry.flows.EppException.AuthenticationErrorException;
import google.registry.flows.PasswordOnlyTransportCredentials;
import google.registry.groups.GmailClient;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.request.Action;
import google.registry.request.HttpException.BadRequestException;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.ui.server.registrar.ConsoleApiParams;
import google.registry.util.EmailMessage;
import java.util.Optional;
import javax.inject.Inject;
import javax.mail.internet.InternetAddress;
@Action(
service = Action.Service.DEFAULT,
path = ConsoleEppPasswordAction.PATH,
method = {POST},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ConsoleEppPasswordAction extends ConsoleApiAction {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
protected static final String EMAIL_SUBJ = "EPP password update confirmation";
protected static final String EMAIL_BODY =
"Dear %s,\n" + "This is to confirm that your account password has been changed.";
public static final String PATH = "/console-api/eppPassword";
private final PasswordOnlyTransportCredentials credentials =
new PasswordOnlyTransportCredentials();
private final AuthenticatedRegistrarAccessor registrarAccessor;
private final GmailClient gmailClient;
@Inject
public ConsoleEppPasswordAction(
ConsoleApiParams consoleApiParams,
AuthenticatedRegistrarAccessor registrarAccessor,
GmailClient gmailClient) {
super(consoleApiParams);
this.registrarAccessor = registrarAccessor;
this.gmailClient = gmailClient;
}
@Override
protected void postHandler(User user) {
String registrarId;
String oldPassword;
String newPassword;
String newPasswordRepeat;
try {
registrarId = extractRequiredParameter(consoleApiParams.request(), "registrarId");
oldPassword = extractRequiredParameter(consoleApiParams.request(), "oldPassword");
newPassword = extractRequiredParameter(consoleApiParams.request(), "newPassword");
newPasswordRepeat = extractRequiredParameter(consoleApiParams.request(), "newPasswordRepeat");
} catch (BadRequestException e) {
setFailedResponse(e.getMessage(), HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
return;
}
if (!newPassword.equals(newPasswordRepeat)) {
setFailedResponse("New password fields don't match", HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
return;
}
Registrar registrar;
try {
registrar = registrarAccessor.getRegistrar(registrarId);
} catch (RegistrarAccessDeniedException e) {
setFailedResponse(e.getMessage(), HttpStatusCodes.STATUS_CODE_NOT_FOUND);
return;
}
try {
credentials.validate(registrar, oldPassword);
} catch (AuthenticationErrorException e) {
setFailedResponse(e.getMessage(), HttpStatusCodes.STATUS_CODE_FORBIDDEN);
return;
}
try {
tm().transact(
() -> {
tm().put(registrar.asBuilder().setPassword(newPassword).build());
this.gmailClient.sendEmail(
EmailMessage.create(
EMAIL_SUBJ,
String.format(EMAIL_BODY, registrar.getRegistrarName()),
new InternetAddress(registrar.getEmailAddress(), true)));
});
} catch (Throwable e) {
logger.atWarning().withCause(e).log("Failed to update password.");
String message =
Optional.ofNullable(Throwables.getRootCause(e).getMessage()).orElse("Unspecified error");
setFailedResponse(message, HttpStatusCodes.STATUS_CODE_SERVER_ERROR);
}
consoleApiParams.response().setStatus(HttpStatusCodes.STATUS_CODE_OK);
}
}