Skip to content

Feature: Password hash upgrade#7696

Merged
DawoudIO merged 4 commits intomasterfrom
fix/password-hash-upgrade
Nov 30, 2025
Merged

Feature: Password hash upgrade#7696
DawoudIO merged 4 commits intomasterfrom
fix/password-hash-upgrade

Conversation

@DawoudIO
Copy link
Contributor

@DawoudIO DawoudIO commented Nov 30, 2025

What Changed

  • upgrades password hashing from weak SHA-256 to secure bcrypt
  • ensures database views are rebuilt after restore operations.

Type

  • ✨ Feature
  • 🐛 Bug fix
  • ♻️ Refactor
  • 🏗️ Build/Infrastructure
  • 🔒 Security

Testing

Screenshots

Security Check

  • Introduces new input validation
  • Modifies authentication/authorization
  • Affects data privacy/GDPR

Code Quality

  • Database: Propel ORM only, no raw SQL
  • No deprecated attributes (align, valign, nowrap, border, cellpadding, cellspacing, bgcolor)
  • Bootstrap CSS classes used
  • All CSS bundled via webpack

Pre-Merge

  • Tested locally
  • No new warnings
  • Build passes
  • Backward compatible (or migration documented)

Migrate from weak SHA-256 password hashing to secure bcrypt using
PHP's password_hash() with PASSWORD_DEFAULT.

Changes:
- hashPassword() now uses password_hash() for bcrypt hashing
- isPasswordValid() supports both legacy SHA-256 and new bcrypt formats
- Legacy passwords are automatically upgraded to bcrypt on successful login
- New users get bcrypt-hashed passwords immediately
- UserEditor.php uses updatePassword() instead of manual hashing

Migration strategy:
- Writing: All new passwords use bcrypt
- Reading: Supports both SHA-256 (legacy) and bcrypt (new)
- Auto-upgrade: Legacy hashes converted to bcrypt on login

The legacy SHA-256 support will be removed in a future version once
all users have logged in and had their passwords upgraded.
Add rebuildViews() method to RestoreJob that executes rebuild_views.sql
after a database restore completes. This ensures views (email_list,
email_count) are always current even when restoring older backups that
may not include current view definitions.

Called from postRestoreCleanup() so views are rebuilt regardless of
backup type (SQL, GZSQL, or full backup).
@DawoudIO DawoudIO added this to the 6.3.0 milestone Nov 30, 2025
Copilot AI review requested due to automatic review settings November 30, 2025 07:17
@DawoudIO DawoudIO requested a review from a team as a code owner November 30, 2025 07:17
@DawoudIO DawoudIO requested review from DAcodedBEAT, MrClever, bigtigerku, grayeul and respencer and removed request for a team November 30, 2025 07:17
Copy link
Contributor

Copilot AI left a 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 PR implements a critical security enhancement by migrating password storage from weak SHA-256 hashing to secure bcrypt hashing using PHP's password_hash() function. The implementation includes a transparent migration path that automatically upgrades legacy SHA-256 passwords to bcrypt when users successfully authenticate. Additionally, the PR ensures database views are properly rebuilt after restore operations to prevent potential schema inconsistencies.

Key Changes:

  • Password hashing upgraded from SHA-256 to bcrypt with automatic migration on login
  • New user passwords now use secure bcrypt hashing via User::updatePassword() method
  • Database views automatically rebuilt after restore operations

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/ChurchCRM/model/ChurchCRM/User.php Implements bcrypt password hashing with backward-compatible SHA-256 validation and automatic upgrade on successful login
src/UserEditor.php Removes legacy SHA-256 hashing for new users; uses User::updatePassword() for secure bcrypt hashing
src/ChurchCRM/Backup/RestoreJob.php Adds rebuildViews() method to restore database views from rebuild_views.sql after backup restoration
demo/ChurchCRM-Database.sql Updates demo database with bcrypt password hashes for users 1 and 3; retains SHA-256 hash for user 95 to demonstrate backward compatibility

Comment on lines +117 to +119
// Upgrade to bcrypt on successful login
$this->setPassword($this->hashPassword($password));
$this->save();
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider adding logging for password hash migration events. When a legacy SHA-256 password is upgraded to bcrypt, this is a significant security event that should be logged for audit purposes. This helps track the migration progress and can alert administrators if unexpected migrations occur.

Suggested addition:

if (hash_equals($storedHash, $legacyHash)) {
    // Upgrade to bcrypt on successful login
    LoggerUtils::getAppLogger()->info('Upgrading password hash from SHA-256 to bcrypt', [
        'user_id' => $this->getPersonId(),
        'username' => $this->getUserName()
    ]);
    $this->setPassword($this->hashPassword($password));
    $this->save();
    return true;
}

Copilot uses AI. Check for mistakes.
return $this->getPassword() == $this->hashPassword($password);
$storedHash = $this->getPassword();

// Check if this is a bcrypt hash (starts with $2y$)
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "Check if this is a bcrypt hash (starts with $2y$)" but the actual implementation checks for three prefixes: $2y$, $2b$, and $2a$. Update the comment to reflect all supported bcrypt variants:

// Check if this is a bcrypt hash (starts with $2y$, $2b$, or $2a$)
Suggested change
// Check if this is a bcrypt hash (starts with $2y$)
// Check if this is a bcrypt hash (starts with $2y$, $2b$, or $2a$)

Copilot uses AI. Check for mistakes.
@DawoudIO DawoudIO merged commit ffca0fc into master Nov 30, 2025
6 checks passed
@DawoudIO DawoudIO deleted the fix/password-hash-upgrade branch November 30, 2025 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants