From 7aa6df56cb56f36c22f88cbc215099cf0851d74f Mon Sep 17 00:00:00 2001 From: pfurio Date: Wed, 13 Nov 2024 13:01:21 +0100 Subject: [PATCH] server: move reset password WS, #TASK-7200 #TASK-7130 --- .../app/cli/main/OpenCgaCompleter.java | 2 +- .../app/cli/main/OpencgaCliOptionsParser.java | 1 + .../OrganizationsCommandExecutor.java | 14 ++++++++++++ .../options/OrganizationsCommandOptions.java | 19 ++++++++++++++++ .../cli/main/options/UsersCommandOptions.java | 2 +- .../catalog/managers/OrganizationManager.java | 20 +++++++++++++++++ .../opencga/catalog/managers/UserManager.java | 22 +------------------ .../src/main/R/R/Organization-methods.R | 7 ++++++ opencga-client/src/main/R/R/User-methods.R | 2 +- .../rest/clients/OrganizationClient.java | 12 ++++++++++ .../client/rest/clients/UserClient.java | 2 +- .../src/main/javascript/Organization.js | 9 ++++++++ opencga-client/src/main/javascript/User.js | 2 +- .../rest_clients/organization_client.py | 10 +++++++++ .../pyopencga/rest_clients/user_client.py | 2 +- .../server/rest/OrganizationWSServer.java | 14 ++++++++++++ .../opencga/server/rest/UserWSServer.java | 6 ++--- 17 files changed, 116 insertions(+), 30 deletions(-) diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpenCgaCompleter.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpenCgaCompleter.java index fa5b3482284..a9ed67a5f54 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpenCgaCompleter.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpenCgaCompleter.java @@ -89,7 +89,7 @@ public abstract class OpenCgaCompleter implements Completer { .map(Candidate::new) .collect(toList()); - private List organizationsList = asList( "create","notes-create","notes-search","notes-delete","notes-update","update-status-user","user-update","configuration-update","info","update") + private List organizationsList = asList( "create","notes-create","notes-search","notes-delete","notes-update","password-reset","update-status-user","user-update","configuration-update","info","update") .stream() .map(Candidate::new) .collect(toList()); diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpencgaCliOptionsParser.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpencgaCliOptionsParser.java index cfd4cee9919..dd11669a01a 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpencgaCliOptionsParser.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/OpencgaCliOptionsParser.java @@ -273,6 +273,7 @@ public OpencgaCliOptionsParser() { organizationsSubCommands.addCommand("notes-search", organizationsCommandOptions.searchNotesCommandOptions); organizationsSubCommands.addCommand("notes-delete", organizationsCommandOptions.deleteNotesCommandOptions); organizationsSubCommands.addCommand("notes-update", organizationsCommandOptions.updateNotesCommandOptions); + organizationsSubCommands.addCommand("password-reset", organizationsCommandOptions.resetPasswordCommandOptions); organizationsSubCommands.addCommand("update-status-user", organizationsCommandOptions.userUpdateStatusCommandOptions); organizationsSubCommands.addCommand("user-update", organizationsCommandOptions.updateUserCommandOptions); organizationsSubCommands.addCommand("configuration-update", organizationsCommandOptions.updateConfigurationCommandOptions); diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java index 1294b1397e7..e56f52bf3a4 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/OrganizationsCommandExecutor.java @@ -81,6 +81,9 @@ public void execute() throws Exception { case "notes-update": queryResponse = updateNotes(); break; + case "password-reset": + queryResponse = resetPassword(); + break; case "update-status-user": queryResponse = userUpdateStatus(); break; @@ -240,6 +243,17 @@ private RestResponse updateNotes() throws Exception { return openCGAClient.getOrganizationClient().updateNotes(commandOptions.id, noteUpdateParams, queryParams); } + private RestResponse resetPassword() throws Exception { + logger.debug("Executing resetPassword in Organizations command line"); + + OrganizationsCommandOptions.ResetPasswordCommandOptions commandOptions = organizationsCommandOptions.resetPasswordCommandOptions; + + ObjectMap queryParams = new ObjectMap(); + queryParams.putIfNotEmpty("userId", commandOptions.userId); + + return openCGAClient.getOrganizationClient().resetPassword(queryParams); + } + private RestResponse userUpdateStatus() throws Exception { logger.debug("Executing userUpdateStatus in Organizations command line"); diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java index 0f9f2a18c49..30667d0531e 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/OrganizationsCommandOptions.java @@ -38,6 +38,7 @@ public class OrganizationsCommandOptions { public SearchNotesCommandOptions searchNotesCommandOptions; public DeleteNotesCommandOptions deleteNotesCommandOptions; public UpdateNotesCommandOptions updateNotesCommandOptions; + public ResetPasswordCommandOptions resetPasswordCommandOptions; public UserUpdateStatusCommandOptions userUpdateStatusCommandOptions; public UpdateUserCommandOptions updateUserCommandOptions; public UpdateConfigurationCommandOptions updateConfigurationCommandOptions; @@ -54,6 +55,7 @@ public OrganizationsCommandOptions(CommonCommandOptions commonCommandOptions, JC this.searchNotesCommandOptions = new SearchNotesCommandOptions(); this.deleteNotesCommandOptions = new DeleteNotesCommandOptions(); this.updateNotesCommandOptions = new UpdateNotesCommandOptions(); + this.resetPasswordCommandOptions = new ResetPasswordCommandOptions(); this.userUpdateStatusCommandOptions = new UserUpdateStatusCommandOptions(); this.updateUserCommandOptions = new UpdateUserCommandOptions(); this.updateConfigurationCommandOptions = new UpdateConfigurationCommandOptions(); @@ -228,6 +230,23 @@ public class UpdateNotesCommandOptions { } + @Parameters(commandNames = {"password-reset"}, commandDescription ="Reset user's password") + public class ResetPasswordCommandOptions { + + @ParametersDelegate + public CommonCommandOptions commonOptions = commonCommandOptions; + + @Parameter(names = {"--json-file"}, description = "File with the body data in JSON format. Note, that using this parameter will ignore all the other parameters.", required = false, arity = 1) + public String jsonFile; + + @Parameter(names = {"--json-data-model"}, description = "Show example of file structure for body data.", help = true, arity = 0) + public Boolean jsonDataModel = false; + + @Parameter(names = {"--user-id"}, description = "User whose password needs to be reset", required = false, arity = 1) + public String userId; + + } + @Parameters(commandNames = {"update-status-user"}, commandDescription ="Update the user status") public class UserUpdateStatusCommandOptions { diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/UsersCommandOptions.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/UsersCommandOptions.java index 66d7cee55a8..0f213447747 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/UsersCommandOptions.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/UsersCommandOptions.java @@ -244,7 +244,7 @@ public class FiltersCommandOptions { } - @Parameters(commandNames = {"password-reset"}, commandDescription ="Reset password") + @Parameters(commandNames = {"password-reset"}, commandDescription ="[DEPRECATED]") public class ResetPasswordCommandOptions { @ParametersDelegate diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java index 20ec12a7f2b..b1e0d3e20d6 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/OrganizationManager.java @@ -292,6 +292,26 @@ public OpenCGAResult update(String organizationId, OrganizationUpd return result; } + public OpenCGAResult resetUserPassword(String userId, String token) throws CatalogException { + ParamUtils.checkParameter(userId, "userId"); + ParamUtils.checkParameter(token, "token"); + JwtPayload jwtPayload = catalogManager.getUserManager().validateToken(token); + String organizationId = jwtPayload.getOrganization(); + try { + authorizationManager.checkIsAtLeastOrganizationOwnerOrAdmin(organizationId, jwtPayload.getUserId()); + String authOrigin = catalogManager.getUserManager().getAuthenticationOriginId(organizationId, userId); + OpenCGAResult writeResult = authenticationFactory.resetPassword(organizationId, authOrigin, userId); + + auditManager.auditUser(organizationId, jwtPayload.getUserId(organizationId), Enums.Action.RESET_USER_PASSWORD, userId, + new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); + return writeResult; + } catch (CatalogException e) { + auditManager.auditUser(organizationId, jwtPayload.getUserId(organizationId), Enums.Action.RESET_USER_PASSWORD, userId, + new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); + throw e; + } + } + public OpenCGAResult updateUser(@Nullable String organizationId, String userId, OrganizationUserUpdateParams updateParams, QueryOptions options, String token) throws CatalogException { JwtPayload tokenPayload = catalogManager.getUserManager().validateToken(token); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java index 7e8e8cdffeb..3efcc935e8a 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/UserManager.java @@ -773,26 +773,6 @@ public OpenCGAResult restore(String ids, QueryOptions options, String sess throw new UnsupportedOperationException(); } - public OpenCGAResult resetPassword(String userId, String token) throws CatalogException { - ParamUtils.checkParameter(userId, "userId"); - ParamUtils.checkParameter(token, "token"); - JwtPayload jwtPayload = validateToken(token); - String organizationId = jwtPayload.getOrganization(); - try { - authorizationManager.checkIsAtLeastOrganizationOwnerOrAdmin(organizationId, jwtPayload.getUserId()); - String authOrigin = getAuthenticationOriginId(organizationId, userId); - OpenCGAResult writeResult = authenticationFactory.resetPassword(organizationId, authOrigin, userId); - - auditManager.auditUser(organizationId, jwtPayload.getUserId(organizationId), Enums.Action.RESET_USER_PASSWORD, userId, - new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); - return writeResult; - } catch (CatalogException e) { - auditManager.auditUser(organizationId, jwtPayload.getUserId(organizationId), Enums.Action.RESET_USER_PASSWORD, userId, - new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); - throw e; - } - } - public AuthenticationResponse loginAsAdmin(String password) throws CatalogException { return login(ParamConstants.ADMIN_ORGANIZATION, OPENCGA, password); } @@ -1533,7 +1513,7 @@ private void checkUserExists(String organizationId, String userId) throws Catalo } } - private String getAuthenticationOriginId(String organizationId, String userId) throws CatalogException { + String getAuthenticationOriginId(String organizationId, String userId) throws CatalogException { OpenCGAResult user = getUserDBAdaptor(organizationId).get(userId, new QueryOptions()); if (user == null || user.getNumResults() == 0) { throw new CatalogException(userId + " user not found"); diff --git a/opencga-client/src/main/R/R/Organization-methods.R b/opencga-client/src/main/R/R/Organization-methods.R index 14e44864ed9..e0e6a3b4dc6 100644 --- a/opencga-client/src/main/R/R/Organization-methods.R +++ b/opencga-client/src/main/R/R/Organization-methods.R @@ -24,6 +24,7 @@ #' | searchNotes | /{apiVersion}/organizations/notes/search | include, exclude, creationDate, modificationDate, id, scope, visibility, uuid, userId, tags, version | #' | deleteNotes | /{apiVersion}/organizations/notes/{id}/delete | id[*], includeResult | #' | updateNotes | /{apiVersion}/organizations/notes/{id}/update | include, exclude, id[*], tagsAction, includeResult, body[*] | +#' | resetPassword | /{apiVersion}/organizations/password/reset | userId | #' | userUpdateStatus | /{apiVersion}/organizations/user/{user}/status/update | include, exclude, user[*], organization, includeResult, body[*] | #' | updateUser | /{apiVersion}/organizations/user/{user}/update | include, exclude, user[*], organization, includeResult, body[*] | #' | updateConfiguration | /{apiVersion}/organizations/{organization}/configuration/update | include, exclude, organization[*], includeResult, authenticationOriginsAction, body[*] | @@ -91,6 +92,12 @@ setMethod("organizationClient", "OpencgaR", function(OpencgaR, id, organization, updateNotes=fetchOpenCGA(object=OpencgaR, category="organizations", categoryId=NULL, subcategory="notes", subcategoryId=id, action="update", params=params, httpMethod="POST", as.queryParam=NULL, ...), + #' @section Endpoint /{apiVersion}/organizations/password/reset: + #' Reset user's password. + #' @param userId User whose password needs to be reset. + resetPassword=fetchOpenCGA(object=OpencgaR, category="organizations", categoryId=NULL, subcategory="password", + subcategoryId=NULL, action="reset", params=params, httpMethod="POST", as.queryParam=NULL, ...), + #' @section Endpoint /{apiVersion}/organizations/user/{user}/status/update: #' Update the user status. #' @param include Fields included in the response, whole JSON path must be provided. diff --git a/opencga-client/src/main/R/R/User-methods.R b/opencga-client/src/main/R/R/User-methods.R index ffc1c599ca9..aa952fa0251 100644 --- a/opencga-client/src/main/R/R/User-methods.R +++ b/opencga-client/src/main/R/R/User-methods.R @@ -128,7 +128,7 @@ setMethod("userClient", "OpencgaR", function(OpencgaR, filterId, user, users, en subcategoryId=filterId, action="update", params=params, httpMethod="POST", as.queryParam=NULL, ...), #' @section Endpoint /{apiVersion}/users/{user}/password/reset: - #' Reset password. + #' [DEPRECATED]. #' @param user User ID. resetPassword=fetchOpenCGA(object=OpencgaR, category="users", categoryId=user, subcategory="password", subcategoryId=NULL, action="reset", params=params, httpMethod="GET", as.queryParam=NULL, ...), diff --git a/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/OrganizationClient.java b/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/OrganizationClient.java index b5d5a3b7fa1..173cbe9c160 100644 --- a/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/OrganizationClient.java +++ b/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/OrganizationClient.java @@ -139,6 +139,18 @@ public RestResponse updateNotes(String id, NoteUpdateParams data, ObjectMa return execute("organizations", null, "notes", id, "update", params, POST, Note.class); } + /** + * Reset user's password. + * @param params Map containing any of the following optional parameters. + * userId: User whose password needs to be reset. + * @return a RestResponse object. + * @throws ClientException ClientException if there is any server error. + */ + public RestResponse resetPassword(ObjectMap params) throws ClientException { + params = params != null ? params : new ObjectMap(); + return execute("organizations", null, "password", null, "reset", params, POST, ObjectMap.class); + } + /** * Update the user status. * @param user User ID. diff --git a/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/UserClient.java b/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/UserClient.java index ee290b40d21..7ae76be75bc 100644 --- a/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/UserClient.java +++ b/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/UserClient.java @@ -208,7 +208,7 @@ public RestResponse updateFilter(String user, String filterId, Filte } /** - * Reset password. + * [DEPRECATED]. * @param user User ID. * @return a RestResponse object. * @throws ClientException ClientException if there is any server error. diff --git a/opencga-client/src/main/javascript/Organization.js b/opencga-client/src/main/javascript/Organization.js index 09b79429246..20578fd04fe 100644 --- a/opencga-client/src/main/javascript/Organization.js +++ b/opencga-client/src/main/javascript/Organization.js @@ -107,6 +107,15 @@ export default class Organization extends OpenCGAParentClass { return this._post("organizations", null, "notes", id, "update", data, params); } + /** Reset user's password + * @param {Object} [params] - The Object containing the following optional parameters: + * @param {String} [params.userId] - User whose password needs to be reset. + * @returns {Promise} Promise object in the form of RestResponse instance. + */ + resetPassword(params) { + return this._post("organizations", null, "password", null, "reset", null, params); + } + /** Update the user status * @param {String} user - User ID. * @param {Object} data - JSON containing the User fields to be updated. diff --git a/opencga-client/src/main/javascript/User.js b/opencga-client/src/main/javascript/User.js index 32b28182c79..c1cdb7d195b 100644 --- a/opencga-client/src/main/javascript/User.js +++ b/opencga-client/src/main/javascript/User.js @@ -149,7 +149,7 @@ export default class User extends OpenCGAParentClass { return this._post("users", user, "filters", filterId, "update", data); } - /** Reset password + /** [DEPRECATED] * @param {String} user - User ID. * @returns {Promise} Promise object in the form of RestResponse instance. */ diff --git a/opencga-client/src/main/python/pyopencga/rest_clients/organization_client.py b/opencga-client/src/main/python/pyopencga/rest_clients/organization_client.py index 0d7dc0ff159..b24668f24c6 100644 --- a/opencga-client/src/main/python/pyopencga/rest_clients/organization_client.py +++ b/opencga-client/src/main/python/pyopencga/rest_clients/organization_client.py @@ -112,6 +112,16 @@ def update_notes(self, id, data=None, **options): return self._post(category='organizations', resource='update', subcategory='notes', second_query_id=id, data=data, **options) + def reset_password(self, **options): + """ + Reset user's password. + PATH: /{apiVersion}/organizations/password/reset + + :param str user_id: User whose password needs to be reset. + """ + + return self._post(category='organizations', resource='reset', subcategory='password', **options) + def user_update_status(self, user, data=None, **options): """ Update the user status. diff --git a/opencga-client/src/main/python/pyopencga/rest_clients/user_client.py b/opencga-client/src/main/python/pyopencga/rest_clients/user_client.py index 93451319d3d..4aad64fe2e6 100644 --- a/opencga-client/src/main/python/pyopencga/rest_clients/user_client.py +++ b/opencga-client/src/main/python/pyopencga/rest_clients/user_client.py @@ -165,7 +165,7 @@ def update_filter(self, user, filter_id, data=None, **options): def reset_password(self, user, **options): """ - Reset password. + [DEPRECATED]. PATH: /{apiVersion}/users/{user}/password/reset :param str user: User ID. (REQUIRED) diff --git a/opencga-server/src/main/java/org/opencb/opencga/server/rest/OrganizationWSServer.java b/opencga-server/src/main/java/org/opencb/opencga/server/rest/OrganizationWSServer.java index 73079cf2704..11ce7cecbc2 100644 --- a/opencga-server/src/main/java/org/opencb/opencga/server/rest/OrganizationWSServer.java +++ b/opencga-server/src/main/java/org/opencb/opencga/server/rest/OrganizationWSServer.java @@ -148,6 +148,20 @@ public Response create( } } + @POST + @Path("/password/reset") + @ApiOperation(value = "Reset user's password", + notes = "Reset the user's password and send a new random one to the e-mail stored in catalog.") + public Response resetPassword( + @ApiParam(value = "User whose password needs to be reset") @QueryParam("userId") String userId) { + try { + OpenCGAResult result = catalogManager.getOrganizationManager().resetUserPassword(userId, token); + return createOkResponse(result, "The new password has been sent to the user's email."); + } catch (Exception e) { + return createErrorResponse(e); + } + } + @GET @Path("/notes/search") @ApiOperation(value = "Search for notes of scope ORGANIZATION", response = Note.class) diff --git a/opencga-server/src/main/java/org/opencb/opencga/server/rest/UserWSServer.java b/opencga-server/src/main/java/org/opencb/opencga/server/rest/UserWSServer.java index 31fcd3a9720..122efee47f8 100644 --- a/opencga-server/src/main/java/org/opencb/opencga/server/rest/UserWSServer.java +++ b/opencga-server/src/main/java/org/opencb/opencga/server/rest/UserWSServer.java @@ -182,14 +182,14 @@ public Response changePassword( } } + @Deprecated @GET @Path("/{user}/password/reset") - @ApiOperation(value = "Reset password", hidden = false, - notes = "Reset the user's password and send a new random one to the e-mail stored in catalog.", response = User.class) + @ApiOperation(value = "[DEPRECATED]", notes = "[DEPRECATED] This WS has been moved to /organizations/password/reset.", response = User.class) public Response resetPassword( @ApiParam(value = ParamConstants.USER_DESCRIPTION, required = true) @PathParam("user") String userId) { try { - OpenCGAResult result = catalogManager.getUserManager().resetPassword(userId, token); + OpenCGAResult result = catalogManager.getOrganizationManager().resetUserPassword(userId, token); return createOkResponse(result, "The new password has been sent to the user's email."); } catch (Exception e) { return createErrorResponse(e);