1
0
mirror of https://github.com/google/nomulus synced 2026-04-23 17:50:49 +00:00

Add console user role update and minor fixes to delete (#2610)

This commit is contained in:
Pavlo Tkach
2024-11-15 13:36:10 -05:00
committed by GitHub
parent e54075fea3
commit eeed166310
12 changed files with 380 additions and 183 deletions

View File

@@ -34,6 +34,7 @@ public @interface Action {
GET,
HEAD,
POST,
PUT,
DELETE
}

View File

@@ -20,6 +20,7 @@ import static google.registry.request.Action.Method.DELETE;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.Action.Method.PUT;
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
@@ -87,6 +88,8 @@ public abstract class ConsoleApiAction implements Runnable {
if (verifyXSRF(user)) {
if (requestMethod.equals(DELETE.toString())) {
deleteHandler(user);
} else if (requestMethod.equals(PUT.toString())) {
putHandler(user);
} else {
postHandler(user);
}
@@ -117,6 +120,10 @@ public abstract class ConsoleApiAction implements Runnable {
throw new UnsupportedOperationException("Console API POST handler not implemented");
}
protected void putHandler(User user) {
throw new UnsupportedOperationException("Console API PUT handler not implemented");
}
protected void getHandler(User user) {
throw new UnsupportedOperationException("Console API GET handler not implemented");
}

View File

@@ -36,7 +36,7 @@ import google.registry.ui.server.SendEmailUtils;
import google.registry.ui.server.console.ConsoleEppPasswordAction.EppPasswordData;
import google.registry.ui.server.console.ConsoleOteAction.OteCreateData;
import google.registry.ui.server.console.ConsoleRegistryLockAction.ConsoleRegistryLockPostInput;
import google.registry.ui.server.console.ConsoleUsersAction.UserDeleteData;
import google.registry.ui.server.console.ConsoleUsersAction.UserData;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;
import org.joda.time.DateTime;
@@ -247,10 +247,10 @@ public final class ConsoleModule {
}
@Provides
@Parameter("userDeleteData")
public static Optional<UserDeleteData> provideUserDeleteData(
@Parameter("userData")
public static Optional<UserData> provideUserData(
Gson gson, @OptionalJsonPayload Optional<JsonElement> payload) {
return payload.map(s -> gson.fromJson(s, UserDeleteData.class));
return payload.map(s -> gson.fromJson(s, UserData.class));
}
@Provides

View File

@@ -21,6 +21,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import static google.registry.request.Action.Method.DELETE;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.Action.Method.PUT;
import static jakarta.servlet.http.HttpServletResponse.SC_CREATED;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
@@ -35,6 +36,7 @@ import com.google.gson.Gson;
import com.google.gson.annotations.Expose;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.VKey;
@@ -50,6 +52,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
@@ -57,7 +60,7 @@ import javax.inject.Named;
service = Action.GaeService.DEFAULT,
gkeService = GkeService.CONSOLE,
path = ConsoleUsersAction.PATH,
method = {GET, POST, DELETE},
method = {GET, POST, DELETE, PUT},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ConsoleUsersAction extends ConsoleApiAction {
static final String PATH = "/console-api/users";
@@ -68,7 +71,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
private final String registrarId;
private final Directory directory;
private final StringGenerator passwordGenerator;
private final Optional<UserDeleteData> userDeleteData;
private final Optional<UserData> userData;
private final Optional<String> maybeGroupEmailAddress;
private final IamClient iamClient;
private final String gSuiteDomainName;
@@ -82,14 +85,14 @@ public class ConsoleUsersAction extends ConsoleApiAction {
@Config("gSuiteDomainName") String gSuiteDomainName,
@Config("gSuiteConsoleUserGroupEmailAddress") Optional<String> maybeGroupEmailAddress,
@Named("base58StringGenerator") StringGenerator passwordGenerator,
@Parameter("userDeleteData") Optional<UserDeleteData> userDeleteData,
@Parameter("userData") Optional<UserData> userData,
@Parameter("registrarId") String registrarId) {
super(consoleApiParams);
this.gson = gson;
this.registrarId = registrarId;
this.directory = directory;
this.passwordGenerator = passwordGenerator;
this.userDeleteData = userDeleteData;
this.userData = userData;
this.maybeGroupEmailAddress = maybeGroupEmailAddress;
this.iamClient = iamClient;
this.gSuiteDomainName = gSuiteDomainName;
@@ -106,18 +109,28 @@ public class ConsoleUsersAction extends ConsoleApiAction {
}
}
@Override
protected void putHandler(User user) {
// Temporary flag while testing
if (user.getUserRoles().isAdmin()) {
checkPermission(user, registrarId, ConsolePermission.MANAGE_USERS);
tm().transact(() -> runUpdateInTransaction());
} else {
consoleApiParams.response().setStatus(SC_FORBIDDEN);
}
}
@Override
protected void getHandler(User user) {
checkPermission(user, registrarId, ConsolePermission.MANAGE_USERS);
List<ImmutableMap> users =
List<UserData> users =
getAllRegistrarUsers(registrarId).stream()
.map(
u ->
ImmutableMap.of(
"emailAddress",
new UserData(
u.getEmailAddress(),
"role",
u.getUserRoles().getRegistrarRoles().get(registrarId)))
u.getUserRoles().getRegistrarRoles().get(registrarId).toString(),
null))
.collect(Collectors.toList());
consoleApiParams.response().setPayload(gson.toJson(users));
@@ -136,22 +149,10 @@ public class ConsoleUsersAction extends ConsoleApiAction {
}
private void runDeleteInTransaction() throws IOException {
if (userDeleteData.isEmpty() || isNullOrEmpty(userDeleteData.get().userEmail)) {
throw new BadRequestException("Missing user data param");
}
String email = userDeleteData.get().userEmail;
User userToDelete =
tm().loadByKeyIfPresent(VKey.create(User.class, email))
.orElseThrow(
() -> new BadRequestException(String.format("User %s doesn't exist", email)));
if (!userToDelete.getUserRoles().getRegistrarRoles().containsKey(registrarId)) {
setFailedResponse(
String.format("Can't delete user not associated with registrarId %s", registrarId),
SC_FORBIDDEN);
if (!isModifyingRequestValid()) {
return;
}
String email = this.userData.get().emailAddress;
try {
directory.users().delete(email).execute();
} catch (IOException e) {
@@ -213,13 +214,50 @@ public class ConsoleUsersAction extends ConsoleApiAction {
.response()
.setPayload(
gson.toJson(
ImmutableMap.of(
"password",
newUser.getPassword(),
"emailAddress",
newUser.getPrimaryEmail(),
"role",
ACCOUNT_MANAGER)));
new UserData(
newUser.getPrimaryEmail(), ACCOUNT_MANAGER.toString(), newUser.getPassword())));
}
private void runUpdateInTransaction() {
if (!isModifyingRequestValid()) {
return;
}
UserData userData = this.userData.get();
UserRoles userRoles =
new UserRoles.Builder()
.setRegistrarRoles(ImmutableMap.of(registrarId, RegistrarRole.valueOf(userData.role)))
.build();
User updatedUser =
tm().loadByKeyIfPresent(VKey.create(User.class, userData.emailAddress))
.get()
.asBuilder()
.setUserRoles(userRoles)
.build();
tm().put(updatedUser);
consoleApiParams.response().setStatus(SC_OK);
}
private boolean isModifyingRequestValid() {
if (userData.isEmpty()
|| isNullOrEmpty(userData.get().emailAddress)
|| isNullOrEmpty(userData.get().role)) {
throw new BadRequestException("User data is missing or incomplete");
}
String email = userData.get().emailAddress;
User userToUpdate =
tm().loadByKeyIfPresent(VKey.create(User.class, email))
.orElseThrow(
() -> new BadRequestException(String.format("User %s doesn't exist", email)));
if (!userToUpdate.getUserRoles().getRegistrarRoles().containsKey(registrarId)) {
setFailedResponse(
String.format("Can't update user not associated with registrarId %s", registrarId),
SC_FORBIDDEN);
return false;
}
return true;
}
private ImmutableList<User> getAllRegistrarUsers(String registrarId) {
@@ -230,5 +268,6 @@ public class ConsoleUsersAction extends ConsoleApiAction {
.collect(toImmutableList()));
}
public record UserDeleteData(@Expose String userEmail) {}
public record UserData(
@Expose String emailAddress, @Expose String role, @Expose @Nullable String password) {}
}