diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java index 6f347fe63..98175f651 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java @@ -105,7 +105,8 @@ public abstract class ConsoleApiAction implements Runnable { } } - protected void checkPermission(User user, String registrarId, ConsolePermission permission) { + protected static void checkPermission( + User user, String registrarId, ConsolePermission permission) { if (!user.getUserRoles().hasPermission(registrarId, permission)) { throw new ConsolePermissionForbiddenException( String.format( diff --git a/core/src/main/java/google/registry/ui/server/console/PasswordResetRequestAction.java b/core/src/main/java/google/registry/ui/server/console/PasswordResetRequestAction.java index 899b2aa69..76c690d51 100644 --- a/core/src/main/java/google/registry/ui/server/console/PasswordResetRequestAction.java +++ b/core/src/main/java/google/registry/ui/server/console/PasswordResetRequestAction.java @@ -131,13 +131,12 @@ public class PasswordResetRequestAction extends ConsoleApiAction { new IllegalArgumentException( "Unknown user with lock email " + destinationEmail)); - // Prevent IDOR: Ensure the resolved user actually belongs to the registrar the requester - // has permissions for, or is a global admin. - if (!targetUser.getUserRoles().isAdmin() - && !targetUser.getUserRoles().getRegistrarRoles().containsKey(registrarId)) { - throw new IllegalArgumentException( - "User with lock email " + destinationEmail + " is not associated with " + registrarId); - } + // Prevent IDOR: Ensure the resolved user has the right permission + checkArgument( + targetUser.getUserRoles().hasPermission(registrarId, ConsolePermission.REGISTRY_LOCK), + "User %s does not have permission REGISTRY_LOCK on registrar %s", + targetUser.getEmailAddress(), + registrarId); return targetUser; } diff --git a/core/src/main/java/google/registry/ui/server/console/PasswordResetVerifyAction.java b/core/src/main/java/google/registry/ui/server/console/PasswordResetVerifyAction.java index 52c2cc889..ed39aee8c 100644 --- a/core/src/main/java/google/registry/ui/server/console/PasswordResetVerifyAction.java +++ b/core/src/main/java/google/registry/ui/server/console/PasswordResetVerifyAction.java @@ -121,7 +121,15 @@ public class PasswordResetVerifyAction extends ConsoleApiAction { ConsolePermission requiredVerifyPermission = switch (request.getType()) { case EPP -> ConsolePermission.MANAGE_USERS; - case REGISTRY_LOCK -> ConsolePermission.REGISTRY_LOCK; + case REGISTRY_LOCK -> { + checkArgument( + user.getRegistryLockEmailAddress() + .map(address -> address.equals(request.getDestinationEmail())) + .orElse(false), + "User %s has the wrong registry lock email address", + user.getEmailAddress()); + yield ConsolePermission.REGISTRY_LOCK; + } }; checkPermission(user, request.getRegistrarId(), requiredVerifyPermission); if (plusHours(request.getRequestTime(), 1).isBefore(tm().getTxTime())) { diff --git a/core/src/test/java/google/registry/ui/server/console/PasswordResetRequestActionTest.java b/core/src/test/java/google/registry/ui/server/console/PasswordResetRequestActionTest.java index a72f0ad6d..7e9b34e50 100644 --- a/core/src/test/java/google/registry/ui/server/console/PasswordResetRequestActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/PasswordResetRequestActionTest.java @@ -158,6 +158,31 @@ public class PasswordResetRequestActionTest extends ConsoleActionBaseTestCase { .isEqualTo("Unknown user with lock email nonexistent@email.com"); } + @Test + void testFailure_registryLock_userNoLockPermission() throws Exception { + DatabaseHelper.persistResource( + new User.Builder() + .setEmailAddress("email@registry.tld") + .setUserRoles( + new UserRoles.Builder() + .setRegistrarRoles( + ImmutableMap.of("TheRegistrar", RegistrarRole.ACCOUNT_MANAGER)) + .build()) + .setRegistryLockEmailAddress("registrylock@theregistrar.com") + .build()); + PasswordResetRequestAction action = + createAction( + PasswordResetRequest.Type.REGISTRY_LOCK, + "TheRegistrar", + "registrylock@theregistrar.com"); + action.run(); + assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); + assertThat(response.getPayload()) + .isEqualTo( + "User email@registry.tld does not have permission REGISTRY_LOCK on registrar" + + " TheRegistrar"); + } + @Test @Disabled("Enable when testing is done in sandbox and isAdmin check is removed") void testFailure_epp_noPermission() throws Exception { diff --git a/core/src/test/java/google/registry/ui/server/console/PasswordResetVerifyActionTest.java b/core/src/test/java/google/registry/ui/server/console/PasswordResetVerifyActionTest.java index 954bc5536..d46b85769 100644 --- a/core/src/test/java/google/registry/ui/server/console/PasswordResetVerifyActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/PasswordResetVerifyActionTest.java @@ -157,6 +157,48 @@ public class PasswordResetVerifyActionTest extends ConsoleActionBaseTestCase { assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); } + @Test + void testFailure_post_lock_differentRegistryLockEmail() throws Exception { + User user = + persistResource( + new User.Builder() + .setEmailAddress("anotheruser@example.tld") + .setUserRoles( + new UserRoles.Builder() + .setRegistrarRoles( + ImmutableMap.of( + "TheRegistrar", RegistrarRole.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK)) + .build()) + .setRegistryLockEmailAddress("anotherregistrylock@theregistrar.com") + .build()); + verificationCode = saveRequest(PasswordResetRequest.Type.REGISTRY_LOCK).getVerificationCode(); + createAction(user, "POST", verificationCode, "newPassword").run(); + assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); + assertThat(response.getPayload()) + .isEqualTo("User anotheruser@example.tld has the wrong registry lock email address"); + } + + @Test + void testFailure_get_lock_differentRegistryLockEmail() throws Exception { + User user = + persistResource( + new User.Builder() + .setEmailAddress("anotheruser@example.tld") + .setUserRoles( + new UserRoles.Builder() + .setRegistrarRoles( + ImmutableMap.of( + "TheRegistrar", RegistrarRole.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK)) + .build()) + .setRegistryLockEmailAddress("anotherregistrylock@theregistrar.com") + .build()); + verificationCode = saveRequest(PasswordResetRequest.Type.REGISTRY_LOCK).getVerificationCode(); + createAction(user, "GET", verificationCode, null).run(); + assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); + assertThat(response.getPayload()) + .isEqualTo("User anotheruser@example.tld has the wrong registry lock email address"); + } + private User createTechUser() { return new User.Builder() .setEmailAddress("tech@example.tld")