Add a reg-lock verification action to the new console (#2467)

The front end will have a (hidden) page that passes the verification
code to this API endpoint and displays the result.
This commit is contained in:
gbrodman
2024-07-08 21:25:22 +00:00
committed by GitHub
parent b602aac09a
commit b8a6ac72dd
9 changed files with 337 additions and 43 deletions
@@ -114,6 +114,7 @@ import google.registry.ui.server.console.ConsoleDomainListAction;
import google.registry.ui.server.console.ConsoleDumDownloadAction;
import google.registry.ui.server.console.ConsoleEppPasswordAction;
import google.registry.ui.server.console.ConsoleRegistryLockAction;
import google.registry.ui.server.console.ConsoleRegistryLockVerifyAction;
import google.registry.ui.server.console.ConsoleUpdateRegistrarAction;
import google.registry.ui.server.console.ConsoleUserDataAction;
import google.registry.ui.server.console.RegistrarsAction;
@@ -191,6 +192,8 @@ interface RequestComponent {
ConsoleRegistryLockAction consoleRegistryLockAction();
ConsoleRegistryLockVerifyAction consoleRegistryLockVerifyAction();
ConsoleUiAction consoleUiAction();
ConsoleUpdateRegistrarAction consoleUpdateRegistrarAction();
@@ -30,6 +30,7 @@ import google.registry.ui.server.console.ConsoleDomainListAction;
import google.registry.ui.server.console.ConsoleDumDownloadAction;
import google.registry.ui.server.console.ConsoleEppPasswordAction;
import google.registry.ui.server.console.ConsoleRegistryLockAction;
import google.registry.ui.server.console.ConsoleRegistryLockVerifyAction;
import google.registry.ui.server.console.ConsoleUpdateRegistrarAction;
import google.registry.ui.server.console.ConsoleUserDataAction;
import google.registry.ui.server.console.RegistrarsAction;
@@ -69,6 +70,8 @@ public interface FrontendRequestComponent {
ConsoleRegistryLockAction consoleRegistryLockAction();
ConsoleRegistryLockVerifyAction consoleRegistryLockVerifyAction();
ConsoleUiAction consoleUiAction();
ConsoleUpdateRegistrarAction consoleUpdateRegistrarAction();
@@ -47,10 +47,8 @@ import google.registry.util.EmailMessage;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.util.Optional;
import javax.inject.Inject;
import org.apache.http.client.utils.URIBuilder;
import org.joda.time.Duration;
/**
@@ -153,14 +151,9 @@ public class ConsoleRegistryLockAction extends ConsoleApiAction {
private void sendVerificationEmail(RegistryLock lock, String userEmail, boolean isLock) {
try {
String url =
new URIBuilder()
.setScheme("https")
.setHost(consoleApiParams.request().getServerName())
// TODO: replace this with the PATH in ConsoleRegistryLockVerifyAction once it exists
.setPath("/console-api/registry-lock-verify")
.setParameter("lockVerificationCode", lock.getVerificationCode())
.build()
.toString();
String.format(
"https://%s/console/#/registry-lock-verify?lockVerificationCode=%s",
consoleApiParams.request().getServerName(), lock.getVerificationCode());
String body = String.format(VERIFICATION_EMAIL_TEMPLATE, lock.getDomainName(), url);
ImmutableList<InternetAddress> recipients =
ImmutableList.of(new InternetAddress(userEmail, true));
@@ -171,7 +164,7 @@ public class ConsoleRegistryLockAction extends ConsoleApiAction {
.setSubject(String.format("Registry %s verification", action))
.setRecipients(recipients)
.build());
} catch (AddressException | URISyntaxException e) {
} catch (AddressException e) {
throw new RuntimeException(e); // caught above -- this is so we can run in a transaction
}
}
@@ -0,0 +1,80 @@
// 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.request.Action.Method.GET;
import com.google.common.base.Ascii;
import com.google.gson.Gson;
import com.google.gson.annotations.Expose;
import google.registry.model.console.User;
import google.registry.model.domain.RegistryLock;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.auth.Auth;
import google.registry.tools.DomainLockUtils;
import google.registry.ui.server.registrar.ConsoleApiParams;
import jakarta.servlet.http.HttpServletResponse;
import javax.inject.Inject;
/** Handler for verifying registry lock requests, a form of 2FA. */
@Action(
service = Action.Service.DEFAULT,
path = ConsoleRegistryLockVerifyAction.PATH,
method = {GET},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ConsoleRegistryLockVerifyAction extends ConsoleApiAction {
static final String PATH = "/console-api/registry-lock-verify";
private final DomainLockUtils domainLockUtils;
private final Gson gson;
private final String lockVerificationCode;
@Inject
public ConsoleRegistryLockVerifyAction(
ConsoleApiParams consoleApiParams,
DomainLockUtils domainLockUtils,
Gson gson,
@Parameter("lockVerificationCode") String lockVerificationCode) {
super(consoleApiParams);
this.domainLockUtils = domainLockUtils;
this.gson = gson;
this.lockVerificationCode = lockVerificationCode;
}
@Override
protected void getHandler(User user) {
RegistryLock lock =
domainLockUtils.verifyVerificationCode(lockVerificationCode, user.getUserRoles().isAdmin());
RegistryLockAction action =
lock.getLockCompletionTime().isPresent()
? RegistryLockAction.UNLOCKED
: RegistryLockAction.LOCKED;
RegistryLockVerificationResponse lockResponse =
new RegistryLockVerificationResponse(
Ascii.toLowerCase(action.toString()), lock.getDomainName(), lock.getRegistrarId());
consoleApiParams.response().setPayload(gson.toJson(lockResponse));
consoleApiParams.response().setStatus(HttpServletResponse.SC_OK);
}
private enum RegistryLockAction {
LOCKED,
UNLOCKED
}
private record RegistryLockVerificationResponse(
@Expose String action, @Expose String domainName, @Expose String registrarId) {}
}