class SecurePassword(object): """Adds hashing (with salting) and verification capabilities to a clear text password.""" _password_context = context.CryptContext(schemes=["bcrypt"], deprecated="auto") def hash_and_salt_password(self, password: str) -> str: """Hash and salt a clear text password using bcrypt. Args: password (str): Plain text password Returns: str: Password hash """ return self._password_context.hash(password) def verify_password(self, password: str, password_hash: str) -> bool: """Verify password. Args: password (str): Clear text password. password_hash (str): Salted and hashed password. Returns: bool: True if the plain text password is correct. """ return self._password_context.verify(secret=password, hash=password_hash)
def get_password_context(): if User._ctx: return User._ctx schemes = registry.list_crypt_handlers() # scrypt throws a warning if the native wheels aren't found schemes.remove('scrypt') # we can't leave plaintext schemes as they will be misidentified for scheme in schemes: if scheme.endswith('plaintext'): schemes.remove(scheme) User._ctx = context.CryptContext( schemes=schemes, default='bcrypt_sha256', bcrypt_sha256__rounds=app.config['CREDENTIAL_ROUNDS'], deprecated='auto') return User._ctx
def get_password_context(self): return context.CryptContext( schemes=self.scheme_dict.values(), default=self.scheme_dict[app.config['PASSWORD_SCHEME']], )
class User(Base, Email): """ A user is an email address that has a password to access a mailbox. """ __tablename__ = "user" domain = db.relationship(Domain, backref=db.backref('users', cascade='all, delete-orphan')) password = db.Column(db.String(255), nullable=False) quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9) global_admin = db.Column(db.Boolean(), nullable=False, default=False) # Features enable_imap = db.Column(db.Boolean(), nullable=False, default=True) enable_pop = db.Column(db.Boolean(), nullable=False, default=True) # Filters forward_enabled = db.Column(db.Boolean(), nullable=False, default=False) forward_destination = db.Column(db.String(255), nullable=True, default=None) reply_enabled = db.Column(db.Boolean(), nullable=False, default=False) reply_subject = db.Column(db.String(255), nullable=True, default=None) reply_body = db.Column(db.Text(), nullable=True, default=None) # Settings displayed_name = db.Column(db.String(160), nullable=False, default="") spam_enabled = db.Column(db.Boolean(), nullable=False, default=True) spam_threshold = db.Column(db.Numeric(), nullable=False, default=80.0) # Flask-login attributes is_authenticated = True is_active = True is_anonymous = False def get_id(self): return self.email pw_context = context.CryptContext( ["sha512_crypt", "sha256_crypt", "md5_crypt"]) def check_password(self, password): reference = re.match('({[^}]+})?(.*)', self.password).group(2) return User.pw_context.verify(password, reference) def set_password(self, password): self.password = '******' + User.pw_context.encrypt(password) def get_managed_domains(self): if self.global_admin: return Domain.query.all() else: return self.manager_of def get_managed_emails(self, include_aliases=True): emails = [] for domain in self.get_managed_domains(): emails.extend(domain.users) if include_aliases: emails.extend(domain.aliases) return emails @classmethod def login(cls, email, password): user = cls.query.get(email) return user if (user and user.check_password(password)) else None
class User(Base, Email): """ A user is an email address that has a password to access a mailbox. """ __tablename__ = "user" domain = db.relationship(Domain, backref=db.backref('users', cascade='all, delete-orphan')) password = db.Column(db.String(255), nullable=False) quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9) global_admin = db.Column(db.Boolean(), nullable=False, default=False) enabled = db.Column(db.Boolean(), nullable=False, default=True) # Features enable_imap = db.Column(db.Boolean(), nullable=False, default=True) enable_pop = db.Column(db.Boolean(), nullable=False, default=True) # Filters forward_enabled = db.Column(db.Boolean(), nullable=False, default=False) forward_destination = db.Column(db.String(255), nullable=True, default=None) forward_keep = db.Column(db.Boolean(), nullable=False, default=True) reply_enabled = db.Column(db.Boolean(), nullable=False, default=False) reply_subject = db.Column(db.String(255), nullable=True, default=None) reply_body = db.Column(db.Text(), nullable=True, default=None) reply_enddate = db.Column(db.Date, nullable=False, default=date(2999, 12, 31)) # Settings displayed_name = db.Column(db.String(160), nullable=False, default="") spam_enabled = db.Column(db.Boolean(), nullable=False, default=True) spam_threshold = db.Column(db.Integer(), nullable=False, default=80.0) # Flask-login attributes is_authenticated = True is_active = True is_anonymous = False def get_id(self): return self.email scheme_dict = { 'SHA512-CRYPT': "sha512_crypt", 'SHA256-CRYPT': "sha256_crypt", 'MD5-CRYPT': "md5_crypt", 'CRYPT': "des_crypt" } pw_context = context.CryptContext( schemes=scheme_dict.values(), default=scheme_dict[app.config['PASSWORD_SCHEME']], ) def check_password(self, password): reference = re.match('({[^}]+})?(.*)', self.password).group(2) return User.pw_context.verify(password, reference) def set_password(self, password, hash_scheme=app.config['PASSWORD_SCHEME'], raw=False): """Set password for user with specified encryption scheme @password: plain text password to encrypt (if raw == True the hash itself) """ # for the list of hash schemes see https://wiki2.dovecot.org/Authentication/PasswordSchemes if raw: self.password = '******' + hash_scheme + '}' + password else: self.password = '******' + hash_scheme + '}' + User.pw_context.encrypt( password, self.scheme_dict[hash_scheme]) def get_managed_domains(self): if self.global_admin: return Domain.query.all() else: return self.manager_of def get_managed_emails(self, include_aliases=True): emails = [] for domain in self.get_managed_domains(): emails.extend(domain.users) if include_aliases: emails.extend(domain.aliases) return emails def send_welcome(self): if app.config["WELCOME"].lower() == "true": self.sendmail(app.config["WELCOME_SUBJECT"], app.config["WELCOME_BODY"]) @classmethod def login(cls, email, password): user = cls.query.get(email) return user if (user and user.enabled and user.check_password(password)) else None
import passlib.context as context _CONTEXT = context.CryptContext(schemes=['argon2'], deprecated='auto') def hash(password): """Hash the given password and return the hash as string.""" return _CONTEXT.hash(password) def verify(password, password_hash): """Return true if the password results in the hash, else False.""" return _CONTEXT.verify(password, password_hash)
def __init__(self) -> None: self._context = passlib_context.CryptContext(schemes=["bcrypt"], deprecated="auto")