From 2122f9b139db7ca8127a658599055b840707e104 Mon Sep 17 00:00:00 2001 From: Isaries Date: Mon, 6 Jul 2026 21:49:17 +0800 Subject: [PATCH] fix(security): require authentication for the credential check endpoint The endpoint that verifies a username and password was reachable without authentication and returned the account's id and real name for any valid username, letting an anonymous caller brute-force passwords and harvest user ids and real names by probing usernames. Require an authenticated user, and only return the account id and name after the correct password has been supplied. The team sign-in flow, the only caller, already runs in an authenticated session and reads those fields only after a successful check. --- .../web/controllers/user/UserAPIController.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java index ca965b81f..8e1b52f53 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java @@ -179,6 +179,7 @@ private boolean isGoogleClassroomEnabled() { return !googleClientId.isEmpty() && !googleClientSecret.isEmpty(); } + @Secured("ROLE_USER") @PostMapping("/check-authentication") HashMap checkAuthentication(@RequestParam("username") String username, @RequestParam("password") String password) { @@ -188,12 +189,18 @@ HashMap checkAuthentication(@RequestParam("username") String use response.put("isUsernameValid", false); response.put("isPasswordValid", false); } else { + boolean isPasswordValid = userService.isPasswordCorrect(user, password); response.put("isUsernameValid", true); - response.put("isPasswordValid", userService.isPasswordCorrect(user, password)); - response.put("userId", user.getId()); - response.put("username", user.getUserDetails().getUsername()); - response.put("firstName", user.getUserDetails().getFirstname()); - response.put("lastName", user.getUserDetails().getLastname()); + response.put("isPasswordValid", isPasswordValid); + // Only reveal the account id and real name once the correct password has been + // provided, so this endpoint cannot be used to harvest user ids and real names + // by probing usernames. + if (isPasswordValid) { + response.put("userId", user.getId()); + response.put("username", user.getUserDetails().getUsername()); + response.put("firstName", user.getUserDetails().getFirstname()); + response.put("lastName", user.getUserDetails().getLastname()); + } } return response; }