mirror of
https://github.com/google/nomulus
synced 2026-07-26 18:12:38 +00:00
Update registrar-update auth block for allowed TLDs + rlock (#3175)
Verified in support docs 2.19 and 2.33 that agents should have the ability to edit allowed TLDs but should not have the ability to edit whether registry lock is allowed. This reflects that. b/534931470
This commit is contained in:
@@ -127,6 +127,14 @@ public abstract class ConsoleApiAction implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
protected static void checkGlobalPermission(User user, ConsolePermission permission) {
|
||||
if (!user.getUserRoles().hasGlobalPermission(permission)) {
|
||||
throw new ConsolePermissionForbiddenException(
|
||||
String.format(
|
||||
"User %s does not have global permission %s", user.getEmailAddress(), permission));
|
||||
}
|
||||
}
|
||||
|
||||
protected void postHandler(User user) {
|
||||
throw new UnsupportedOperationException("Console API POST handler not implemented");
|
||||
}
|
||||
|
||||
+31
-26
@@ -15,6 +15,7 @@
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
@@ -38,7 +39,6 @@ import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Action(
|
||||
service = Service.CONSOLE,
|
||||
@@ -69,22 +69,23 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction {
|
||||
|
||||
tm().transact(
|
||||
() -> {
|
||||
Optional<Registrar> existingRegistrar =
|
||||
Registrar.loadByRegistrarId(registrarParam.getRegistrarId());
|
||||
checkArgument(
|
||||
!existingRegistrar.isEmpty(),
|
||||
"Registrar with registrarId %s doesn't exists",
|
||||
registrarParam.getRegistrarId());
|
||||
Registrar existingRegistrar =
|
||||
Registrar.loadByRegistrarId(registrarParam.getRegistrarId())
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format(
|
||||
"Registrar %s does not exist",
|
||||
registrarParam.getRegistrarId())));
|
||||
|
||||
// Only allow modifying allowed TLDs if we're in a non-PRODUCTION environment, if the
|
||||
// registrar is not REAL, or the registrar has a RDAP abuse contact set.
|
||||
if (!registrarParam.getAllowedTlds().isEmpty()) {
|
||||
boolean isRealRegistrar =
|
||||
Registrar.Type.REAL.equals(existingRegistrar.get().getType());
|
||||
boolean isRealRegistrar = Registrar.Type.REAL.equals(existingRegistrar.getType());
|
||||
if (RegistryEnvironment.PRODUCTION.equals(RegistryEnvironment.get())
|
||||
&& isRealRegistrar) {
|
||||
checkArgumentPresent(
|
||||
existingRegistrar.get().getRdapAbuseContact(),
|
||||
existingRegistrar.getRdapAbuseContact(),
|
||||
"Cannot modify allowed TLDs if there is no RDAP abuse contact set. Please"
|
||||
+ " use the \"nomulus registrar_contact\" command on this registrar to"
|
||||
+ " set a RDAP abuse contact.");
|
||||
@@ -103,20 +104,27 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction {
|
||||
|
||||
var updatedRegistrarBuilder =
|
||||
existingRegistrar
|
||||
.get()
|
||||
.asBuilder()
|
||||
.setLastPocVerificationDate(newLastPocVerificationDate);
|
||||
|
||||
if (user.getUserRoles()
|
||||
.hasGlobalPermission(ConsolePermission.EDIT_REGISTRAR_DETAILS)) {
|
||||
updatedRegistrarBuilder =
|
||||
updatedRegistrarBuilder
|
||||
.setAllowedTlds(
|
||||
registrarParam.getAllowedTlds().stream()
|
||||
.map(DomainNameUtils::canonicalizeHostname)
|
||||
.collect(Collectors.toSet()))
|
||||
.setRegistryLockAllowed(registrarParam.isRegistryLockAllowed())
|
||||
.setLastPocVerificationDate(newLastPocVerificationDate);
|
||||
if (!registrarParam.getAllowedTlds().equals(existingRegistrar.getAllowedTlds())) {
|
||||
// The global permission EDIT_REGISTRAR_DETAILS signifies a support agent who *does*
|
||||
// have the ability to edit allowed TLDs. See support docs 2.19: "Enabling TLD
|
||||
// Access in Production"
|
||||
checkGlobalPermission(user, ConsolePermission.EDIT_REGISTRAR_DETAILS);
|
||||
updatedRegistrarBuilder.setAllowedTlds(
|
||||
registrarParam.getAllowedTlds().stream()
|
||||
.map(DomainNameUtils::canonicalizeHostname)
|
||||
.collect(toImmutableSet()));
|
||||
}
|
||||
|
||||
if (registrarParam.isRegistryLockAllowed()
|
||||
!= existingRegistrar.isRegistryLockAllowed()) {
|
||||
// Enabling registry lock requires a support lead or FTE, which maps to
|
||||
// MANAGE_REGISTRARS. See support docs 2.33: "Registry Lock Onboarding Process"
|
||||
checkGlobalPermission(user, ConsolePermission.MANAGE_REGISTRARS);
|
||||
updatedRegistrarBuilder.setRegistryLockAllowed(
|
||||
registrarParam.isRegistryLockAllowed());
|
||||
}
|
||||
|
||||
var updatedRegistrar = updatedRegistrarBuilder.build();
|
||||
@@ -126,14 +134,11 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction {
|
||||
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
|
||||
.setDescription(updatedRegistrar.getRegistrarId()));
|
||||
|
||||
logConsoleChangesIfNecessary(updatedRegistrar, existingRegistrar.get());
|
||||
logConsoleChangesIfNecessary(updatedRegistrar, existingRegistrar);
|
||||
|
||||
sendExternalUpdatesIfNecessary(
|
||||
EmailInfo.create(
|
||||
existingRegistrar.get(),
|
||||
updatedRegistrar,
|
||||
ImmutableSet.of(),
|
||||
ImmutableSet.of()));
|
||||
existingRegistrar, updatedRegistrar, ImmutableSet.of(), ImmutableSet.of()));
|
||||
});
|
||||
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
|
||||
+114
-12
@@ -20,6 +20,7 @@ import static google.registry.testing.DatabaseHelper.createTlds;
|
||||
import static google.registry.testing.DatabaseHelper.loadSingleton;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -37,6 +38,7 @@ import google.registry.request.Action;
|
||||
import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.SystemPropertyExtension;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
@@ -55,8 +57,6 @@ class ConsoleUpdateRegistrarActionTest extends ConsoleActionBaseTestCase {
|
||||
|
||||
private Registrar registrar;
|
||||
|
||||
private User user;
|
||||
|
||||
private static String registrarPostData =
|
||||
"{\"registrarId\":\"%s\",\"allowedTlds\":[%s],\"registryLockAllowed\":%s,"
|
||||
+ " \"lastPocVerificationDate\":%s }";
|
||||
@@ -76,12 +76,6 @@ class ConsoleUpdateRegistrarActionTest extends ConsoleActionBaseTestCase {
|
||||
.setAllowedTlds(ImmutableSet.of())
|
||||
.setRegistryLockAllowed(false)
|
||||
.build());
|
||||
user =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("user@registrarId.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -209,15 +203,123 @@ class ConsoleUpdateRegistrarActionTest extends ConsoleActionBaseTestCase {
|
||||
.build());
|
||||
}
|
||||
|
||||
private ConsoleApiParams createParams() {
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
return ConsoleApiParamsUtils.createFake(authResult);
|
||||
@Test
|
||||
void testFailure_registrarNotFound() throws IOException {
|
||||
var action =
|
||||
createAction(
|
||||
String.format(
|
||||
registrarPostData,
|
||||
"nonexistent",
|
||||
"app, dev",
|
||||
false,
|
||||
"\"2023-12-12T00:00:00.000Z\""));
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
private ConsoleUpdateRegistrarAction createAction(String requestData) throws IOException {
|
||||
@Test
|
||||
void testSuccess_supportAgentCanUpdateAllowedTlds() throws IOException {
|
||||
User supportAgentUser =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("agent@registrarId.com")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_AGENT).build())
|
||||
.build());
|
||||
var action =
|
||||
createAction(
|
||||
supportAgentUser,
|
||||
String.format(
|
||||
registrarPostData,
|
||||
"TheRegistrar",
|
||||
"app, dev",
|
||||
false,
|
||||
"\"2023-12-12T00:00:00.000Z\""));
|
||||
action.run();
|
||||
Registrar newRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
|
||||
assertThat(newRegistrar.getAllowedTlds()).containsExactly("app", "dev");
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_supportAgentCannotUpdateRegistryLock() throws IOException {
|
||||
User supportAgentUser =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("agent@registrarId.com")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_AGENT).build())
|
||||
.build());
|
||||
var action =
|
||||
createAction(
|
||||
supportAgentUser,
|
||||
String.format(
|
||||
registrarPostData,
|
||||
"TheRegistrar",
|
||||
"app, dev",
|
||||
true,
|
||||
"\"2023-12-12T00:00:00.000Z\""));
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
Registrar unupdatedRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
|
||||
assertThat(unupdatedRegistrar.isRegistryLockAllowed()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_userWithoutEditRegistrarDetailsCannotUpdateAllowedTlds() throws IOException {
|
||||
User normalUser =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("normal@registrarId.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.NONE).build())
|
||||
.build());
|
||||
var action =
|
||||
createAction(
|
||||
normalUser,
|
||||
String.format(
|
||||
registrarPostData,
|
||||
"TheRegistrar",
|
||||
"app, dev",
|
||||
false,
|
||||
"\"2023-12-12T00:00:00.000Z\""));
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
Registrar unupdatedRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
|
||||
assertThat(unupdatedRegistrar.getAllowedTlds()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_supportLeadCanUpdateRegistryLock() throws IOException {
|
||||
User supportLeadUser =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("lead@registrarId.com")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setGlobalRole(GlobalRole.SUPPORT_LEAD).build())
|
||||
.build());
|
||||
var action =
|
||||
createAction(
|
||||
supportLeadUser,
|
||||
String.format(
|
||||
registrarPostData, "TheRegistrar", "", true, "\"2023-12-12T00:00:00.000Z\""));
|
||||
action.run();
|
||||
Registrar newRegistrar = Registrar.loadByRegistrarId("TheRegistrar").get();
|
||||
assertThat(newRegistrar.isRegistryLockAllowed()).isTrue();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
|
||||
private ConsoleUpdateRegistrarAction createAction(User actionUser, String requestData)
|
||||
throws IOException {
|
||||
AuthResult authResult = AuthResult.createUser(actionUser);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
response = (FakeResponse) consoleApiParams.response();
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.POST.toString());
|
||||
Optional<Registrar> maybeRegistrarUpdateData =
|
||||
ConsoleModule.provideRegistrar(GSON, RequestModule.provideJsonBody(requestData, GSON));
|
||||
return new ConsoleUpdateRegistrarAction(consoleApiParams, maybeRegistrarUpdateData);
|
||||
}
|
||||
|
||||
private ConsoleUpdateRegistrarAction createAction(String requestData) throws IOException {
|
||||
return createAction(fteUser, requestData);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user