def update(cls, *args, **kwargs):
"""Update password hash on update"""
if 'password' in kwargs.keys():
kwargs['phash'] = crypt.crypt(kwargs.pop('password'),
crypt.mksalt())
return super().update(*args, **kwargs)
python类crypt()的实例源码
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
# Python 3's crypt() only accepts unicode, which is then
# encoding using utf-8 before passing to the C-level crypt().
# so we have to decode the secret.
orig = secret
try:
secret = secret.decode("utf-8")
except UnicodeDecodeError:
return None
assert secret.encode("utf-8") == orig, \
"utf-8 spec says this can't happen!"
if _NULL in secret:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
result = _crypt(secret, hash)
if not result or result[0] in _invalid_prefixes:
return None
return result
def check_credentials(username, password):
"""Compare the crypted password of this user with the one stored in the db.
Return the User instance if authenticated successfully.
"""
users_with_that_name = Users.objects.filter(username=username)
if not users_with_that_name:
return [None, "User '{}' does not exist".format(username)]
active_users_with_that_name = users_with_that_name.filter(is_active=1)
if not active_users_with_that_name:
return [None, "Account '{}' has not been activated".format(username)]
user = users_with_that_name[0]
users_with_that_name_and_pwd = users_with_that_name.filter(password=crypt.crypt(password, user.salt))
if not users_with_that_name_and_pwd:
return [None, "Wrong password"]
user = users_with_that_name_and_pwd[0]
return [user, '']
def change_password(username, email, activation_code, password, email_to_file=None, send=True):
if not find_user2(username=username, email=email):
return [None, USER_NOT_FOUND_WITH_EMAIL_MSG]
user = Users.objects.get(username=username, email=email, is_active=1)
if user.activation_code != activation_code:
logging.warning("Invalid activation code: {}".format(activation_code))
return [None, "Password has already been reset"]
user.password = crypt.crypt(password, user.salt)
user.activation_code = None
user.save()
if send:
text = "Your varapp password has changed. " + \
"Please use the new login information below:" + \
"\n\n\tLogin: {}\n\tPassword: {}\n\n".format(username, password)
html = "<p>Your varapp password changed. " + \
"Please use the new login information below:</p>" + \
"<table><tr><td>Login:</td><td>{}</td></tr>".format(username) + \
"<tr><td>Password:</td><td>{}</td></tr></table>".format(password)
send_email(email, "Password reset", text=text, html=html, tofile=email_to_file)
return [user, '']
def _enable_backend_case(cls, backend):
"helper for create_backend_cases(); returns reason to skip backend, or None"
handler = cls.handler
if not is_default_backend(handler, backend) and not TEST_MODE("full"):
return "only default backend is being tested"
if handler.has_backend(backend):
return None
if handler.name == "bcrypt" and backend == "builtin" and TEST_MODE("full"):
# this will be auto-enabled under TEST_MODE 'full'.
return None
from passlib.utils import has_crypt
if backend == "os_crypt" and has_crypt:
if TEST_MODE("full") and cls.find_crypt_replacement():
# in this case, HandlerCase will monkeypatch os_crypt
# to use another backend, just so we can test os_crypt fully.
return None
else:
return "hash not supported by os crypt()"
return "backend not available"
def test_80_faulty_crypt(self):
"test with faulty crypt()"
hash = self.get_sample_hash()[1]
exc_types = (AssertionError,)
setter = self._use_mock_crypt()
def test(value):
# set safe_crypt() to return specified value, and
# make sure assertion error is raised by handler.
setter(value)
self.assertRaises(exc_types, self.do_genhash, "stub", hash)
self.assertRaises(exc_types, self.do_encrypt, "stub")
self.assertRaises(exc_types, self.do_verify, "stub", hash)
test('$x' + hash[2:]) # detect wrong prefix
test(hash[:-1]) # detect too short
test(hash + 'x') # detect too long
def test_81_crypt_fallback(self):
"test per-call crypt() fallback"
# set safe_crypt to return None
setter = self._use_mock_crypt()
setter(None)
if self.find_crypt_replacement():
# handler should have a fallback to use
h1 = self.do_encrypt("stub")
h2 = self.do_genhash("stub", h1)
self.assertEqual(h2, h1)
self.assertTrue(self.do_verify("stub", h1))
else:
# handler should give up
from passlib.exc import MissingBackendError
hash = self.get_sample_hash()[1]
self.assertRaises(MissingBackendError, self.do_encrypt, 'stub')
self.assertRaises(MissingBackendError, self.do_genhash, 'stub', hash)
self.assertRaises(MissingBackendError, self.do_verify, 'stub', hash)
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
# Python 3's crypt() only accepts unicode, which is then
# encoding using utf-8 before passing to the C-level crypt().
# so we have to decode the secret.
orig = secret
try:
secret = secret.decode("utf-8")
except UnicodeDecodeError:
return None
assert secret.encode("utf-8") == orig, \
"utf-8 spec says this can't happen!"
if _NULL in secret:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
result = _crypt(secret, hash)
if not result or result[0] in _invalid_prefixes:
return None
return result
def AdminLogin(req,onlyhead):
global currentcookie
passwd = req.query.get('passwd',[''])[0]
salt = Config.conf['AdministratorPassword'][:2]
passwd = crypt.crypt(passwd,salt)
if passwd != Config.conf['AdministratorPassword']:
return Delegate('/errors/wrongpasswd.html',req,onlyhead)
random.seed(os.urandom(200));
currentcookie = str(random.getrandbits(200))
handler = EH_Generic_class()
handler.iamadmin = 1
(header,content) = Site['/adminmenu.html'].getresult(req,onlyhead,handler)
header['Set-Cookie'] = 'OKUSON='+currentcookie+ \
';Path=/;Max-Age=3600;Version=1'
# Max-Age is one hour
#header['Location'] = '/adminmenu.html'
# Taken out to please opera, which does not get the cookie for the
# login with this header. Max.
return (header,content)
def post(self):
try:
root_crypt=check_output("getent shadow root", shell=True).decode("utf-8").split(':')[1]
rcparts=root_crypt.split('$')
input_passwd=self.get_argument("PASSWORD")
input_crypt=crypt.crypt(input_passwd, "$%s$%s" % (rcparts[1],rcparts[2]))
logging.debug("PASSWD: %s <=> %s" % (root_crypt,input_crypt))
if input_crypt==root_crypt:
self.set_secure_cookie("user", "root")
if self.get_argument("next"):
self.redirect(self.get_argument("next"))
else:
self.redirect("/")
else:
self.get({"PASSWORD":"Incorrect Password"})
except:
self.get({"PASSWORD":"Authentication Failure"})
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
# Python 3's crypt() only accepts unicode, which is then
# encoding using utf-8 before passing to the C-level crypt().
# so we have to decode the secret.
orig = secret
try:
secret = secret.decode("utf-8")
except UnicodeDecodeError:
return None
assert secret.encode("utf-8") == orig, \
"utf-8 spec says this can't happen!"
if _NULL in secret:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
result = _crypt(secret, hash)
if not result or result[0] in _invalid_prefixes:
return None
return result
def create_user(self, name, username, password):
encrypted = crypt.crypt(password, "22") # todo why t-f is salt "22"?
return self.bash(
"useradd"
" -p " + encrypted +
" -s " + "/bin/bash" +
" -d " + "/home/" + username +
" -m " +
" -c \"" + name + "\" " + username)
# Roadmap: this would be cool
#
# class BlackArch(IOperatingSystem):
#
# def install(self, programs):
# print("pacman -S " + programs)
#
# def uninstall(self, programs):
# print("apt-get -R " + programs)
# ...
def validate_authentication(self, username, password, handler):
"""Authenticates against shadow password db; raises
AuthenticationFailed in case of failed authentication.
"""
if username == "anonymous":
if self.anonymous_user is None:
raise AuthenticationFailed(self.msg_anon_not_allowed)
else:
try:
pw1 = spwd.getspnam(username).sp_pwd
pw2 = crypt.crypt(password, pw1)
except KeyError: # no such username
raise AuthenticationFailed(self.msg_no_such_user)
else:
if pw1 != pw2:
raise AuthenticationFailed(self.msg_wrong_password)
def __init__(self, *args, **kwargs):
self.hashes = []
def crypt_pw(pw):
return "{crypt}" + python_crypt(pw, generate_crypt_salt(2))
self.methods = {"crypt": crypt_pw,
"CRYPT": ldap_sha1_crypt.encrypt,
"MD5": ldap_md5_crypt.encrypt,
"SSHA": ldap_salted_sha1.encrypt}
for length in range(4,20):
pw = generate_password(length)
hash_dict = {"plain": pw}
for method in self.methods:
hash_dict[method] = self.methods[method](pw)
self.hashes.append(hash_dict)
super(Test_020_PasswdHashes, self).__init__(*args, **kwargs)
def verify_password(plaintext_password, hash):
"""Verifies a plain password string agailst a given password hash.
It uses a ldap_context to verify RFC 2307 hashes including the GNU
{crypt} extension. If the passord is a basic 2-byte-salted hash
given grom old unix crypt() the ldap_context will fail. For this we
try to crypt() the given plaintext using the first two bytes of the
given hash als salt and compare the two hashes.
"""
try:
result = ldap_context.verify(plaintext_password, hash)
if result:
return result
except ValueError:
pass
if hash.startswith("{crypt}") and len(hash) > 9:
real_hash = hash[7:]
salt = hash[7:9]
crypted = crypt(plaintext_password, salt)
return crypted == real_hash
return False
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
# Python 3's crypt() only accepts unicode, which is then
# encoding using utf-8 before passing to the C-level crypt().
# so we have to decode the secret.
orig = secret
try:
secret = secret.decode("utf-8")
except UnicodeDecodeError:
return None
assert secret.encode("utf-8") == orig, \
"utf-8 spec says this can't happen!"
if _NULL in secret:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
result = _crypt(secret, hash)
if not result or result[0] in _invalid_prefixes:
return None
return result
def setUp(self):
self.admin = credentials.UsernamePassword('admin', 'asdf')
self.alice = credentials.UsernamePassword('alice', 'foo')
self.badPass = credentials.UsernamePassword('alice', 'foobar')
self.badUser = credentials.UsernamePassword('x', 'yz')
self.checker = strcred.makeChecker('unix')
# Hack around the pwd and spwd modules, since we can't really
# go about reading your /etc/passwd or /etc/shadow files
if pwd:
database = UserDatabase()
for username, password in self.users.items():
database.addUser(
username, crypt.crypt(password, 'F/'),
1000, 1000, username, '/home/' + username, '/bin/sh')
self.patch(pwd, 'getpwnam', database.getpwnam)
if spwd:
self._spwd_getspnam = spwd.getspnam
spwd.getspnam = self._spwd
def _enable_backend_case(cls, backend):
"helper for create_backend_cases(); returns reason to skip backend, or None"
handler = cls.handler
if not is_default_backend(handler, backend) and not TEST_MODE("full"):
return "only default backend is being tested"
if handler.has_backend(backend):
return None
if handler.name == "bcrypt" and backend == "builtin" and TEST_MODE("full"):
# this will be auto-enabled under TEST_MODE 'full'.
return None
from passlib.utils import has_crypt
if backend == "os_crypt" and has_crypt:
if TEST_MODE("full") and cls.find_crypt_replacement():
# in this case, HandlerCase will monkeypatch os_crypt
# to use another backend, just so we can test os_crypt fully.
return None
else:
return "hash not supported by os crypt()"
return "backend not available"
def test_80_faulty_crypt(self):
"test with faulty crypt()"
hash = self.get_sample_hash()[1]
exc_types = (AssertionError,)
setter = self._use_mock_crypt()
def test(value):
# set safe_crypt() to return specified value, and
# make sure assertion error is raised by handler.
setter(value)
self.assertRaises(exc_types, self.do_genhash, "stub", hash)
self.assertRaises(exc_types, self.do_encrypt, "stub")
self.assertRaises(exc_types, self.do_verify, "stub", hash)
test('$x' + hash[2:]) # detect wrong prefix
test(hash[:-1]) # detect too short
test(hash + 'x') # detect too long
def test_81_crypt_fallback(self):
"test per-call crypt() fallback"
# set safe_crypt to return None
setter = self._use_mock_crypt()
setter(None)
if self.find_crypt_replacement():
# handler should have a fallback to use
h1 = self.do_encrypt("stub")
h2 = self.do_genhash("stub", h1)
self.assertEqual(h2, h1)
self.assertTrue(self.do_verify("stub", h1))
else:
# handler should give up
from passlib.exc import MissingBackendError
hash = self.get_sample_hash()[1]
self.assertRaises(MissingBackendError, self.do_encrypt, 'stub')
self.assertRaises(MissingBackendError, self.do_genhash, 'stub', hash)
self.assertRaises(MissingBackendError, self.do_verify, 'stub', hash)
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
# Python 3's crypt() only accepts unicode, which is then
# encoding using utf-8 before passing to the C-level crypt().
# so we have to decode the secret.
orig = secret
try:
secret = secret.decode("utf-8")
except UnicodeDecodeError:
return None
assert secret.encode("utf-8") == orig, \
"utf-8 spec says this can't happen!"
if _NULL in secret:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
result = _crypt(secret, hash)
if not result or result[0] in _invalid_prefixes:
return None
return result
def get_hexdigest(algorithm, salt, raw_password):
"""
Returns a string of the hexdigest of the given plaintext password and salt
using the given algorithm ('md5', 'sha1' or 'crypt').
"""
raw_password, salt = smart_str(raw_password), smart_str(salt)
if algorithm == 'crypt':
try:
import crypt
except ImportError:
raise ValueError('"crypt" password algorithm not supported in this environment')
return crypt.crypt(raw_password, salt)
if algorithm == 'md5':
return hashlib.md5(salt + raw_password).hexdigest()
elif algorithm == 'sha1':
return hashlib.sha1(salt + raw_password).hexdigest()
elif algorithm == 'sha256':
return hashlib.sha256(salt + raw_password).hexdigest()
raise ValueError("Got unknown password algorithm type in password.")
def pytest_sessionstart(request):
""" before session.main() is called. """
import crypt, shutil
pw = crypt.crypt(pws[0], 'ab')
dbpath = os.path.join(SEC_DB_PATH, user)
thisdir = os.path.dirname(os.path.abspath(__file__))
if os.path.exists(dbpath):
subprocess.Popen("sudo rm -rf {}".format(dbpath), shell=True)
if DISTRO == 'darwin':
subprocess.Popen(
"sudo {2}/create_mac_user.sh {0} {1}"
.format(user, pws[0], thisdir),
shell=True
)
elif DISTRO == 'windows':
print("WINDOWS: Ignoring!!")
else:
cmd = "sudo {2}/create_linux_user.sh {0} {1}".format(user, pw, thisdir),
subprocess.Popen(
cmd,
shell=True
)
print("LINUX: {}".format(cmd))
assert check(0)
def safe_crypt(secret, hash):
if isinstance(secret, bytes):
# Python 3's crypt() only accepts unicode, which is then
# encoding using utf-8 before passing to the C-level crypt().
# so we have to decode the secret.
orig = secret
try:
secret = secret.decode("utf-8")
except UnicodeDecodeError:
return None
assert secret.encode("utf-8") == orig, \
"utf-8 spec says this can't happen!"
if _NULL in secret:
raise ValueError("null character in secret")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
result = _crypt(secret, hash)
if not result or result[0] in _invalid_prefixes:
return None
return result
def authorize(self, channel, username, password):
import crypt
import pwd
try:
info = pwd.getpwnam(username)
except KeyError:
return 0, 'No such user.', None
mangled = info[1]
if crypt.crypt(password, mangled[:2]) == mangled:
channel.read_only = 0
fs = filesys.schizophrenic_unix_filesystem(
'/',
info[5],
persona=(info[2], info[3])
)
return 1, 'Login successful.', fs
else:
return 0, 'Password invalid.', None
def hexdigest(self, password):
if self.algorithm == PasswordEncryption.ALGORITHM_CRYPT:
try:
import crypt
except ImportError:
self.error("crypt module not found in this system. Please use md5 or sha* algorithm")
return crypt.crypt(password, self.salt)
encoded_str = (self.salt + password).encode('utf-8')
if self.algorithm == PasswordEncryption.ALGORITHM_SHA1:
return hashlib.sha1(encoded_str).hexdigest()
elif self.algorithm == PasswordEncryption.ALGORITHM_MD5:
return hashlib.md5(encoded_str).hexdigest()
elif self.algorithm == PasswordEncryption.ALGORITHM_SHA256:
return hashlib.sha256(encoded_str).hexdigest()
elif self.algorithm == PasswordEncryption.ALGORITHM_SHA512:
return hashlib.sha512(encoded_str).hexdigest()
raise ValueError('Unsupported hash type %s' % self.algorithm)
def encoded_password(self):
if self.auth_method == Authentication.CLEARTEXT_PASSWORD:
return self.password
elif self.auth_method == Authentication.CRYPT_PASSWORD:
return crypt.crypt(self.password, self.options['salt'])
elif self.auth_method == Authentication.MD5_PASSWORD:
for key in 'user', 'salt':
m = hashlib.md5()
m.update(self.password + self.options[key])
hexdigest = m.hexdigest()
if six.PY3:
# In python3 the output of m.hexdigest() is a unicode string,
# so has to be converted to bytes before concat'ing with
# the password bytes.
hexdigest = bytes(hexdigest, 'ascii')
self.password = hexdigest
prefix = 'md5'
if six.PY3:
# Same workaround for bytes here.
prefix = bytes(prefix, 'ascii')
return prefix + self.password
else:
raise ValueError("unsupported authentication method: {0}".format(self.auth_method))
def check_passwd(name, passwd):
cryptedpass = None
try:
cryptedpass = getpwnam(name)[1]
except:
return False
#shadowed or not, that's the questions here
if cryptedpass == 'x' or cryptedpass == '*':
try:
cryptedpass = getspnam(name)[1]
except:
return False
if cryptedpass == '':
return True
return crypt(passwd, cryptedpass) == cryptedpass
def create(cls, *args, **kwargs):
"""Update password hash on create"""
if 'password' in kwargs.keys():
kwargs['phash'] = crypt.crypt(kwargs.pop('password'),
crypt.mksalt())
return super().create(*args, **kwargs)
def save(self, *args, **kwargs):
"""Update password hash on save"""
if getattr(self, 'password', None) is not None:
self.phash = crypt.crypt(self.password, crypt.mksalt())
del self.password
return super().save(*args, **kwargs)