def __init__(self, max_length=None, **kwargs): # Fail if passlib is not found. if passlib is None: raise ImproperlyConfigured( "'passlib' is required to use 'PasswordType'") # Construct the passlib crypt context. self.context = LazyCryptContext(**kwargs) self._max_length = max_length
def crypt_ctx(self): ctx = stack.top if ctx is not None: if not hasattr(self, '_crypt_ctx'): self._crypt_ctx = LazyCryptContext( **current_app.config['PASSLIB_CONTEXT']) return self._crypt_ctx
def __init__(self, max_length=None, **kwargs): # Fail if passlib is not found. if passlib is None: raise ImproperlyConfigured( "'passlib' is required to use 'PasswordType'" ) # Construct the passlib crypt context. self.context = LazyCryptContext(**kwargs) self._max_length = max_length
def test_kwd_constructor(self): self.assertFalse(has_crypt_handler("dummy_2")) register_crypt_handler_path("dummy_2", "passlib.tests.test_context") cc = LazyCryptContext(iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"]) self.assertFalse(has_crypt_handler("dummy_2", True)) self.assertTrue(cc.policy.handler_is_deprecated("des_crypt")) self.assertEqual(cc.policy.schemes(), ["dummy_2", "des_crypt"]) self.assertTrue(has_crypt_handler("dummy_2", True))
def __init__(self, max_length=None, **kwargs): # Fail if passlib is not found. if passlib is None: raise ImproperlyConfigured( "'passlib' is required to use 'PasswordType'" ) # Construct the passlib crypt context. self.context = LazyCryptContext(**kwargs) if max_length is None: max_length = self.calculate_max_length() # Set the length to the now-calculated max length. self.length = max_length
def test_callable_constructor(self): self.assertFalse(has_crypt_handler("dummy_2")) register_crypt_handler_path("dummy_2", "passlib.tests.test_context") def create_policy(flag=False): self.assertTrue(flag) return CryptPolicy(schemes=iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"]) cc = LazyCryptContext(create_policy=create_policy, flag=True) self.assertFalse(has_crypt_handler("dummy_2", True)) self.assertTrue(cc.policy.handler_is_deprecated("des_crypt")) self.assertEqual(cc.policy.schemes(), ["dummy_2", "des_crypt"]) self.assertTrue(has_crypt_handler("dummy_2", True))
class PasswordType(TypeDecorator): impl = Text def __init__(self, **kwargs): super().__init__() self.context = LazyCryptContext(**kwargs) def process_bind_param(self, value, dialect): return self.coerce(value).hash def process_result_value(self, value, dialect): return Password(value, self.context) def coerce(self, value): if isinstance(value, Password): return value return Password(self.context.hash(value), self.context)
"openbsd_context", "netbsd_context", "freebsd_context", "host_context", ] # ============================================================================= # linux support # ============================================================================= # known platform names - linux2 linux_context = linux2_context = LazyCryptContext( schemes=[ "sha512_crypt", "sha256_crypt", "md5_crypt", "des_crypt", "unix_disabled" ], deprecated=["des_crypt"], ) # ============================================================================= # bsd support # ============================================================================= # known platform names - # freebsd2 # freebsd3 # freebsd4 # freebsd5 # freebsd6 # freebsd7
class PasswordType(types.TypeDecorator, ScalarCoercible): """ PasswordType hashes passwords as they come into the database and allows verifying them using a pythonic interface. All keyword arguments (aside from max_length) are forwarded to the construction of a `passlib.context.LazyCryptContext` object, which also supports deferred configuration via the `onload` callback. The following usage will create a password column that will automatically hash new passwords as `pbkdf2_sha512` but still compare passwords against pre-existing `md5_crypt` hashes. As passwords are compared; the password hash in the database will be updated to be `pbkdf2_sha512`. :: class Model(Base): password = sa.Column(PasswordType( schemes=[ 'pbkdf2_sha512', 'md5_crypt' ], deprecated=['md5_crypt'] )) Verifying password is as easy as: :: target = Model() target.password = '******' # '$5$rounds=80000$H.............' target.password == 'b' # True Lazy configuration of the type with Flask config: :: import flask class User(db.Model): __tablename__ = 'user' password = db.Column( PasswordType( # The returned dictionary is forwarded to the CryptContext onload=lambda **kwargs: dict( schemes=flask.current_app.config['PASSWORD_SCHEMES'], **kwargs ), ), unique=False, nullable=False, ) """ impl = types.VARBINARY(1024) python_type = Password def __init__(self, max_length=None, **kwargs): # Fail if passlib is not found. if passlib is None: raise ImproperlyConfigured( "'passlib' is required to use 'PasswordType'" ) # Construct the passlib crypt context. self.context = LazyCryptContext(**kwargs) if max_length is None: max_length = self.calculate_max_length() # Set the length to the now-calculated max length. self.length = max_length def calculate_max_length(self): # Calculate the largest possible encoded password. # name + rounds + salt + hash + ($ * 4) of largest hash max_lengths = [1024] for name in self.context.schemes(): scheme = getattr(__import__('passlib.hash').hash, name) length = 4 + len(scheme.name) length += len(str(getattr(scheme, 'max_rounds', ''))) length += (getattr(scheme, 'max_salt_size', 0) or 0) length += getattr( scheme, 'encoded_checksum_size', scheme.checksum_size ) max_lengths.append(length) # Return the maximum calculated max length. return max(max_lengths) def load_dialect_impl(self, dialect): if dialect.name == 'postgresql': # Use a BYTEA type for postgresql. impl = postgresql.BYTEA(self.length) return dialect.type_descriptor(impl) if dialect.name == 'oracle': # Use a RAW type for oracle. impl = oracle.RAW(self.length) return dialect.type_descriptor(impl) # Use a VARBINARY for all other dialects. impl = types.VARBINARY(self.length) return dialect.type_descriptor(impl) def process_bind_param(self, value, dialect): if isinstance(value, Password): # If were given a password secret; encrypt it. if value.secret is not None: return self.context.encrypt(value.secret).encode('utf8') # Value has already been hashed. return value.hash if isinstance(value, six.string_types): # Assume value has not been hashed. return self.context.encrypt(value).encode('utf8') def process_result_value(self, value, dialect): if value is not None: return Password(value, self.context) def _coerce(self, value): if value is None: return if not isinstance(value, Password): # Hash the password using the default scheme. value = self.context.encrypt(value).encode('utf8') return Password(value, context=self.context) else: # If were given a password object; ensure the context is right. value.context = weakref.proxy(self.context) # If were given a password secret; encrypt it. if value.secret is not None: value.hash = self.context.encrypt(value.secret).encode('utf8') value.secret = None return value @property def python_type(self): return self.impl.type.python_type
class PasswordType(types.TypeDecorator, ConversionBase): python_type = Password impl = types.VARBINARY(1024) def __init__(self, max_length=None, **kwargs): self._max_length = max_length self.context = LazyCryptContext(**kwargs) super(PasswordType, self).__init__() @property def length(self): if self._max_length is None: self._max_length = self.calculate_max_length() return self._max_length def calculate_max_length(self): max_lengths = [1024] for name in self.context.schemes(): scheme = getattr(__import__('passlib.hash').hash, name) length = 4 + len(scheme.name) length += len(str(getattr(scheme, 'max_rounds', ''))) length += (getattr(scheme, 'max_salt_size', 0) or 0) length += getattr(scheme, 'encoded_checksum_size', scheme.checksum_size) max_lengths.append(length) return max(max_lengths) def load_dialect_impl(self, dialect): impl = types.VARBINARY(self.length) return dialect.type_descriptor(impl) def process_bind_param(self, value, dialect): if isinstance(value, Password): if value.secret is not None: return value.context.encrypt(value.secret).encode("utf-8") return value.hash if isinstance(value, basestring): return self.context.encrypt(value).encode("utf-8") def process_result_value(self, value, dialect): if value is not None: return Password(value, self.context) def _conversion(self, value): if value is None: return if not isinstance(value, Password): value = self.context.encrypt(value).encode("utf-8") return Password(value, context=self.context, secret=False) else: value.context = weakref.proxy(self.context) if value.secret: value.hash = value.context.encrypt( value.secret).encode("utf-8") value.secret = None return value
# plaintext handlers 'plaintext', 'ldap_plaintext', # disabled handlers 'django_disabled', 'unix_disabled', 'unix_fallback', ] for name in excluded: schemes.remove(name) # return config return dict(schemes=schemes, default="sha256_crypt") master_context = LazyCryptContext(onload=_load_master_config) #============================================================================= # for quickly bootstrapping new custom applications #============================================================================= custom_app_context = LazyCryptContext( # choose some reasonbly strong schemes schemes=["sha512_crypt", "sha256_crypt"], # set some useful global options default="sha256_crypt" if sys_bits < 64 else "sha512_crypt", all__vary_rounds = 0.1, # set a good starting point for rounds selection sha512_crypt__min_rounds = 60000, sha256_crypt__min_rounds = 80000,
from passlib.context import LazyCryptContext olea_context = LazyCryptContext(schemes=['argon2'], argon2__time_cost=2, argon2__memory_cost=256 * 1024, argon2__parallelism=4)
from distutils.version import StrictVersion from passlib.context import LazyCryptContext import werkzeug from .handlers import (werkzeug_salted_md5, werkzeug_salted_sha1, werkzeug_salted_sha224, werkzeug_salted_sha256, werkzeug_salted_sha384, werkzeug_salted_sha512) werkzeug061_context = LazyCryptContext( schemes=[ werkzeug_salted_md5, werkzeug_salted_sha1, ], default='werkzeug_salted_sha1', ) werkzeugdev_context = LazyCryptContext( schemes=[ werkzeug_salted_md5, werkzeug_salted_sha1, werkzeug_salted_sha224, werkzeug_salted_sha256, werkzeug_salted_sha384, werkzeug_salted_sha512, ], default='werkzeug_salted_sha1', ) if StrictVersion('0.6.1') <= StrictVersion(werkzeug.__version__) <= StrictVersion('0.8.3'):
def __init__(self, max_length=None, **kwargs): self._max_length = max_length self.context = LazyCryptContext(**kwargs) super(PasswordType, self).__init__()
def __init__(self, **kwargs): super().__init__() self.context = LazyCryptContext(**kwargs)
class PasswordType(types.TypeDecorator, ScalarCoercible): """ PasswordType hashes passwords as they come into the database and allows verifying them using a pythonic interface. All keyword arguments (aside from max_length) are forwarded to the construction of a `passlib.context.LazyCryptContext` object, which also supports deferred configuration via the `onload` callback. The following usage will create a password column that will automatically hash new passwords as `pbkdf2_sha512` but still compare passwords against pre-existing `md5_crypt` hashes. As passwords are compared; the password hash in the database will be updated to be `pbkdf2_sha512`. :: class Model(Base): password = sa.Column(PasswordType( schemes=[ 'pbkdf2_sha512', 'md5_crypt' ], deprecated=['md5_crypt'] )) Verifying password is as easy as: :: target = Model() target.password = '******' # '$5$rounds=80000$H.............' target.password == 'b' # True Lazy configuration of the type with Flask config: :: import flask class User(db.Model): __tablename__ = 'user' password = db.Column( PasswordType( # The returned dictionary is forwarded to the CryptContext onload=lambda **kwargs: dict( schemes=flask.current_app.config['PASSWORD_SCHEMES'], **kwargs ), ), unique=False, nullable=False, ) """ impl = types.VARBINARY(1024) python_type = Password def __init__(self, max_length=None, **kwargs): # Fail if passlib is not found. if passlib is None: raise ImproperlyConfigured( "'passlib' is required to use 'PasswordType'") # Construct the passlib crypt context. self.context = LazyCryptContext(**kwargs) self._max_length = max_length def __repr__(self): return 'PasswordType(max_length={length})'.format(length=self.length) @property def length(self): """Get column length.""" if self._max_length is None: self._max_length = self.calculate_max_length() return self._max_length def calculate_max_length(self): # Calculate the largest possible encoded password. # name + rounds + salt + hash + ($ * 4) of largest hash max_lengths = [1024] for name in self.context.schemes(): scheme = getattr(__import__('passlib.hash').hash, name) length = 4 + len(scheme.name) length += len(str(getattr(scheme, 'max_rounds', ''))) length += (getattr(scheme, 'max_salt_size', 0) or 0) length += getattr(scheme, 'encoded_checksum_size', scheme.checksum_size) max_lengths.append(length) # Return the maximum calculated max length. return max(max_lengths) def load_dialect_impl(self, dialect): if dialect.name == 'postgresql': # Use a BYTEA type for postgresql. impl = postgresql.BYTEA(self.length) return dialect.type_descriptor(impl) if dialect.name == 'oracle': # Use a RAW type for oracle. impl = oracle.RAW(self.length) return dialect.type_descriptor(impl) # Use a VARBINARY for all other dialects. impl = types.VARBINARY(self.length) return dialect.type_descriptor(impl) def process_bind_param(self, value, dialect): if isinstance(value, Password): # If were given a password secret; encrypt it. if value.secret is not None: return self.context.encrypt(value.secret).encode('utf8') # Value has already been hashed. return value.hash if isinstance(value, six.string_types): # Assume value has not been hashed. return self.context.encrypt(value).encode('utf8') def process_result_value(self, value, dialect): if value is not None: return Password(value, self.context) def _coerce(self, value): if value is None: return if not isinstance(value, Password): # Hash the password using the default scheme. value = self.context.encrypt(value).encode('utf8') return Password(value, context=self.context) else: # If were given a password object; ensure the context is right. value.context = weakref.proxy(self.context) # If were given a password secret; encrypt it. if value.secret is not None: value.hash = self.context.encrypt(value.secret).encode('utf8') value.secret = None return value @property def python_type(self): return self.impl.type.python_type
from passlib.context import LazyCryptContext from {{ cookiecutter.repo_name }}.models.types.password import Password context = LazyCryptContext(schemes=[ 'md5_crypt' ]) def test_password(): pwd = Password(context.hash("test_password"), context) assert pwd == "test_password", "Comparing against plaintext should work" assert pwd != "wrong_password", "not equals should work"