-
Notifications
You must be signed in to change notification settings - Fork 41
Feature/password validation fixes #226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit addresses 4 critical security issues in password management: **Fix #1: Add password validation to /updatePassword endpoint** - Added passwordPolicyService.validate() call before saving password - Prevents users from setting weak passwords when updating - Enforces all policy rules including history, similarity, and complexity **Fix #2: Implement missing /savePassword endpoint** - Created SavePasswordDto for password reset with token - Implemented complete /savePassword endpoint with full validation - Added deletePasswordResetToken method to UserService - Added message keys for password reset flow - Fixes incomplete password reset functionality **Fix #3: Document password history behavior** - Added JavaDoc explaining null user parameter during registration - Documented that history checks only apply to existing users - Added clarifying comments in registration endpoint **Fix #4: Add transaction isolation for password history cleanup** - Added @transactional(isolation = SERIALIZABLE) to cleanUpPasswordHistory - Prevents race conditions during concurrent password changes - Added comprehensive JavaDoc documentation **Additional improvements:** - Cascade delete configuration for PasswordHistoryEntry (from earlier work) - LAZY fetch type optimization on both sides of relationship - All existing tests pass (372 tests) See IMPLEMENTATION_PLAN_PASSWORD_FIXES.md for detailed analysis and implementation plan. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Updated DEMO_APP_CHANGES_REQUIRED.md to reflect that: - Password strength meter already exists on registration form - Can be extracted and reused on password reset and update forms - Reduced estimated effort from 2-4 hours to 1-2 hours 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request implements comprehensive security improvements to the password reset and update flows, addressing critical validation gaps and enforcing password policies consistently throughout the user authentication system. The changes introduce a new dedicated password reset endpoint, enhance password policy enforcement with history checking, improve database performance through optimized lazy loading, and provide clear documentation for required demo application updates.
Key Changes:
- Added
/user/savePasswordendpoint with full password policy validation and token management for the password reset flow - Enhanced password update endpoint to validate new passwords against policy rules including history checking
- Optimized password history relationship loading and added transaction isolation to prevent race conditions
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| SavePasswordDto.java | New DTO to support password reset flow with token and password fields |
| UserAPI.java | Added savePassword endpoint and enhanced updatePassword with policy validation |
| UserService.java | Added token deletion method and SERIALIZABLE isolation for history cleanup |
| PasswordPolicyService.java | Clarified documentation that history checks skip new user registrations |
| User.java | Added explicit LAZY-loaded password history relationship |
| PasswordHistoryEntry.java | Changed user relationship to LAZY loading for performance |
| dsspringusermessages.properties | Added password mismatch and reset success messages |
| IMPLEMENTATION_PLAN_PASSWORD_FIXES.md | Comprehensive implementation guide and testing strategy |
| DEMO_APP_CHANGES_REQUIRED.md | Documentation of required demo app form fixes |
Comments suppressed due to low confidence (1)
src/main/java/com/digitalsanctuary/spring/user/dto/SavePasswordDto.java:1
- The
@NotEmptyannotation already validates for null and empty strings, making@NotNullredundant. Consider removing@NotNullannotations or use@NotBlankwhich is more appropriate for trimming whitespace in string fields.
package com.digitalsanctuary.spring.user.dto;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| PasswordResetToken resetToken = passwordTokenRepository.findByToken(token); | ||
| if (resetToken != null) { | ||
| passwordTokenRepository.delete(resetToken); | ||
| log.debug("Deleted password reset token for user: {}", resetToken.getUser().getEmail()); | ||
| } |
Copilot
AI
Oct 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method fetches the entire PasswordResetToken entity just to delete it. Consider adding a deleteByToken(String token) method to the repository to execute a direct DELETE query, avoiding the unnecessary SELECT and reducing database roundtrips.
| PasswordResetToken resetToken = passwordTokenRepository.findByToken(token); | |
| if (resetToken != null) { | |
| passwordTokenRepository.delete(resetToken); | |
| log.debug("Deleted password reset token for user: {}", resetToken.getUser().getEmail()); | |
| } | |
| passwordTokenRepository.deleteByToken(token); | |
| log.debug("Deleted password reset token with token: {}", token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix.
…parison This commit addresses code review feedback from Copilot AI: **1. Clarify password comparison timing attack concern** - Added detailed comment explaining why equals() is safe for comparing two user-provided strings (newPassword vs confirmPassword) - Timing attacks only matter when comparing against stored secrets - Spring's PasswordEncoder already uses constant-time comparison for actual credential verification **2. Optimize password reset token deletion** - Added @Modifying query method deleteByToken() to PasswordResetTokenRepository - Uses direct DELETE query instead of SELECT + DELETE - Reduces database roundtrips from 2 to 1 - Updated UserService.deletePasswordResetToken() to use optimized method - Maintains logging while improving performance All tests pass (372 tests). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
This pull request introduces several important changes to improve password validation and security in the SpringUserFramework, especially around password reset and update flows. The main updates include adding a dedicated endpoint for saving new passwords after a reset, enforcing password policy and history checks, improving error handling and messaging, and enhancing the demo application's forms for better usability and consistency.
Key changes are grouped below:
Password Reset Flow Improvements
/user/savePasswordendpoint inUserAPI.javato handle saving a new password after a password reset token is validated. This endpoint checks for password match, validates the reset token, enforces password policy (including history and strength), saves the new password, and deletes the token after use.SavePasswordDtoas a new DTO to carry the token, new password, and confirmation password for the password reset flow.deletePasswordResetTokeninUserService.javato remove used tokens and prevent reuse.Password Policy and History Enforcement
Userentity explicit and set to LAZY loading. Also, changed the fetch type forPasswordHistoryEntry.userto LAZY for efficiency. [1] [2]@Transactional(isolation = Isolation.SERIALIZABLE)annotation tocleanUpPasswordHistoryto prevent race conditions when updating password history.Demo Application and User Experience
DEMO_APP_CHANGES_REQUIRED.md) outlining necessary changes in the demo app, including fixing the password reset form to use the correct endpoint and field names, and suggestions for reusing the password strength meter across all password-related forms.Error Handling and Messaging
dsspringusermessages.properties.References:
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]