diff --git a/console-webapp/src/app/shared/services/backend.service.ts b/console-webapp/src/app/shared/services/backend.service.ts index a655c423ffd..c34f2582a65 100644 --- a/console-webapp/src/app/shared/services/backend.service.ts +++ b/console-webapp/src/app/shared/services/backend.service.ts @@ -172,14 +172,20 @@ export class BackendService { .pipe(catchError((err) => this.errorCatcher(err))); } - deleteUser(registrarId: string, emailAddress: string): Observable { + deleteUser(registrarId: string, user: User): Observable { return this.http .delete(`/console-api/users?registrarId=${registrarId}`, { - body: JSON.stringify({ emailAddress }), + body: JSON.stringify(user), }) .pipe(catchError((err) => this.errorCatcher(err))); } + updateUser(registrarId: string, updatedUser: User): Observable { + return this.http + .put(`/console-api/users?registrarId=${registrarId}`, updatedUser) + .pipe(catchError((err) => this.errorCatcher(err))); + } + getUserData(): Observable { return this.http .get('/console-api/userdata') diff --git a/console-webapp/src/app/users/userEdit.component.html b/console-webapp/src/app/users/userEdit.component.html index aa9e24e9de9..79cd61e1c80 100644 --- a/console-webapp/src/app/users/userEdit.component.html +++ b/console-webapp/src/app/users/userEdit.component.html @@ -1,32 +1,77 @@
- @if(isNewUser) { + @if(isEditing) { +

Editing {{ userDetails().emailAddress }}

+ +
+ +
+
+

+ + User Role: + help_outline + + Editor + Viewer + + +

+ +
+ } @else { @if(isNewUser) {

- {{ userDetails.emailAddress + " succesfully created" }} + {{ userDetails().emailAddress + " successfully created" }}

} @else {

User details

- } -
-
- -
- -
+
+ +
+ +
+
+ priority_high + Please save the password. For your security, we do not store passwords in a + recoverable format. +
+

@@ -41,17 +86,17 @@

User details

User email {{ - userDetails.emailAddress + userDetails().emailAddress }} User role {{ - roleToDescription(userDetails.role) + roleToDescription(userDetails().role) }} - @if (userDetails.password) { + @if (userDetails().password) { Password @@ -60,7 +105,7 @@

User details

>
diff --git a/console-webapp/src/app/users/userEdit.component.scss b/console-webapp/src/app/users/userEdit.component.scss index c24ece06ac0..6935e048338 100644 --- a/console-webapp/src/app/users/userEdit.component.scss +++ b/console-webapp/src/app/users/userEdit.component.scss @@ -25,6 +25,15 @@ background: transparent; } } + &-save-password { + display: flex; + justify-content: center; + align-items: center; + padding: 15px 10px; + margin-bottom: 20px; + border: 1px solid #ddd; + border-radius: 10px; + } max-width: 616px; } } diff --git a/console-webapp/src/app/users/userEdit.component.ts b/console-webapp/src/app/users/userEdit.component.ts index 19490dafefa..9c84cd17801 100644 --- a/console-webapp/src/app/users/userEdit.component.ts +++ b/console-webapp/src/app/users/userEdit.component.ts @@ -13,13 +13,14 @@ // limitations under the License. import { CommonModule } from '@angular/common'; -import { Component } from '@angular/core'; +import { Component, computed } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { SelectedRegistrarModule } from '../app.module'; import { MaterialModule } from '../material.module'; import { RegistrarService } from '../registrar/registrar.service'; import { SnackBarModule } from '../snackbar.module'; import { User, UsersService, roleToDescription } from './users.service'; +import { FormsModule } from '@angular/forms'; @Component({ selector: 'app-user-edit', @@ -27,6 +28,7 @@ import { User, UsersService, roleToDescription } from './users.service'; styleUrls: ['./userEdit.component.scss'], standalone: true, imports: [ + FormsModule, MaterialModule, SnackBarModule, CommonModule, @@ -35,22 +37,25 @@ import { User, UsersService, roleToDescription } from './users.service'; providers: [], }) export class UserEditComponent { - inEdit = false; + isEditing = false; isPasswordVisible = false; isNewUser = false; isLoading = false; - userDetails: User; + userRole = ''; + + userDetails = computed(() => { + return this.usersService + .users() + .filter( + (u) => u.emailAddress === this.usersService.currentlyOpenUserEmail() + )[0]; + }); constructor( protected registrarService: RegistrarService, protected usersService: UsersService, private _snackBar: MatSnackBar ) { - this.userDetails = this.usersService - .users() - .filter( - (u) => u.emailAddress === this.usersService.currentlyOpenUserEmail() - )[0]; if (this.usersService.isNewUser) { this.isNewUser = true; this.usersService.isNewUser = false; @@ -63,7 +68,7 @@ export class UserEditComponent { deleteUser() { this.isLoading = true; - this.usersService.deleteUser(this.userDetails.emailAddress).subscribe({ + this.usersService.deleteUser(this.userDetails()).subscribe({ error: (err) => { this._snackBar.open(err.error || err.message); this.isLoading = false; @@ -78,4 +83,23 @@ export class UserEditComponent { goBack() { this.usersService.currentlyOpenUserEmail.set(''); } + + saveEdit() { + this.isLoading = true; + this.usersService + .updateUser({ + role: this.userRole, + emailAddress: this.userDetails().emailAddress, + }) + .subscribe({ + error: (err) => { + this._snackBar.open(err.error || err.message); + this.isLoading = false; + }, + complete: () => { + this.isLoading = false; + this.isEditing = false; + }, + }); + } } diff --git a/console-webapp/src/app/users/users.service.ts b/console-webapp/src/app/users/users.service.ts index 87121006765..400be8a6f63 100644 --- a/console-webapp/src/app/users/users.service.ts +++ b/console-webapp/src/app/users/users.service.ts @@ -13,13 +13,13 @@ // limitations under the License. import { Injectable, signal } from '@angular/core'; -import { tap } from 'rxjs'; +import { switchMap, tap } from 'rxjs'; import { RegistrarService } from '../registrar/registrar.service'; import { BackendService } from '../shared/services/backend.service'; export const roleToDescription = (role: string) => { if (!role) return 'N/A'; - else if (role.toLowerCase().startsWith('account_manager')) { + else if (role === 'ACCOUNT_MANAGER') { return 'Viewer'; } return 'Editor'; @@ -68,9 +68,15 @@ export class UsersService { ); } - deleteUser(emailAddress: string) { + deleteUser(user: User) { return this.backendService - .deleteUser(this.registrarService.registrarId(), emailAddress) - .pipe(tap((_) => this.fetchUsers())); + .deleteUser(this.registrarService.registrarId(), user) + .pipe(switchMap((_) => this.fetchUsers())); + } + + updateUser(updatedUser: User) { + return this.backendService + .updateUser(this.registrarService.registrarId(), updatedUser) + .pipe(switchMap((_) => this.fetchUsers())); } } diff --git a/core/src/main/java/google/registry/request/Action.java b/core/src/main/java/google/registry/request/Action.java index 30dab90c8d6..2a2a75418fc 100644 --- a/core/src/main/java/google/registry/request/Action.java +++ b/core/src/main/java/google/registry/request/Action.java @@ -34,6 +34,7 @@ enum Method { GET, HEAD, POST, + PUT, DELETE } diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java index 05fe9553c39..8ac5e94a9e1 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java @@ -20,6 +20,7 @@ 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 final void run() { 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 @@ protected void postHandler(User user) { 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"); } diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleModule.java b/core/src/main/java/google/registry/ui/server/console/ConsoleModule.java index 4f19e1843fd..737de470e74 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleModule.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleModule.java @@ -36,7 +36,7 @@ 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 static Optional provideEppPasswordChangeRequest( } @Provides - @Parameter("userDeleteData") - public static Optional provideUserDeleteData( + @Parameter("userData") + public static Optional provideUserData( Gson gson, @OptionalJsonPayload Optional payload) { - return payload.map(s -> gson.fromJson(s, UserDeleteData.class)); + return payload.map(s -> gson.fromJson(s, UserData.class)); } @Provides diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleUsersAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleUsersAction.java index 7dbc94f42b2..e4ff38dcd84 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleUsersAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleUsersAction.java @@ -21,6 +21,7 @@ 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.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.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 @@ 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; + private final Optional userData; private final Optional maybeGroupEmailAddress; private final IamClient iamClient; private final String gSuiteDomainName; @@ -82,14 +85,14 @@ public ConsoleUsersAction( @Config("gSuiteDomainName") String gSuiteDomainName, @Config("gSuiteConsoleUserGroupEmailAddress") Optional maybeGroupEmailAddress, @Named("base58StringGenerator") StringGenerator passwordGenerator, - @Parameter("userDeleteData") Optional userDeleteData, + @Parameter("userData") Optional 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 @@ protected void postHandler(User user) { } } + @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 users = + List 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 @@ protected void deleteHandler(User user) { } 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 @@ private void runCreateInTransaction() throws IOException { .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 getAllRegistrarUsers(String registrarId) { @@ -230,5 +268,6 @@ private ImmutableList getAllRegistrarUsers(String registrarId) { .collect(toImmutableList())); } - public record UserDeleteData(@Expose String userEmail) {} + public record UserData( + @Expose String emailAddress, @Expose String role, @Expose @Nullable String password) {} } diff --git a/core/src/test/java/google/registry/ui/server/console/ConsoleUsersActionTest.java b/core/src/test/java/google/registry/ui/server/console/ConsoleUsersActionTest.java index 8195fe859de..811b12bddda 100644 --- a/core/src/test/java/google/registry/ui/server/console/ConsoleUsersActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/ConsoleUsersActionTest.java @@ -44,7 +44,7 @@ import google.registry.testing.DeterministicStringGenerator; import google.registry.testing.FakeResponse; import google.registry.tools.IamClient; -import google.registry.ui.server.console.ConsoleUsersAction.UserDeleteData; +import google.registry.ui.server.console.ConsoleUsersAction.UserData; import google.registry.util.StringGenerator; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @@ -176,7 +176,7 @@ void testSuccess_createsUser() throws IOException { assertThat(response.getStatus()).isEqualTo(SC_CREATED); assertThat(response.getPayload()) .contains( - "{\"password\":\"abcdefghijklmnop\",\"emailAddress\":\"TheRegistrar-user1@email.com\",\"role\":\"ACCOUNT_MANAGER\"}"); + "{\"emailAddress\":\"TheRegistrar-user1@email.com\",\"role\":\"ACCOUNT_MANAGER\",\"password\":\"abcdefghijklmnop\"}"); } @Test @@ -192,14 +192,15 @@ void testFailure_noPermissionToDeleteUser() throws IOException { createAction( Optional.of(ConsoleApiParamsUtils.createFake(authResult)), Optional.of("DELETE"), - Optional.of(new UserDeleteData("test3@test.com"))); + Optional.of( + new UserData("test3@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null))); when(directory.users()).thenReturn(users); when(users.delete(any(String.class))).thenReturn(delete); action.run(); var response = ((FakeResponse) consoleApiParams.response()); assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN); assertThat(response.getPayload()) - .contains("Can't delete user not associated with registrarId TheRegistrar"); + .contains("Can't update user not associated with registrarId TheRegistrar"); } @Test @@ -210,7 +211,8 @@ void testFailure_userDoesntExist() throws IOException { createAction( Optional.of(ConsoleApiParamsUtils.createFake(authResult)), Optional.of("DELETE"), - Optional.of(new UserDeleteData("email-1@email.com"))); + Optional.of( + new UserData("email-1@email.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null))); when(directory.users()).thenReturn(users); when(users.delete(any(String.class))).thenReturn(delete); action.run(); @@ -232,7 +234,8 @@ void testSuccess_deletesUser() throws IOException { createAction( Optional.of(ConsoleApiParamsUtils.createFake(authResult)), Optional.of("DELETE"), - Optional.of(new UserDeleteData("test2@test.com"))); + Optional.of( + new UserData("test2@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null))); action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils(); when(directory.users()).thenReturn(users); when(users.delete(any(String.class))).thenReturn(delete); @@ -282,10 +285,66 @@ void testFailure_limitedTo4UsersPerRegistrar() throws IOException { assertThat(response.getPayload()).contains("Total users amount per registrar is limited to 4"); } + @Test + void testSuccess_updatesUserRole() 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()); + + assertThat( + DatabaseHelper.loadByKey(VKey.create(User.class, "test2@test.com")) + .getUserRoles() + .getRegistrarRoles() + .get("TheRegistrar")) + .isEqualTo(RegistrarRole.PRIMARY_CONTACT); + ConsoleUsersAction action = + createAction( + Optional.of(ConsoleApiParamsUtils.createFake(authResult)), + Optional.of("PUT"), + Optional.of( + new UserData("test2@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null))); + action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils(); + action.run(); + var response = ((FakeResponse) consoleApiParams.response()); + assertThat(response.getStatus()).isEqualTo(SC_OK); + assertThat( + DatabaseHelper.loadByKey(VKey.create(User.class, "test2@test.com")) + .getUserRoles() + .getRegistrarRoles() + .get("TheRegistrar")) + .isEqualTo(RegistrarRole.ACCOUNT_MANAGER); + } + + @Test + void testFailure_noPermissionToUpdateUser() 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()); + ConsoleUsersAction action = + createAction( + Optional.of(ConsoleApiParamsUtils.createFake(authResult)), + Optional.of("PUT"), + Optional.of( + new UserData("test3@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null))); + action.run(); + var response = ((FakeResponse) consoleApiParams.response()); + assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN); + assertThat(response.getPayload()) + .contains("Can't update user not associated with registrarId TheRegistrar"); + } + private ConsoleUsersAction createAction( Optional maybeConsoleApiParams, Optional method, - Optional userDeleteData) + Optional userData) throws IOException { consoleApiParams = maybeConsoleApiParams.orElseGet( @@ -299,7 +358,7 @@ private ConsoleUsersAction createAction( "email.com", Optional.of("someRandomString"), passwordGenerator, - userDeleteData, + userData, "TheRegistrar"); } } diff --git a/core/src/test/resources/google/registry/module/frontend/frontend_routing.txt b/core/src/test/resources/google/registry/module/frontend/frontend_routing.txt index d7f98a8d0fb..5c86f9d013b 100644 --- a/core/src/test/resources/google/registry/module/frontend/frontend_routing.txt +++ b/core/src/test/resources/google/registry/module/frontend/frontend_routing.txt @@ -1,16 +1,16 @@ -SERVICE PATH CLASS METHODS OK MIN USER_POLICY -FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN -CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC -CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC -CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC -CONSOLE /console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC -CONSOLE /console-api/ote ConsoleOteAction GET,POST n USER PUBLIC -CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC -CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC -CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC -CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC -CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC -CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC -CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC -CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC -CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE n USER PUBLIC \ No newline at end of file +SERVICE PATH CLASS METHODS OK MIN USER_POLICY +FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN +CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC +CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC +CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC +CONSOLE /console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC +CONSOLE /console-api/ote ConsoleOteAction GET,POST n USER PUBLIC +CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC +CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC +CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC +CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC +CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC +CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC +CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC +CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC +CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC \ No newline at end of file diff --git a/core/src/test/resources/google/registry/module/routing.txt b/core/src/test/resources/google/registry/module/routing.txt index 6c33545a681..053dab0e91f 100644 --- a/core/src/test/resources/google/registry/module/routing.txt +++ b/core/src/test/resources/google/registry/module/routing.txt @@ -1,82 +1,82 @@ -SERVICE PATH CLASS METHODS OK MIN USER_POLICY -FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN -BACKEND /_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN -BACKEND /_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN -BACKEND /_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN -BACKEND /_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n APP ADMIN -BACKEND /_dr/admin/list/registrars ListRegistrarsAction GET,POST n APP ADMIN -BACKEND /_dr/admin/list/reservedLists ListReservedListsAction GET,POST n APP ADMIN -BACKEND /_dr/admin/list/tlds ListTldsAction GET,POST n APP ADMIN -BACKEND /_dr/admin/updateUserGroup UpdateUserGroupAction POST n APP ADMIN -BACKEND /_dr/admin/verifyOte VerifyOteAction POST n APP ADMIN -BACKEND /_dr/cron/fanout TldFanoutAction GET y APP ADMIN -BACKEND /_dr/epptool EppToolAction POST n APP ADMIN -BACKEND /_dr/loadtest LoadTestAction POST y APP ADMIN -BACKEND /_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN -BACKEND /_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN -BACKEND /_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN -BACKEND /_dr/task/bsaValidate BsaValidateAction GET,POST n APP ADMIN -BACKEND /_dr/task/copyDetailReports CopyDetailReportsAction POST n APP ADMIN -BACKEND /_dr/task/deleteExpiredDomains DeleteExpiredDomainsAction GET n APP ADMIN -BACKEND /_dr/task/deleteLoadTestData DeleteLoadTestDataAction POST n APP ADMIN -BACKEND /_dr/task/deleteProberData DeleteProberDataAction POST n APP ADMIN -BACKEND /_dr/task/dnsRefresh RefreshDnsAction GET y APP ADMIN -BACKEND /_dr/task/executeCannedScript CannedScriptExecutionAction POST,GET y APP ADMIN -BACKEND /_dr/task/expandBillingRecurrences ExpandBillingRecurrencesAction GET n APP ADMIN -BACKEND /_dr/task/exportDomainLists ExportDomainListsAction POST n APP ADMIN -BACKEND /_dr/task/exportPremiumTerms ExportPremiumTermsAction POST n APP ADMIN -BACKEND /_dr/task/exportReservedTerms ExportReservedTermsAction POST n APP ADMIN -BACKEND /_dr/task/generateInvoices GenerateInvoicesAction POST n APP ADMIN -BACKEND /_dr/task/generateSpec11 GenerateSpec11ReportAction POST n APP ADMIN -BACKEND /_dr/task/generateZoneFiles GenerateZoneFilesAction POST n APP ADMIN -BACKEND /_dr/task/icannReportingStaging IcannReportingStagingAction POST n APP ADMIN -BACKEND /_dr/task/icannReportingUpload IcannReportingUploadAction POST n APP ADMIN -BACKEND /_dr/task/nordnUpload NordnUploadAction POST y APP ADMIN -BACKEND /_dr/task/nordnVerify NordnVerifyAction POST y APP ADMIN -BACKEND /_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y APP ADMIN -BACKEND /_dr/task/publishInvoices PublishInvoicesAction POST n APP ADMIN -BACKEND /_dr/task/publishSpec11 PublishSpec11ReportAction POST n APP ADMIN -BACKEND /_dr/task/rdeReport RdeReportAction POST n APP ADMIN -BACKEND /_dr/task/rdeStaging RdeStagingAction GET,POST n APP ADMIN -BACKEND /_dr/task/rdeUpload RdeUploadAction POST n APP ADMIN -BACKEND /_dr/task/readDnsRefreshRequests ReadDnsRefreshRequestsAction POST y APP ADMIN -BACKEND /_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN -BACKEND /_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN -BACKEND /_dr/task/relockDomain RelockDomainAction POST y APP ADMIN -BACKEND /_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN -BACKEND /_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN -BACKEND /_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN -BACKEND /_dr/task/syncGroupMembers SyncGroupMembersAction POST n APP ADMIN -BACKEND /_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n APP ADMIN -BACKEND /_dr/task/tmchCrl TmchCrlAction POST y APP ADMIN -BACKEND /_dr/task/tmchDnl TmchDnlAction POST y APP ADMIN -BACKEND /_dr/task/tmchSmdrl TmchSmdrlAction POST y APP ADMIN -BACKEND /_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN -BACKEND /_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN -BACKEND /_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN -PUBAPI /_dr/whois WhoisAction POST n APP ADMIN -PUBAPI /check CheckApiAction GET n NONE PUBLIC -PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/entities RdapEntitySearchAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/entity/(*) RdapEntityAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC -PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC -PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC -CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC -CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC -CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC -CONSOLE /console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC -CONSOLE /console-api/ote ConsoleOteAction GET,POST n USER PUBLIC -CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC -CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC -CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC -CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC -CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC -CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC -CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC -CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC -CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE n USER PUBLIC \ No newline at end of file +SERVICE PATH CLASS METHODS OK MIN USER_POLICY +FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN +BACKEND /_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN +BACKEND /_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN +BACKEND /_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN +BACKEND /_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n APP ADMIN +BACKEND /_dr/admin/list/registrars ListRegistrarsAction GET,POST n APP ADMIN +BACKEND /_dr/admin/list/reservedLists ListReservedListsAction GET,POST n APP ADMIN +BACKEND /_dr/admin/list/tlds ListTldsAction GET,POST n APP ADMIN +BACKEND /_dr/admin/updateUserGroup UpdateUserGroupAction POST n APP ADMIN +BACKEND /_dr/admin/verifyOte VerifyOteAction POST n APP ADMIN +BACKEND /_dr/cron/fanout TldFanoutAction GET y APP ADMIN +BACKEND /_dr/epptool EppToolAction POST n APP ADMIN +BACKEND /_dr/loadtest LoadTestAction POST y APP ADMIN +BACKEND /_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN +BACKEND /_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN +BACKEND /_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN +BACKEND /_dr/task/bsaValidate BsaValidateAction GET,POST n APP ADMIN +BACKEND /_dr/task/copyDetailReports CopyDetailReportsAction POST n APP ADMIN +BACKEND /_dr/task/deleteExpiredDomains DeleteExpiredDomainsAction GET n APP ADMIN +BACKEND /_dr/task/deleteLoadTestData DeleteLoadTestDataAction POST n APP ADMIN +BACKEND /_dr/task/deleteProberData DeleteProberDataAction POST n APP ADMIN +BACKEND /_dr/task/dnsRefresh RefreshDnsAction GET y APP ADMIN +BACKEND /_dr/task/executeCannedScript CannedScriptExecutionAction POST,GET y APP ADMIN +BACKEND /_dr/task/expandBillingRecurrences ExpandBillingRecurrencesAction GET n APP ADMIN +BACKEND /_dr/task/exportDomainLists ExportDomainListsAction POST n APP ADMIN +BACKEND /_dr/task/exportPremiumTerms ExportPremiumTermsAction POST n APP ADMIN +BACKEND /_dr/task/exportReservedTerms ExportReservedTermsAction POST n APP ADMIN +BACKEND /_dr/task/generateInvoices GenerateInvoicesAction POST n APP ADMIN +BACKEND /_dr/task/generateSpec11 GenerateSpec11ReportAction POST n APP ADMIN +BACKEND /_dr/task/generateZoneFiles GenerateZoneFilesAction POST n APP ADMIN +BACKEND /_dr/task/icannReportingStaging IcannReportingStagingAction POST n APP ADMIN +BACKEND /_dr/task/icannReportingUpload IcannReportingUploadAction POST n APP ADMIN +BACKEND /_dr/task/nordnUpload NordnUploadAction POST y APP ADMIN +BACKEND /_dr/task/nordnVerify NordnVerifyAction POST y APP ADMIN +BACKEND /_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y APP ADMIN +BACKEND /_dr/task/publishInvoices PublishInvoicesAction POST n APP ADMIN +BACKEND /_dr/task/publishSpec11 PublishSpec11ReportAction POST n APP ADMIN +BACKEND /_dr/task/rdeReport RdeReportAction POST n APP ADMIN +BACKEND /_dr/task/rdeStaging RdeStagingAction GET,POST n APP ADMIN +BACKEND /_dr/task/rdeUpload RdeUploadAction POST n APP ADMIN +BACKEND /_dr/task/readDnsRefreshRequests ReadDnsRefreshRequestsAction POST y APP ADMIN +BACKEND /_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN +BACKEND /_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN +BACKEND /_dr/task/relockDomain RelockDomainAction POST y APP ADMIN +BACKEND /_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN +BACKEND /_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN +BACKEND /_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN +BACKEND /_dr/task/syncGroupMembers SyncGroupMembersAction POST n APP ADMIN +BACKEND /_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n APP ADMIN +BACKEND /_dr/task/tmchCrl TmchCrlAction POST y APP ADMIN +BACKEND /_dr/task/tmchDnl TmchDnlAction POST y APP ADMIN +BACKEND /_dr/task/tmchSmdrl TmchSmdrlAction POST y APP ADMIN +BACKEND /_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN +BACKEND /_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN +BACKEND /_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN +PUBAPI /_dr/whois WhoisAction POST n APP ADMIN +PUBAPI /check CheckApiAction GET n NONE PUBLIC +PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/entities RdapEntitySearchAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/entity/(*) RdapEntityAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC +PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC +PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC +CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC +CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC +CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC +CONSOLE /console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC +CONSOLE /console-api/ote ConsoleOteAction GET,POST n USER PUBLIC +CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC +CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC +CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC +CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC +CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC +CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC +CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC +CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC +CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC \ No newline at end of file