Skip to content

Commit 7114ea9

Browse files
Copilotdevondragon
andcommitted
Phase 3: Add char[] overloads to PasswordPolicyService and UserService
Co-authored-by: devondragon <1254537+devondragon@users.noreply.github.com>
1 parent a51b684 commit 7114ea9

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

src/main/java/com/digitalsanctuary/spring/user/service/PasswordPolicyService.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,41 @@ public List<String> validate(User user, String password, String usernameOrEmail,
154154
return validateWithPassay(password, rules, locale);
155155
}
156156

157+
/**
158+
* Validate the given password (as char array) against the configured policy rules.
159+
* This is the preferred method for security as it allows explicit password clearing.
160+
*
161+
* <p>Note: The password char array is converted to String internally only when needed
162+
* for validation, and the String is not retained beyond the validation process.</p>
163+
*
164+
* <p>Note: The user parameter may be null during new user registration.
165+
* When null, password history checking is skipped (since new users have no history).
166+
* This is intentional - history checks only apply to existing users changing their passwords.</p>
167+
*
168+
* @param user The user (may be null for new registrations)
169+
* @param passwordChars the password as char array to validate
170+
* @param usernameOrEmail optional username/email for similarity checks
171+
* @param locale the locale
172+
* @return list of error messages if validation fails, empty if valid
173+
*/
174+
public List<String> validate(User user, char[] passwordChars, String usernameOrEmail, Locale locale) {
175+
if (passwordChars == null) {
176+
return List.of("Password cannot be null");
177+
}
178+
179+
// Convert to String for validation
180+
// Note: We need String for Passay library and password encoder
181+
String password = new String(passwordChars);
182+
try {
183+
return validate(user, password, usernameOrEmail, locale);
184+
} finally {
185+
// Clear the temporary String from memory (best effort)
186+
// Note: String is immutable so this won't actually clear the String,
187+
// but it helps signal intent and clears the reference
188+
password = null;
189+
}
190+
}
191+
157192
/**
158193
* Build the list of Passay rules based on configuration.
159194
*

src/main/java/com/digitalsanctuary/spring/user/service/UserService.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,28 @@ public void changeUserPassword(final User user, final String password) {
448448
savePasswordHistory(user, encodedPassword);
449449
}
450450

451+
/**
452+
* Change user password (char array version - preferred for security).
453+
* This method converts the char array to String for encoding and immediately clears it.
454+
*
455+
* @param user the user
456+
* @param passwordChars the password as char array
457+
*/
458+
public void changeUserPassword(final User user, final char[] passwordChars) {
459+
if (passwordChars == null) {
460+
throw new IllegalArgumentException("Password cannot be null");
461+
}
462+
463+
// Convert to String for password encoder (required by BCrypt)
464+
String password = new String(passwordChars);
465+
try {
466+
changeUserPassword(user, password);
467+
} finally {
468+
// Clear the temporary String reference
469+
password = null;
470+
}
471+
}
472+
451473
/**
452474
* Check if valid old password.
453475
*
@@ -462,6 +484,29 @@ public boolean checkIfValidOldPassword(final User user, final String oldPassword
462484
return passwordEncoder.matches(oldPassword, user.getPassword());
463485
}
464486

487+
/**
488+
* Check if valid old password (char array version - preferred for security).
489+
* This method converts the char array to String for verification.
490+
*
491+
* @param user the user
492+
* @param oldPasswordChars the old password as char array
493+
* @return true, if successful
494+
*/
495+
public boolean checkIfValidOldPassword(final User user, final char[] oldPasswordChars) {
496+
if (oldPasswordChars == null) {
497+
return false;
498+
}
499+
500+
// Convert to String for password encoder
501+
String oldPassword = new String(oldPasswordChars);
502+
try {
503+
return checkIfValidOldPassword(user, oldPassword);
504+
} finally {
505+
// Clear the temporary String reference
506+
oldPassword = null;
507+
}
508+
}
509+
465510
/**
466511
* See if the Email exists in the user repository.
467512
*

0 commit comments

Comments
 (0)