Source code for tet.sqlalchemy.password

"""
Password hashing mixin for SQLAlchemy user models.

This module provides a mixin class that adds secure password handling
to SQLAlchemy models using bcrypt hashing.

Example
-------

Creating a user model with password support::

    from sqlalchemy import Column, Integer, String
    from sqlalchemy.ext.declarative import declarative_base
    from tet.sqlalchemy.password import UserPasswordMixin

    Base = declarative_base()

    class User(UserPasswordMixin, Base):
        __tablename__ = "users"

        id = Column(Integer, primary_key=True)
        username = Column(String(100), unique=True, nullable=False)

Using the password property::

    user = User(username="john")
    user.password = "secret123"  # Automatically hashed

    # Later, validate password
    if user.validate_password("secret123"):
        print("Password correct!")
"""
import sqlalchemy as sa
from sqlalchemy import orm as orm
from sqlalchemy.ext import declarative

from ..util.crypt import crypt, verify


[docs] class UserPasswordMixin(object): """ Mixin that adds password hashing to SQLAlchemy user models. Provides a ``password`` property that automatically hashes on set, and a :meth:`validate_password` method for verification. """ _password = sa.Column("password", sa.Unicode, nullable=True) def _set_password(self, password): self._password = crypt(password) def _get_password(self): """Return the hashed version of the password.""" return self._password
[docs] def validate_password(self, password): """ Validate a plaintext password against the stored hash. :param password: Plaintext password to validate :return: True if password matches, False otherwise """ if self._password is None: return False return verify(password, self._password)
@declarative.declared_attr def password(cls): """Password property that hashes on set and returns hash on get.""" return orm.synonym( "_password", descriptor=property(cls._get_password, cls._set_password) )