Class PasswordChangeHandler
POST /api/v2/auth/password.
Changes the current user's password. The handler requires an active
session (401 auth_required otherwise) and the caller's
current_password — when blank the response is
400 invalid_request, when wrong the response is
401 auth_required. The new password is validated against the
system's password policy (SystemHelper#validatePassword), and the
actual store is delegated to UserService.changePassword(java.lang.String, java.lang.String).
Confirm-password mismatch and a blank new password both yield
400 invalid_request.
Request body shape:
{ "current_password": "...", "new_password": "...", "confirm_password": "..." }
All three fields are required. The current_password check follows the
same TypicalLoginAssist.findLoginUser(org.lastaflute.web.login.credential.LoginCredential) pattern used by
ProfileAction.changePassword.
C-3: although the caller is already authenticated, a stolen-session attacker
could otherwise brute-force current_password unbounded. The handler
therefore consults the LoginRateLimiter per-user bucket (same
configuration as /api/v2/auth/login): a LoginRateLimiter.peek(org.codelibs.fess.api.v2.handlers.LoginRateLimiter.Scope, java.lang.String, int, int)
gates entry, an LoginRateLimiter.allow(org.codelibs.fess.api.v2.handlers.LoginRateLimiter.Scope, java.lang.String, int, int) consumes a slot on wrong-password,
and LoginRateLimiter.clear(org.codelibs.fess.api.v2.handlers.LoginRateLimiter.Scope, java.lang.String) resets the bucket on success — mirroring
LoginHandler. When the user bucket is exhausted, the handler returns
429 rate_limited with a Retry-After header.
M-3 session contract: After a successful password change the current HTTP session
is invalidated (HttpSession.invalidate()) so any session token that was
exfiltrated before the change cannot be reused. The response includes
re_login_required: true so the SPA can redirect to the login page.
Note that csrf_token is NOT returned in the success response because the
session that held the old token has already been destroyed; the SPA must obtain a
fresh token after re-authenticating. Invalidating other concurrent sessions for the
same user is a follow-up item (requires a Fess-wide session registry, not available
in this release).
MJ-30 i18n contract: error.message values in this handler are
developer-facing English strings. Clients MUST use error.code
(the V2ErrorCode token) for user-facing i18n. Handlers also emit a stable
error.details.reason token (and min_length for
errors.password_length) so clients can localize the specific failure.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidhandle(jakarta.servlet.http.HttpServletRequest req, jakarta.servlet.http.HttpServletResponse res) Processes onePOST /api/v2/auth/passwordrequest.
-
Constructor Details
-
PasswordChangeHandler
public PasswordChangeHandler()Default constructor used by the DI container. The handler resolves the sharedLoginRateLimiterlazily so DI bootstrap order is not constrained. The handler holds no per-request state and is safe to share across concurrent requests.
-
-
Method Details
-
handle
public void handle(jakarta.servlet.http.HttpServletRequest req, jakarta.servlet.http.HttpServletResponse res) throws IOException Processes onePOST /api/v2/auth/passwordrequest.Requires an authenticated session, then re-verifies the supplied
current_passwordviaTypicalLoginAssist.findLoginUser(org.lastaflute.web.login.credential.LoginCredential)before updating the stored hash. On success the current HTTP session is invalidated (M-3) and the response includesre_login_required: true. Because the session is destroyed the response does not carry a rotated CSRF token; the SPA must obtain a fresh token after re-authenticating.- Parameters:
req- the incoming HTTP requestres- the HTTP response to write to- Throws:
IOException- if writing the envelope or reading the body fails
-