mirror of
https://github.com/google/nomulus
synced 2026-08-28 03:46:30 +00:00
Call Workspace Groups API directly from nomulus tool (#2515)
When creating/deleting users, we need to add/remove the emails in question to/from the console email group (if it exists). This used to be done synchronously by calling the Groups API directly from the nomulus tool. However #2488 made it so that in all cases where group membership is modified, a Cloud Tasks task is created to execute the change on the server side asynchronously (because there are multiple places where this change needs to be done, and it is easier to make it all happen on the server side). Alas, as it turns out, Cloud Tasks tasks need to be created with a service account's credential (which is trivially done on the server side because the ADC is a service account). Nomulus command runs with a user credential, and we need to grant the relevant user permission to masquerade as a service account, in order to enqueue tasks from the nomulus tool. It is therefore easier to just revert to the old behavior.
This commit is contained in:
@@ -21,15 +21,20 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.tools.IamClient;
|
||||
import google.registry.tools.ServiceConnection;
|
||||
import google.registry.tools.server.UpdateUserGroupAction;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -57,6 +62,34 @@ public class UserTest extends EntityTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_asyncAndSyncModeConflict() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> User.grantIapPermission("email@example.com", Optional.empty(), null, null, null));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
User.grantIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
mock(CloudTasksUtils.class),
|
||||
mock(ServiceConnection.class),
|
||||
null));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> User.revokeIapPermission("email@example.com", Optional.empty(), null, null, null));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
User.revokeIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
mock(CloudTasksUtils.class),
|
||||
mock(ServiceConnection.class),
|
||||
null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_badInputs() {
|
||||
User.Builder builder = new User.Builder();
|
||||
@@ -116,19 +149,20 @@ public class UserTest extends EntityTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGrantIapPermission() {
|
||||
void testGrantIapPermissionAsync() {
|
||||
CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
|
||||
IamClient iamClient = mock(IamClient.class);
|
||||
CloudTasksUtils cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
|
||||
// Individual permission.
|
||||
User.grantIapPermission("email@example.com", Optional.empty(), cloudTasksUtils, iamClient);
|
||||
User.grantIapPermission(
|
||||
"email@example.com", Optional.empty(), cloudTasksUtils, null, iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued();
|
||||
verify(iamClient).addBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
|
||||
// Group membership.
|
||||
User.grantIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), cloudTasksUtils, iamClient);
|
||||
"email@example.com", Optional.of("console@example.com"), cloudTasksUtils, null, iamClient);
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
new TaskMatcher()
|
||||
@@ -142,19 +176,49 @@ public class UserTest extends EntityTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRevokeIapPermission() {
|
||||
void testGrantIapPermissionSync() throws Exception {
|
||||
ServiceConnection connection = mock(ServiceConnection.class);
|
||||
IamClient iamClient = mock(IamClient.class);
|
||||
|
||||
// Individual permission.
|
||||
User.grantIapPermission("email@example.com", Optional.empty(), null, connection, iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
verify(iamClient).addBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
|
||||
// Group membership.
|
||||
User.grantIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), null, connection, iamClient);
|
||||
verify(connection)
|
||||
.sendPostRequest(
|
||||
UpdateUserGroupAction.PATH,
|
||||
ImmutableMap.of(
|
||||
"userEmailAddress",
|
||||
"email@example.com",
|
||||
"groupEmailAddress",
|
||||
"console@example.com",
|
||||
"groupUpdateMode",
|
||||
"ADD"),
|
||||
MediaType.PLAIN_TEXT_UTF_8,
|
||||
new byte[0]);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
verifyNoMoreInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRevokeIapPermissionAsync() {
|
||||
CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
|
||||
IamClient iamClient = mock(IamClient.class);
|
||||
CloudTasksUtils cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
|
||||
// Individual permission.
|
||||
User.revokeIapPermission("email@example.com", Optional.empty(), cloudTasksUtils, iamClient);
|
||||
User.revokeIapPermission(
|
||||
"email@example.com", Optional.empty(), cloudTasksUtils, null, iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued();
|
||||
verify(iamClient).removeBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
|
||||
// Group membership.
|
||||
User.revokeIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), cloudTasksUtils, iamClient);
|
||||
"email@example.com", Optional.of("console@example.com"), cloudTasksUtils, null, iamClient);
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
new TaskMatcher()
|
||||
@@ -166,4 +230,33 @@ public class UserTest extends EntityTestCase {
|
||||
.param("groupUpdateMode", "REMOVE"));
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRevokeIapPermissionSync() throws Exception {
|
||||
ServiceConnection connection = mock(ServiceConnection.class);
|
||||
IamClient iamClient = mock(IamClient.class);
|
||||
|
||||
// Individual permission.
|
||||
User.revokeIapPermission("email@example.com", Optional.empty(), null, connection, iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
verify(iamClient).removeBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
|
||||
// Group membership.
|
||||
User.revokeIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), null, connection, iamClient);
|
||||
verify(connection)
|
||||
.sendPostRequest(
|
||||
UpdateUserGroupAction.PATH,
|
||||
ImmutableMap.of(
|
||||
"userEmailAddress",
|
||||
"email@example.com",
|
||||
"groupEmailAddress",
|
||||
"console@example.com",
|
||||
"groupUpdateMode",
|
||||
"REMOVE"),
|
||||
MediaType.PLAIN_TEXT_UTF_8,
|
||||
new byte[0]);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
verifyNoMoreInteractions(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,15 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.tools.server.UpdateUserGroupAction;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -40,13 +39,13 @@ import org.junit.jupiter.api.Test;
|
||||
public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
|
||||
private final IamClient iamClient = mock(IamClient.class);
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
|
||||
private final ServiceConnection connection = mock(ServiceConnection.class);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
command.iamClient = iamClient;
|
||||
command.maybeGroupEmailAddress = Optional.empty();
|
||||
command.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
command.setConnection(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -59,7 +58,7 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
assertThat(onlyUser.getUserRoles().getRegistrarRoles()).isEmpty();
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -71,16 +70,20 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
assertThat(onlyUser.getUserRoles().isAdmin()).isFalse();
|
||||
assertThat(onlyUser.getUserRoles().getGlobalRole()).isEqualTo(GlobalRole.NONE);
|
||||
assertThat(onlyUser.getUserRoles().getRegistrarRoles()).isEmpty();
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
new TaskMatcher()
|
||||
.method(HttpMethod.POST)
|
||||
.service("TOOLS")
|
||||
.path("/_dr/admin/updateUserGroup")
|
||||
.param("userEmailAddress", "user@example.test")
|
||||
.param("groupEmailAddress", "group@example.test")
|
||||
.param("groupUpdateMode", "ADD"));
|
||||
verify(connection)
|
||||
.sendPostRequest(
|
||||
UpdateUserGroupAction.PATH,
|
||||
ImmutableMap.of(
|
||||
"userEmailAddress",
|
||||
"user@example.test",
|
||||
"groupEmailAddress",
|
||||
"group@example.test",
|
||||
"groupUpdateMode",
|
||||
"ADD"),
|
||||
MediaType.PLAIN_TEXT_UTF_8,
|
||||
new byte[0]);
|
||||
verifyNoInteractions(iamClient);
|
||||
verifyNoMoreInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,7 +103,7 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
assertThat(UserDao.loadUser("user@example.test").get().getUserRoles().isAdmin()).isTrue();
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,7 +113,7 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
.isEqualTo(GlobalRole.FTE);
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,7 +132,7 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
RegistrarRole.PRIMARY_CONTACT));
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,7 +147,7 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
.hasMessageThat()
|
||||
.isEqualTo("A user with email user@example.test already exists");
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -22,11 +22,11 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.cloud.tasks.v2.HttpMethod;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.model.console.UserDao;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.CloudTasksHelper.TaskMatcher;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.tools.server.UpdateUserGroupAction;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -35,13 +35,13 @@ import org.junit.jupiter.api.Test;
|
||||
public class DeleteUserCommandTest extends CommandTestCase<DeleteUserCommand> {
|
||||
|
||||
private final IamClient iamClient = mock(IamClient.class);
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
|
||||
private final ServiceConnection connection = mock(ServiceConnection.class);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
command.iamClient = iamClient;
|
||||
command.maybeGroupEmailAddress = Optional.empty();
|
||||
command.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
command.setConnection(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -52,7 +52,7 @@ public class DeleteUserCommandTest extends CommandTestCase<DeleteUserCommand> {
|
||||
assertThat(UserDao.loadUser("email@example.test")).isEmpty();
|
||||
verify(iamClient).removeBinding("email@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -62,16 +62,20 @@ public class DeleteUserCommandTest extends CommandTestCase<DeleteUserCommand> {
|
||||
assertThat(UserDao.loadUser("email@example.test")).isPresent();
|
||||
runCommandForced("--email", "email@example.test");
|
||||
assertThat(UserDao.loadUser("email@example.test")).isEmpty();
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
new TaskMatcher()
|
||||
.method(HttpMethod.POST)
|
||||
.service("TOOLS")
|
||||
.path("/_dr/admin/updateUserGroup")
|
||||
.param("userEmailAddress", "email@example.test")
|
||||
.param("groupEmailAddress", "group@example.test")
|
||||
.param("groupUpdateMode", "REMOVE"));
|
||||
verify(connection)
|
||||
.sendPostRequest(
|
||||
UpdateUserGroupAction.PATH,
|
||||
ImmutableMap.of(
|
||||
"userEmailAddress",
|
||||
"email@example.test",
|
||||
"groupEmailAddress",
|
||||
"group@example.test",
|
||||
"groupUpdateMode",
|
||||
"REMOVE"),
|
||||
MediaType.PLAIN_TEXT_UTF_8,
|
||||
new byte[0]);
|
||||
verifyNoInteractions(iamClient);
|
||||
verifyNoMoreInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,6 +87,6 @@ public class DeleteUserCommandTest extends CommandTestCase<DeleteUserCommand> {
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Email does not correspond to a valid user");
|
||||
verifyNoInteractions(iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user