mirror of
https://github.com/google/nomulus
synced 2026-07-19 06:22:33 +00:00
Only delete Workspace accounts if we created them (#3161)
Just in case, we should check to make sure that we created the account-with-no-registrars before we delete it.
This commit is contained in:
@@ -33,6 +33,7 @@ import com.google.api.services.directory.model.UserName;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
@@ -58,6 +59,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -69,6 +71,7 @@ import javax.annotation.Nullable;
|
||||
public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
static final String PATH = "/console-api/users";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final int PASSWORD_LENGTH = 16;
|
||||
|
||||
private final String registrarId;
|
||||
@@ -184,11 +187,20 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
|
||||
// User has no registrars assigned
|
||||
if (updatedUser.getUserRoles().getRegistrarRoles().isEmpty()) {
|
||||
try {
|
||||
directory.users().delete(email).execute();
|
||||
} catch (IOException e) {
|
||||
setFailedResponse("Failed to delete the user workspace account", SC_INTERNAL_SERVER_ERROR);
|
||||
throw e;
|
||||
// Only delete the Workspace account if runCreate() provably minted it. Addresses that
|
||||
// reached this row via CLI create_user, OteAccountBuilder, or other means must survive
|
||||
if (isConsoleMintedAddress(email)) {
|
||||
try {
|
||||
directory.users().delete(email).execute();
|
||||
} catch (IOException e) {
|
||||
setFailedResponse(
|
||||
"Failed to delete the user workspace account", SC_INTERNAL_SERVER_ERROR);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
logger.atInfo().log(
|
||||
"Skipping Workspace deletion for %s because the console did not mint the account",
|
||||
email);
|
||||
}
|
||||
|
||||
VKey<User> key = VKey.create(User.class, email);
|
||||
@@ -368,6 +380,22 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* True iff {@code email} matches the exact shape produced by {@link #runCreate()} for the current
|
||||
* {@code registrarId}: {@code <3 alnum>.<registrarId>@<gSuiteDomainName>}.
|
||||
*
|
||||
* <p>Addresses of any other shape were provisioned outside this action and should not be passed
|
||||
* to {@code directory.users().delete()}.
|
||||
*/
|
||||
private boolean isConsoleMintedAddress(String email) {
|
||||
return email.endsWith("@" + gSuiteDomainName)
|
||||
&& Pattern.matches(
|
||||
String.format(
|
||||
"^[a-zA-Z0-9]{3}\\.%s@%s$",
|
||||
Pattern.quote(registrarId), Pattern.quote(gSuiteDomainName)),
|
||||
email);
|
||||
}
|
||||
|
||||
public record UserData(
|
||||
@Expose String emailAddress,
|
||||
@Expose String registryLockEmailAddress,
|
||||
|
||||
@@ -20,7 +20,10 @@ import static jakarta.servlet.http.HttpServletResponse.SC_CREATED;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.services.directory.Directory;
|
||||
@@ -243,7 +246,8 @@ class ConsoleUsersActionTest extends ConsoleActionBaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_deletesUser() throws IOException {
|
||||
void testSuccess_deletesUser_nonConsoleMintedAddress_skipsWorkspaceAccountDeletion()
|
||||
throws IOException {
|
||||
User user1 = DatabaseHelper.loadByKey(VKey.create(User.class, "test1@test.com"));
|
||||
AuthResult authResult =
|
||||
AuthResult.createUser(
|
||||
@@ -265,6 +269,44 @@ class ConsoleUsersActionTest extends ConsoleActionBaseTestCase {
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(DatabaseHelper.loadByKeyIfPresent(VKey.create(User.class, "test2@test.com")))
|
||||
.isEmpty();
|
||||
verify(users, never()).delete(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_deletesUser_consoleMintedAddress_deletesWorkspaceAccount() throws IOException {
|
||||
User user1 = DatabaseHelper.loadByKey(VKey.create(User.class, "test1@test.com"));
|
||||
AuthResult authResult =
|
||||
AuthResult.createUser(
|
||||
user1
|
||||
.asBuilder()
|
||||
.setUserRoles(user1.getUserRoles().asBuilder().setIsAdmin(true).build())
|
||||
.build());
|
||||
String mintedEmail = "abc.TheRegistrar@email.com";
|
||||
DatabaseHelper.persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress(mintedEmail)
|
||||
.setUserRoles(
|
||||
new UserRoles()
|
||||
.asBuilder()
|
||||
.setRegistrarRoles(
|
||||
ImmutableMap.of("TheRegistrar", RegistrarRole.PRIMARY_CONTACT))
|
||||
.build())
|
||||
.build());
|
||||
|
||||
ConsoleUsersAction action =
|
||||
createAction(
|
||||
Optional.of(ConsoleApiParamsUtils.createFake(authResult)),
|
||||
Optional.of("DELETE"),
|
||||
Optional.of(
|
||||
new UserData(mintedEmail, null, RegistrarRole.ACCOUNT_MANAGER.toString(), null)));
|
||||
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
when(directory.users()).thenReturn(users);
|
||||
when(users.delete(mintedEmail)).thenReturn(delete);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(DatabaseHelper.loadByKeyIfPresent(VKey.create(User.class, mintedEmail))).isEmpty();
|
||||
verify(users).delete(mintedEmail);
|
||||
verify(delete).execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user