Skip to content

Commit

Permalink
Deactivate/update user
Browse files Browse the repository at this point in the history
  • Loading branch information
alainbodiguel committed May 3, 2024
1 parent 3e97c0c commit b3f826b
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public interface AuthService {
User resetUserPassword(UUID userId, String resetToken, String password) throws SendEmailException, NotFoundException;

Optional<User> readUser(UUID userId);
User updateUser(User user, String oldPassword, String newPassword) throws NonMatchingPasswordException;
User updateUser(User user, String oldPassword, String newPassword, String firstName, String lastName, String locale, String timezone) throws NonMatchingPasswordException;
void deleteUser(UUID userId) throws NotAllowedException;

Optional<User> activateUser(UUID userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ public void initDatabase() {
admin.setLocale(initConf.locale);
admin.setTimezone(initConf.timezone);
admin.setVerified(true);
admin.setActive(true);
admin = userDao.createUser(admin);
admin.setRoles(importDefaultAdminRole(admin));
} else {
Expand Down Expand Up @@ -265,7 +266,7 @@ public Optional<User> readUser(UUID userId) {
@Override
public User readUser(UUID userId, boolean checkActiveVerified) throws NotFoundException {
Optional<User> user = readUser(userId);
if (user.isPresent() && user.get().isVerified() && user.get().isActive()) {
if (user.isPresent() && user.get().isVerified() && (!checkActiveVerified || user.get().isActive())) {
return user.get();
} else {
throw new NotFoundException("User not found.");
Expand Down Expand Up @@ -393,14 +394,29 @@ public void deleteApiKey(User user, UUID ownerId, UUID oid, UUID apiKeyId) throw
}

@Override
public User updateUser(User user, String oldPassword, String newPassword)
public User updateUser(User user, String oldPassword, String newPassword, String firstName, String lastName, String locale, String timezone)
throws NonMatchingPasswordException {
if (matches(oldPassword, user.getPassword())) {
user.setPassword(encode(newPassword));
return userDao.updateUser(user);
} else {
throw new NonMatchingPasswordException("Old password does not match.");
if (oldPassword != null && newPassword != null) {
if (matches(oldPassword, user.getPassword())) {
user.setPassword(encode(newPassword));
} else {
throw new NonMatchingPasswordException("Old password does not match.");
}
}
if (firstName != null && !firstName.equals(user.getFirstName())) {
user.setFirstName(firstName);
}
if (lastName != null && !lastName.equals(user.getLastName())) {
user.setLastName(lastName);
}
if (locale != null && !locale.equals(user.getLocale())) {
user.setLocale(locale);
}
if (timezone != null && !timezone.equals(user.getTimezone())) {
user.setTimezone(timezone);
}

return userDao.updateUser(user);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
public class UpdateUserDef {
public String oldPassword;
public String newPassword;
public String locale;
public String timezone;
public String firstName;
public String lastName;

public UpdateUserDef(){}
}
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,72 @@ public Response readUser(
.build();
}

@Timed
@Path("users/{id}/activate")
@POST
@Produces(UTF8JSON)
@Consumes(UTF8JSON)
@Operation(
security = @SecurityRequirement(name = "JWT"),
summary = "Activate the given user"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "202", description = "Successful operation",
content = @Content(schema = @Schema(implementation = ArlasMessage.class))),
@ApiResponse(responseCode = "500", description = "Arlas Error.",
content = @Content(schema = @Schema(implementation = Error.class)))})

@UnitOfWork
public Response activateUser(
@Context UriInfo uriInfo,
@Context HttpHeaders headers,
@Context HttpServletRequest request,

@Parameter(name = "id", required = true)
@PathParam(value = "id") String id
) {
authService.activateUser(UUID.fromString(id));
logUAM(request, headers, "users", "activate-user-account");
return Response.accepted(uriInfo.getRequestUriBuilder().build())
.entity(new ArlasMessage("User activated."))
.type(MediaType.APPLICATION_JSON_TYPE)
.build();

}

@Timed
@Path("users/{id}/deactivate")
@POST
@Produces(UTF8JSON)
@Consumes(UTF8JSON)
@Operation(
security = @SecurityRequirement(name = "JWT"),
summary = "Deactivate the given user"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "202", description = "Successful operation",
content = @Content(schema = @Schema(implementation = ArlasMessage.class))),
@ApiResponse(responseCode = "500", description = "Arlas Error.",
content = @Content(schema = @Schema(implementation = Error.class)))})

@UnitOfWork
public Response deactivateUser(
@Context UriInfo uriInfo,
@Context HttpHeaders headers,
@Context HttpServletRequest request,

@Parameter(name = "id", required = true)
@PathParam(value = "id") String id
) throws NotAllowedException {
authService.deactivateUser(UUID.fromString(id));
logUAM(request, headers, "users", "deactivate-user-account");
return Response.accepted(uriInfo.getRequestUriBuilder().build())
.entity(new ArlasMessage("User deactivated."))
.type(MediaType.APPLICATION_JSON_TYPE)
.build();

}

@Timed
@Path("users/{id}")
@DELETE
Expand All @@ -538,8 +604,6 @@ public Response readUser(
@ApiResponses(value = {
@ApiResponse(responseCode = "202", description = "Successful operation",
content = @Content(schema = @Schema(implementation = ArlasMessage.class))),
@ApiResponse(responseCode = "400", description = "Non matching passwords.",
content = @Content(schema = @Schema(implementation = Error.class))),
@ApiResponse(responseCode = "500", description = "Arlas Error.",
content = @Content(schema = @Schema(implementation = Error.class)))})

Expand Down Expand Up @@ -569,7 +633,7 @@ public Response deleteUser(
@Consumes(UTF8JSON)
@Operation(
security = @SecurityRequirement(name = "JWT"),
summary = "Update the logged in user"
summary = "Update the given user (absent attribute - null - are not updated)."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Successful operation",
Expand All @@ -592,14 +656,15 @@ public Response updateUser(
@PathParam(value = "id") String id,

@Parameter(name = "updateDef", required = true)
@NotNull @Valid UpdateUserDef updateDef
@NotNull @Valid UpdateUserDef ud

) throws NotFoundException, NonMatchingPasswordException {
LOGGER.info(ud.toString());
Response response = Response.created(uriInfo.getRequestUriBuilder().build())
.entity(new UserData(authService.updateUser(getUser(headers, id), updateDef.oldPassword, updateDef.newPassword)))
.entity(new UserData(authService.updateUser(getUser(headers, id, false), ud.oldPassword, ud.newPassword, ud.firstName, ud.lastName, ud.locale, ud.timezone)))
.type(MediaType.APPLICATION_JSON_TYPE)
.build();
logUAM(request, headers, "users", "change-password");
logUAM(request, headers, "users", "update-user");
return response;
}

Expand Down Expand Up @@ -1979,7 +2044,11 @@ protected User getUser(HttpHeaders headers) throws NotFoundException {
}

protected User getUser(HttpHeaders headers, String id) throws NotFoundException {
checkLoggedInUser(headers, id);
return getUser(headers, id, true);
}

protected User getUser(HttpHeaders headers, String id, boolean checkSame) throws NotFoundException {
if (checkSame) { checkLoggedInUser(headers, id); }
return getUser(headers);
}

Expand Down
34 changes: 25 additions & 9 deletions arlas-iam-tests/src/test/java/io/arlas/iam/test/AuthEndpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ protected Response logout(String userId) {
.delete(arlasAppPath.concat("session"));
}

protected Response changePassword(String userId, String oldPassword, String password) {
protected Response changePassword(String actingId, String userId, String oldPassword, String password) {
return given()
.header(AUTH_HEADER, getToken(userId))
.header(AUTH_HEADER, getToken(actingId))
.contentType("application/json")
.pathParam("id", userId)
.body(String.format("""
Expand All @@ -116,6 +116,17 @@ protected Response changePassword(String userId, String oldPassword, String pass
.put(arlasAppPath.concat("users/{id}"));
}

protected Response updateUser(String userId, String firstName, String lastName, String locale, String timezone) {
return given()
.header(AUTH_HEADER, getToken(userId))
.contentType("application/json")
.pathParam("id", userId)
.body(String.format("""
{"firstName": "%s", "lastName": "%s", "locale": "%s", "timezone": "%s"}
""", firstName, lastName, locale, timezone))
.put(arlasAppPath.concat("users/{id}"));
}

protected String getToken(String userId) {
if (userId.equals(userId1)) {
return "bearer " + token1;
Expand All @@ -138,15 +149,20 @@ protected Response getUser(String actingId, String id) {
.get(arlasAppPath.concat("users/{id}"));
}

protected Response updateUser(String id, String p1, String p2) {
protected Response deactivateUser(String actingId, String targetId) {
return given()
.header(AUTH_HEADER, getToken(userId1))
.pathParam("id", id)
.body(String.format("""
{"oldPassword":"%s","newPassword":"%s"}
""", p1, p2))
.header(AUTH_HEADER, getToken(actingId))
.pathParam("id", targetId)
.contentType("application/json")
.put(arlasAppPath.concat("users/{id}"));
.post(arlasAppPath.concat("users/{id}/deactivate"));
}

protected Response activateUser(String actingId, String targetId) {
return given()
.header(AUTH_HEADER, getToken(actingId))
.pathParam("id", targetId)
.contentType("application/json")
.post(arlasAppPath.concat("users/{id}/activate"));
}

protected Response deleteUser(String actingId, String targetId) {
Expand Down
25 changes: 20 additions & 5 deletions arlas-iam-tests/src/test/java/io/arlas/iam/test/AuthITUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void test013LoginWithInvalidPassword() {

@Test
public void test015ChangePassword() {
changePassword(userId1, "secret", "newsecret").then().statusCode(201)
changePassword(userId1, userId1, "secret", "newsecret").then().statusCode(201)
.body("email", equalTo(USER1));

logout(USER1).then().statusCode(200);
Expand All @@ -79,12 +79,17 @@ public void test015ChangePassword() {

@Test
public void test016ChangeWrongPassword() {
changePassword(userId1, "othersecret", "newsecret").then().statusCode(400);
changePassword(userId1, userId1, "othersecret", "newsecret").then().statusCode(400);
}

@Test
public void test017ChangePasswordOtherUser() {
updateUser(userId2, "password2", "newpassword2").then().statusCode(404);
public void test018UpdateUser() {
updateUser(userId1, "John", "Doe", "fr_FR", "Europe/London").then().statusCode(201)
.body("firstName", equalTo("John"))
.body("lastName", equalTo("Doe"))
.body("locale", equalTo("fr_FR"))
.body("timezone", equalTo("Europe/London"))
;
}

// @Test
Expand Down Expand Up @@ -465,7 +470,17 @@ public void test903DeleteUserNotSelf() {
}

@Test
public void test904DeleteUserSelf() {
public void test904DeactivateUser() {
deactivateUser(userId1, userId2).then().statusCode(202);
}

@Test
public void test905ActivateUser() {
activateUser(userId1, userId2).then().statusCode(202);
}

@Test
public void test906DeleteUserSelf() {
deleteUser(userId1, userId1).then().statusCode(202);
deleteUser(userId2, userId2).then().statusCode(202);
}
Expand Down

0 comments on commit b3f826b

Please sign in to comment.