Files
Church-Music/legacy-site/backend/security_migration.py

120 lines
4.0 KiB
Python
Raw Normal View History

2026-01-27 18:04:50 -06:00
#!/usr/bin/env python3
"""
Security Migration Script
Migrates existing SHA-256 passwords to bcrypt
MUST be run after upgrading to bcrypt-based authentication
"""
import sys
import os
sys.path.insert(0, os.path.dirname(__file__))
from postgresql_models import SessionLocal, User
import bcrypt
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def migrate_passwords():
"""
Migrate all SHA-256 passwords to bcrypt
This should be run ONCE after upgrading to bcrypt
"""
db = SessionLocal()
try:
users = db.query(User).all()
logger.info(f"Found {len(users)} users to check")
migrated = 0
for user in users:
# Check if password is already bcrypt (starts with $2b$)
if user.password_hash.startswith('$2b$') or user.password_hash.startswith('$2a$'):
logger.info(f"User {user.username} already using bcrypt - skipping")
continue
# Check if this is a SHA-256 hash (64 hex characters)
if len(user.password_hash) == 64 and all(c in '0123456789abcdef' for c in user.password_hash):
logger.warning(f"User {user.username} has SHA-256 hash - CANNOT migrate automatically")
logger.warning(f" User must reset password or admin must set new password")
logger.warning(f" To set new password: user.set_password('new_password')")
else:
logger.warning(f"User {user.username} has unknown hash format: {user.password_hash[:20]}...")
logger.info(f"Migration complete. {migrated} passwords migrated.")
logger.warning("")
logger.warning("IMPORTANT: Users with SHA-256 passwords must reset their passwords!")
logger.warning(" Option 1: Users can request password reset")
logger.warning(" Option 2: Admin can manually set new passwords using user.set_password()")
except Exception as e:
logger.error(f"Migration failed: {e}")
db.rollback()
return 1
finally:
db.close()
return 0
def create_default_admin(username='admin', password=None):
"""
Create a default admin user with bcrypt password
Use this to create the first admin account
"""
db = SessionLocal()
try:
# Check if user exists
existing = db.query(User).filter(User.username == username).first()
if existing:
logger.error(f"User {username} already exists")
return 1
if not password:
logger.error("Password is required")
return 1
# Create new admin user
admin = User(
username=username,
role='admin',
permissions='view,edit,modify,settings',
active=True
)
admin.set_password(password)
db.add(admin)
db.commit()
logger.info(f"✓ Admin user '{username}' created successfully with bcrypt password")
return 0
except Exception as e:
logger.error(f"Failed to create admin: {e}")
db.rollback()
return 1
finally:
db.close()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Security migration tool')
parser.add_argument('--migrate', action='store_true', help='Migrate SHA-256 passwords to bcrypt')
parser.add_argument('--create-admin', action='store_true', help='Create default admin user')
parser.add_argument('--username', default='admin', help='Username for new admin')
parser.add_argument('--password', help='Password for new admin')
args = parser.parse_args()
if args.create_admin:
if not args.password:
print("ERROR: --password required when creating admin")
sys.exit(1)
sys.exit(create_default_admin(args.username, args.password))
if args.migrate:
sys.exit(migrate_passwords())
parser.print_help()
sys.exit(1)