mirror of
https://github.com/google/nomulus
synced 2026-07-23 08:22:27 +00:00
Only grant IAP access to the console for new users (#3167)
Currently we grant users IAP_SECURED_WEB_APP_USER_ROLE access to the entire project upon creation if there is no preexisting group set up for them to use. These users only need to be able to access the console, so we should restrict it to the console. If there is a group (which we do have in our prod + sandbox configuration) then we just add them to that group instead and that group controls all the privileges. So this is a no-op for our setup. We prioritize the group -- if both the group and the IAP service ID are specified, we'll still just add them to the group b/534931170
This commit is contained in:
@@ -165,6 +165,12 @@ public final class RegistryConfig {
|
||||
return config.misc.isEmailSendingEnabled;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("consoleIapServiceId")
|
||||
public static Optional<String> provideConsoleIapServiceId(RegistryConfigSettings config) {
|
||||
return Optional.ofNullable(config.registrarConsole.consoleIapServiceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* The e-mail address for general support. Used in the "contact-us" section of the registrar
|
||||
* console.
|
||||
|
||||
@@ -187,6 +187,7 @@ public class RegistryConfigSettings {
|
||||
|
||||
/** Configuration for the web-based registrar console. */
|
||||
public static class RegistrarConsole {
|
||||
public String consoleIapServiceId;
|
||||
public String dumFileName;
|
||||
public String supportPhoneNumber;
|
||||
public String supportEmailAddress;
|
||||
|
||||
@@ -390,6 +390,11 @@ rde:
|
||||
sshIdentityEmailAddress: rde@example.com
|
||||
|
||||
registrarConsole:
|
||||
# IAP service ID of the HTTP(s) load balancer that serves the console-api backend.
|
||||
# Users created in the console will be bound only to this service to limit access.
|
||||
# This is only applicable to non-group-based auth (if there is no consoleUserGroupEmailAddress)
|
||||
consoleIapServiceId: null
|
||||
|
||||
# DUM download file name, excluding the extension
|
||||
dumFileName: dum_file_name
|
||||
|
||||
|
||||
@@ -197,8 +197,7 @@ public final class OteAccountBuilder {
|
||||
registrars.stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
Registrar::getRegistrarId,
|
||||
registrar -> RegistrarRole.ACCOUNT_MANAGER)))
|
||||
Registrar::getRegistrarId, _ -> RegistrarRole.ACCOUNT_MANAGER)))
|
||||
.build())
|
||||
.build());
|
||||
return this;
|
||||
@@ -265,10 +264,18 @@ public final class OteAccountBuilder {
|
||||
|
||||
/** Grants the users permission to pass IAP. */
|
||||
public void grantIapPermission(
|
||||
Optional<String> groupEmailAddress, CloudTasksUtils cloudTasksUtils, IamClient iamClient) {
|
||||
Optional<String> groupEmailAddress,
|
||||
Optional<String> consoleIapServiceId,
|
||||
CloudTasksUtils cloudTasksUtils,
|
||||
IamClient iamClient) {
|
||||
for (User user : users) {
|
||||
User.grantIapPermission(
|
||||
user.getEmailAddress(), groupEmailAddress, cloudTasksUtils, null, iamClient);
|
||||
user.getEmailAddress(),
|
||||
groupEmailAddress,
|
||||
consoleIapServiceId,
|
||||
cloudTasksUtils,
|
||||
null,
|
||||
iamClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
public static void grantIapPermission(
|
||||
String emailAddress,
|
||||
Optional<String> groupEmailAddress,
|
||||
Optional<String> consoleIapServiceId,
|
||||
@Nullable CloudTasksUtils cloudTasksUtils,
|
||||
@Nullable ServiceConnection connection,
|
||||
IamClient iamClient) {
|
||||
@@ -93,14 +94,14 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
return;
|
||||
}
|
||||
checkArgument(
|
||||
cloudTasksUtils != null || connection != null,
|
||||
"At least one of cloudTasksUtils or connection must be set");
|
||||
cloudTasksUtils == null ^ connection == null,
|
||||
"Precisely one of cloudTasksUtils or connection can be set");
|
||||
checkArgument(
|
||||
cloudTasksUtils == null || connection == null,
|
||||
"Only one of cloudTasksUtils or connection can be set");
|
||||
groupEmailAddress.isPresent() || consoleIapServiceId.isPresent(),
|
||||
"At least one of groupEmailAddress or consoleIapServiceId must be present");
|
||||
if (groupEmailAddress.isEmpty()) {
|
||||
logger.atInfo().log("Granting IAP role to user %s", emailAddress);
|
||||
iamClient.addBinding(emailAddress, IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
iamClient.addBinding(emailAddress, IAP_SECURED_WEB_APP_USER_ROLE, consoleIapServiceId.get());
|
||||
} else {
|
||||
logger.atInfo().log("Adding %s to group %s", emailAddress, groupEmailAddress.get());
|
||||
if (cloudTasksUtils != null) {
|
||||
@@ -129,11 +130,8 @@ public class User extends UpdateAutoTimestampEntity implements Buildable {
|
||||
return;
|
||||
}
|
||||
checkArgument(
|
||||
cloudTasksUtils != null || connection != null,
|
||||
"At least one of cloudTasksUtils or connection must be set");
|
||||
checkArgument(
|
||||
cloudTasksUtils == null || connection == null,
|
||||
"Only one of cloudTasksUtils or connection can be set");
|
||||
cloudTasksUtils == null ^ connection == null,
|
||||
"Precisely one of cloudTasksUtils or connection can be set");
|
||||
if (groupEmailAddress.isEmpty()) {
|
||||
logger.atInfo().log("Removing IAP role from user %s", emailAddress);
|
||||
iamClient.removeBinding(emailAddress, IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
|
||||
@@ -38,6 +38,10 @@ public class CreateUserCommand extends CreateOrUpdateUserCommand implements Comm
|
||||
@Config("gSuiteConsoleUserGroupEmailAddress")
|
||||
Optional<String> maybeGroupEmailAddress;
|
||||
|
||||
@Inject
|
||||
@Config("consoleIapServiceId")
|
||||
Optional<String> consoleIapServiceId;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
User getExistingUser(String email) {
|
||||
@@ -49,7 +53,8 @@ public class CreateUserCommand extends CreateOrUpdateUserCommand implements Comm
|
||||
@Override
|
||||
protected String execute() throws Exception {
|
||||
String ret = super.execute();
|
||||
grantIapPermission(email, maybeGroupEmailAddress, null, connection, iamClient);
|
||||
grantIapPermission(
|
||||
email, maybeGroupEmailAddress, consoleIapServiceId, null, connection, iamClient);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.tools;
|
||||
|
||||
import com.google.api.services.cloudresourcemanager.CloudResourceManager;
|
||||
import com.google.api.services.cloudresourcemanager.model.Binding;
|
||||
import com.google.api.services.cloudresourcemanager.model.Expr;
|
||||
import com.google.api.services.cloudresourcemanager.model.GetIamPolicyRequest;
|
||||
import com.google.api.services.cloudresourcemanager.model.Policy;
|
||||
import com.google.api.services.cloudresourcemanager.model.SetIamPolicyRequest;
|
||||
@@ -31,7 +32,10 @@ import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class IamClient {
|
||||
|
||||
private static final String MEMBER_FORMAT = "user:%s";
|
||||
private static final String IAP_ACCESS_EXPRESSION_FORMAT =
|
||||
"resource.name == 'projects/%s/iap_web/compute/services/%s'";
|
||||
|
||||
private final CloudResourceManager resourceManager;
|
||||
private final String projectId;
|
||||
@@ -60,7 +64,7 @@ public class IamClient {
|
||||
*
|
||||
* <p>No-op if the role is already bound to the account.
|
||||
*/
|
||||
public void addBinding(String account, String role) {
|
||||
public void addBinding(String account, String role, String consoleIapServiceId) {
|
||||
String member = String.format(MEMBER_FORMAT, account);
|
||||
Policy policy = getPolicy();
|
||||
Binding binding =
|
||||
@@ -69,7 +73,21 @@ public class IamClient {
|
||||
.findFirst()
|
||||
.orElseGet(
|
||||
() -> {
|
||||
Binding newBinding = new Binding().setRole(role).setMembers(new ArrayList<>());
|
||||
Binding newBinding =
|
||||
new Binding()
|
||||
.setRole(role)
|
||||
.setMembers(new ArrayList<>())
|
||||
.setCondition(
|
||||
new Expr()
|
||||
.setTitle("Registrar Console IAP access")
|
||||
.setDescription(
|
||||
"Restrict IAP access only to the Registrar Console HTTP(s)"
|
||||
+ " load balancer")
|
||||
.setExpression(
|
||||
String.format(
|
||||
IAP_ACCESS_EXPRESSION_FORMAT,
|
||||
projectId,
|
||||
consoleIapServiceId)));
|
||||
policy.getBindings().add(newBinding);
|
||||
return newBinding;
|
||||
});
|
||||
|
||||
@@ -86,6 +86,10 @@ final class SetupOteCommand extends ConfirmingCommand {
|
||||
@Config("gSuiteConsoleUserGroupEmailAddress")
|
||||
Optional<String> maybeGroupEmailAddress;
|
||||
|
||||
@Inject
|
||||
@Config("consoleIapServiceId")
|
||||
Optional<String> consoleIapServiceId;
|
||||
|
||||
OteAccountBuilder oteAccountBuilder;
|
||||
String password;
|
||||
|
||||
@@ -138,7 +142,8 @@ you sure you didn't mean to run this against sandbox (e.g. "-e SANDBOX")?\
|
||||
@Override
|
||||
public String execute() {
|
||||
ImmutableMap<String, String> clientIdToTld = oteAccountBuilder.buildAndPersist();
|
||||
oteAccountBuilder.grantIapPermission(maybeGroupEmailAddress, cloudTasksUtils, iamClient);
|
||||
oteAccountBuilder.grantIapPermission(
|
||||
maybeGroupEmailAddress, consoleIapServiceId, cloudTasksUtils, iamClient);
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
private final StringGenerator passwordGenerator;
|
||||
private final Optional<OteCreateData> oteCreateData;
|
||||
private final Optional<String> maybeGroupEmailAddress;
|
||||
private final Optional<String> consoleIapServiceId;
|
||||
private final IamClient iamClient;
|
||||
private final String registrarId;
|
||||
|
||||
@@ -71,12 +72,14 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
IamClient iamClient,
|
||||
@Parameter("registrarId") String registrarId, // Get request param
|
||||
@Config("gSuiteConsoleUserGroupEmailAddress") Optional<String> maybeGroupEmailAddress,
|
||||
@Config("consoleIapServiceId") Optional<String> consoleIapServiceId,
|
||||
@Named("base58StringGenerator") StringGenerator passwordGenerator,
|
||||
@Parameter("oteCreateData") Optional<OteCreateData> oteCreateData) {
|
||||
super(consoleApiParams);
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
this.oteCreateData = oteCreateData;
|
||||
this.maybeGroupEmailAddress = maybeGroupEmailAddress;
|
||||
this.consoleIapServiceId = consoleIapServiceId;
|
||||
this.iamClient = iamClient;
|
||||
this.registrarId = registrarId;
|
||||
}
|
||||
@@ -105,7 +108,8 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
.setPassword(password);
|
||||
|
||||
ImmutableMap<String, String> registrarIdToTld = oteAccountBuilder.buildAndPersist();
|
||||
oteAccountBuilder.grantIapPermission(maybeGroupEmailAddress, cloudTasksUtils, iamClient);
|
||||
oteAccountBuilder.grantIapPermission(
|
||||
maybeGroupEmailAddress, consoleIapServiceId, cloudTasksUtils, iamClient);
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
consoleApiParams
|
||||
.response()
|
||||
|
||||
@@ -79,6 +79,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
private final StringGenerator passwordGenerator;
|
||||
private final Optional<UserData> userData;
|
||||
private final Optional<String> maybeGroupEmailAddress;
|
||||
private final Optional<String> consoleIapServiceId;
|
||||
private final IamClient iamClient;
|
||||
private final String gSuiteDomainName;
|
||||
|
||||
@@ -89,6 +90,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
IamClient iamClient,
|
||||
@Config("gSuiteDomainName") String gSuiteDomainName,
|
||||
@Config("gSuiteConsoleUserGroupEmailAddress") Optional<String> maybeGroupEmailAddress,
|
||||
@Config("consoleIapServiceId") Optional<String> consoleIapServiceId,
|
||||
@Named("base58StringGenerator") StringGenerator passwordGenerator,
|
||||
@Parameter("userData") Optional<UserData> userData,
|
||||
@Parameter("registrarId") String registrarId) {
|
||||
@@ -98,6 +100,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
this.userData = userData;
|
||||
this.maybeGroupEmailAddress = maybeGroupEmailAddress;
|
||||
this.consoleIapServiceId = consoleIapServiceId;
|
||||
this.iamClient = iamClient;
|
||||
this.gSuiteDomainName = gSuiteDomainName;
|
||||
}
|
||||
@@ -256,7 +259,8 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
|
||||
User.Builder builder = new User.Builder().setUserRoles(userRoles).setEmailAddress(newEmail);
|
||||
tm().put(builder.build());
|
||||
User.grantIapPermission(newEmail, maybeGroupEmailAddress, cloudTasksUtils, null, iamClient);
|
||||
User.grantIapPermission(
|
||||
newEmail, maybeGroupEmailAddress, consoleIapServiceId, cloudTasksUtils, null, iamClient);
|
||||
sendConfirmationEmail(registrarId, newEmail, "Created user");
|
||||
consoleApiParams.response().setStatus(SC_CREATED);
|
||||
consoleApiParams
|
||||
|
||||
@@ -116,6 +116,7 @@ public final class OteAccountBuilderTest {
|
||||
public static void verifyIapPermission(
|
||||
@Nullable String emailAddress,
|
||||
Optional<String> maybeGroupEmailAddress,
|
||||
Optional<String> consoleIapServiceId,
|
||||
CloudTasksHelper cloudTasksHelper,
|
||||
IamClient iamClient) {
|
||||
if (emailAddress == null) {
|
||||
@@ -125,7 +126,8 @@ public final class OteAccountBuilderTest {
|
||||
String groupEmailAddress = maybeGroupEmailAddress.orElse(null);
|
||||
if (groupEmailAddress == null) {
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verify(iamClient).addBinding(emailAddress, IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding(emailAddress, IAP_SECURED_WEB_APP_USER_ROLE, consoleIapServiceId.get());
|
||||
} else {
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
@@ -146,9 +148,32 @@ public final class OteAccountBuilderTest {
|
||||
CloudTasksUtils cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
OteAccountBuilder.forRegistrarId("myclientid")
|
||||
.addUser("email@example.com")
|
||||
.grantIapPermission(Optional.of("console@example.com"), cloudTasksUtils, iamClient);
|
||||
.grantIapPermission(
|
||||
Optional.of("console@example.com"),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
cloudTasksUtils,
|
||||
iamClient);
|
||||
verifyIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), cloudTasksHelper, iamClient);
|
||||
"email@example.com",
|
||||
Optional.of("console@example.com"),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
cloudTasksHelper,
|
||||
iamClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateUserGroup_worksWithoutIapServiceId() {
|
||||
CloudTasksUtils cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
OteAccountBuilder.forRegistrarId("myclientid")
|
||||
.addUser("email@example.com")
|
||||
.grantIapPermission(
|
||||
Optional.of("console@example.com"), Optional.empty(), cloudTasksUtils, iamClient);
|
||||
verifyIapPermission(
|
||||
"email@example.com",
|
||||
Optional.of("console@example.com"),
|
||||
Optional.empty(),
|
||||
cloudTasksHelper,
|
||||
iamClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -156,8 +181,14 @@ public final class OteAccountBuilderTest {
|
||||
CloudTasksUtils cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
OteAccountBuilder.forRegistrarId("myclientid")
|
||||
.addUser("email@example.com")
|
||||
.grantIapPermission(Optional.empty(), cloudTasksUtils, iamClient);
|
||||
verifyIapPermission("email@example.com", Optional.empty(), cloudTasksHelper, iamClient);
|
||||
.grantIapPermission(
|
||||
Optional.empty(), Optional.of("consoleIapServiceId"), cloudTasksUtils, iamClient);
|
||||
verifyIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
cloudTasksHelper,
|
||||
iamClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -66,13 +66,21 @@ public class UserTest extends EntityTestCase {
|
||||
void testFailure_asyncAndSyncModeConflict() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> User.grantIapPermission("email@example.com", Optional.empty(), null, null, null));
|
||||
() ->
|
||||
User.grantIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
null,
|
||||
null,
|
||||
null));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
User.grantIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
mock(CloudTasksUtils.class),
|
||||
mock(ServiceConnection.class),
|
||||
null));
|
||||
@@ -90,6 +98,24 @@ public class UserTest extends EntityTestCase {
|
||||
null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGrantIapPermission_neitherGroupNorIapServiceId_fails() {
|
||||
IllegalArgumentException e =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
User.grantIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
mock(CloudTasksUtils.class),
|
||||
null,
|
||||
mock(IamClient.class)));
|
||||
assertThat(e)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("At least one of groupEmailAddress or consoleIapServiceId must be present");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_badInputs() {
|
||||
User.Builder builder = new User.Builder();
|
||||
@@ -156,13 +182,33 @@ public class UserTest extends EntityTestCase {
|
||||
|
||||
// Individual permission.
|
||||
User.grantIapPermission(
|
||||
"email@example.com", Optional.empty(), cloudTasksUtils, null, iamClient);
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
cloudTasksUtils,
|
||||
null,
|
||||
iamClient);
|
||||
cloudTasksHelper.assertNoTasksEnqueued();
|
||||
verify(iamClient).addBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
|
||||
// Group membership.
|
||||
User.grantIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), cloudTasksUtils, null, iamClient);
|
||||
"email@example.com",
|
||||
Optional.of("console@example.com"),
|
||||
Optional.empty(),
|
||||
cloudTasksUtils,
|
||||
null,
|
||||
iamClient);
|
||||
// Group membership takes precedence over individual membership
|
||||
User.grantIapPermission(
|
||||
"groupemail@example.com",
|
||||
Optional.of("console@example.com"),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
cloudTasksUtils,
|
||||
null,
|
||||
iamClient);
|
||||
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
new TaskMatcher()
|
||||
@@ -171,6 +217,13 @@ public class UserTest extends EntityTestCase {
|
||||
.path("/_dr/admin/updateUserGroup")
|
||||
.param("userEmailAddress", "email@example.com")
|
||||
.param("groupEmailAddress", "console@example.com")
|
||||
.param("groupUpdateMode", "ADD"),
|
||||
new TaskMatcher()
|
||||
.service("BACKEND")
|
||||
.method(HttpMethod.POST)
|
||||
.path("/_dr/admin/updateUserGroup")
|
||||
.param("userEmailAddress", "groupemail@example.com")
|
||||
.param("groupEmailAddress", "console@example.com")
|
||||
.param("groupUpdateMode", "ADD"));
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
}
|
||||
@@ -181,13 +234,25 @@ public class UserTest extends EntityTestCase {
|
||||
IamClient iamClient = mock(IamClient.class);
|
||||
|
||||
// Individual permission.
|
||||
User.grantIapPermission("email@example.com", Optional.empty(), null, connection, iamClient);
|
||||
User.grantIapPermission(
|
||||
"email@example.com",
|
||||
Optional.empty(),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
null,
|
||||
connection,
|
||||
iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
verify(iamClient).addBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("email@example.com", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
|
||||
// Group membership.
|
||||
User.grantIapPermission(
|
||||
"email@example.com", Optional.of("console@example.com"), null, connection, iamClient);
|
||||
"email@example.com",
|
||||
Optional.of("console@example.com"),
|
||||
Optional.empty(),
|
||||
null,
|
||||
connection,
|
||||
iamClient);
|
||||
verify(connection)
|
||||
.sendPostRequest(
|
||||
UpdateUserGroupAction.PATH,
|
||||
|
||||
@@ -45,6 +45,7 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
void beforeEach() {
|
||||
command.iamClient = iamClient;
|
||||
command.maybeGroupEmailAddress = Optional.empty();
|
||||
command.consoleIapServiceId = Optional.of("consoleIapServiceId");
|
||||
command.setConnection(connection);
|
||||
}
|
||||
|
||||
@@ -56,7 +57,8 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
assertThat(onlyUser.getUserRoles().isAdmin()).isFalse();
|
||||
assertThat(onlyUser.getUserRoles().getGlobalRole()).isEqualTo(GlobalRole.NONE);
|
||||
assertThat(onlyUser.getUserRoles().getRegistrarRoles()).isEmpty();
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
@@ -86,6 +88,41 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
verifyNoMoreInteractions(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_addToGroup_noIapServiceId() throws Exception {
|
||||
command.maybeGroupEmailAddress = Optional.of("group@example.test");
|
||||
command.consoleIapServiceId = Optional.empty();
|
||||
runCommandForced("--email", "user@example.test");
|
||||
User onlyUser = Iterables.getOnlyElement(DatabaseHelper.loadAllOf(User.class));
|
||||
assertThat(onlyUser.getEmailAddress()).isEqualTo("user@example.test");
|
||||
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
|
||||
void testFailure_neitherGroupNorIapServiceId() {
|
||||
command.maybeGroupEmailAddress = Optional.empty();
|
||||
command.consoleIapServiceId = Optional.empty();
|
||||
IllegalArgumentException e =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> runCommandForced("--email", "user@example.test"));
|
||||
assertThat(e)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("At least one of groupEmailAddress or consoleIapServiceId must be present");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_registryLock() throws Exception {
|
||||
runCommandForced(
|
||||
@@ -107,7 +144,8 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
void testSuccess_admin() throws Exception {
|
||||
runCommandForced("--email", "user@example.test", "--admin", "true");
|
||||
assertThat(loadExistingUser("user@example.test").getUserRoles().isAdmin()).isTrue();
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
@@ -117,7 +155,8 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
runCommandForced("--email", "user@example.test", "--global_role", "FTE");
|
||||
assertThat(loadExistingUser("user@example.test").getUserRoles().getGlobalRole())
|
||||
.isEqualTo(GlobalRole.FTE);
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
@@ -136,7 +175,8 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
RegistrarRole.ACCOUNT_MANAGER,
|
||||
"NewRegistrar",
|
||||
RegistrarRole.PRIMARY_CONTACT));
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
verifyNoInteractions(connection);
|
||||
}
|
||||
@@ -144,7 +184,8 @@ public class CreateUserCommandTest extends CommandTestCase<CreateUserCommand> {
|
||||
@Test
|
||||
void testFailure_alreadyExists() throws Exception {
|
||||
runCommandForced("--email", "user@example.test");
|
||||
verify(iamClient).addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding("user@example.test", IAP_SECURED_WEB_APP_USER_ROLE, "consoleIapServiceId");
|
||||
verifyNoMoreInteractions(iamClient);
|
||||
assertThat(
|
||||
assertThrows(
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.mockito.ArgumentCaptor;
|
||||
/** Unit tests for {@link IamClient}. */
|
||||
public class IamClientTest {
|
||||
private final CloudResourceManager resourceManager = mock(CloudResourceManager.class);
|
||||
private final String consoleIapServiceId = "123456789";
|
||||
private final String projectId = "my-project";
|
||||
private final String account = "test@example.test";
|
||||
private final String role = "roles/fakeRole";
|
||||
@@ -89,11 +90,17 @@ public class IamClientTest {
|
||||
void testSuccess_addBinding_noMatchedBindingExists() throws Exception {
|
||||
setupRequests();
|
||||
assertThat(bindings.size()).isEqualTo(1);
|
||||
client.addBinding(account, role);
|
||||
client.addBinding(account, role, consoleIapServiceId);
|
||||
assertThat(bindings.size()).isEqualTo(2);
|
||||
Binding binding = bindings.get(1);
|
||||
assertThat(binding.getRole()).isEqualTo(role);
|
||||
assertThat(binding.getMembers()).containsExactly("user:" + account);
|
||||
assertThat(binding.getCondition()).isNotNull();
|
||||
assertThat(binding.getCondition().getTitle()).isEqualTo("Registrar Console IAP access");
|
||||
assertThat(binding.getCondition().getDescription())
|
||||
.isEqualTo("Restrict IAP access only to the Registrar Console HTTP(s) load balancer");
|
||||
assertThat(binding.getCondition().getExpression())
|
||||
.isEqualTo("resource.name == 'projects/my-project/iap_web/compute/services/123456789'");
|
||||
verifySetPolicyRequest();
|
||||
}
|
||||
|
||||
@@ -107,7 +114,7 @@ public class IamClientTest {
|
||||
when(matchedBinding.getMembers()).thenReturn(existingMembers);
|
||||
bindings.add(matchedBinding);
|
||||
assertThat(bindings.size()).isEqualTo(2);
|
||||
client.addBinding(account, role);
|
||||
client.addBinding(account, role, consoleIapServiceId);
|
||||
assertThat(bindings.size()).isEqualTo(2);
|
||||
assertThat(existingMembers)
|
||||
.containsExactly("serviceAccount:service@example.test", "user:" + account);
|
||||
@@ -125,7 +132,7 @@ public class IamClientTest {
|
||||
when(matchedBinding.getMembers()).thenReturn(existingMembers);
|
||||
bindings.add(matchedBinding);
|
||||
assertThat(bindings.size()).isEqualTo(2);
|
||||
client.addBinding(account, role);
|
||||
client.addBinding(account, role, consoleIapServiceId);
|
||||
assertThat(bindings.size()).isEqualTo(2);
|
||||
assertThat(existingMembers)
|
||||
.containsExactly("serviceAccount:service@example.test", "user:" + account);
|
||||
|
||||
@@ -73,6 +73,7 @@ class SetupOteCommandTest extends CommandTestCase<SetupOteCommand> {
|
||||
command.clock = fakeClock;
|
||||
command.passwordGenerator = passwordGenerator;
|
||||
command.maybeGroupEmailAddress = Optional.of("group@example.com");
|
||||
command.consoleIapServiceId = Optional.of("consoleIapServiceId");
|
||||
command.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
command.iamClient = iamClient;
|
||||
persistPremiumList("default_sandbox_list", USD, "sandbox,USD 1000");
|
||||
@@ -129,7 +130,9 @@ class SetupOteCommandTest extends CommandTestCase<SetupOteCommand> {
|
||||
String groupEmailAddress = command.maybeGroupEmailAddress.orElse(null);
|
||||
if (groupEmailAddress == null) {
|
||||
cloudTasksHelper.assertNoTasksEnqueued("console-user-group-update");
|
||||
verify(iamClient).addBinding(emailAddress, IAP_SECURED_WEB_APP_USER_ROLE);
|
||||
verify(iamClient)
|
||||
.addBinding(
|
||||
emailAddress, IAP_SECURED_WEB_APP_USER_ROLE, command.consoleIapServiceId.get());
|
||||
} else {
|
||||
cloudTasksHelper.assertTasksEnqueued(
|
||||
"console-user-group-update",
|
||||
|
||||
@@ -144,6 +144,7 @@ class ConsoleOteActionTest extends ConsoleActionBaseTestCase {
|
||||
verifyIapPermission(
|
||||
"contact@registry.example",
|
||||
Optional.of("someRandomString@email.test"),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
cloudTasksHelper,
|
||||
iamClient);
|
||||
}
|
||||
@@ -216,6 +217,7 @@ class ConsoleOteActionTest extends ConsoleActionBaseTestCase {
|
||||
iamClient,
|
||||
registrarId,
|
||||
maybeGroupEmailAddress,
|
||||
Optional.of("consoleIapServiceId"),
|
||||
passwordGenerator,
|
||||
oteCreateData);
|
||||
}
|
||||
|
||||
@@ -663,6 +663,7 @@ class ConsoleUsersActionTest extends ConsoleActionBaseTestCase {
|
||||
iamClient,
|
||||
"email.com",
|
||||
Optional.of("someRandomString"),
|
||||
Optional.of("consoleIapServiceId"),
|
||||
passwordGenerator,
|
||||
userData,
|
||||
"TheRegistrar");
|
||||
|
||||
Reference in New Issue
Block a user