parent
0fc870d383
commit
66bd44b4b7
@ -0,0 +1 @@
|
||||
from .security import passwd
|
||||
@ -0,0 +1,101 @@
|
||||
"""
|
||||
Password generation for the Notebook.
|
||||
"""
|
||||
import getpass
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
from ipython_genutils.py3compat import cast_bytes, str_to_bytes
|
||||
|
||||
# Length of the salt in nr of hex chars, which implies salt_len * 4
|
||||
# bits of randomness.
|
||||
salt_len = 12
|
||||
|
||||
|
||||
def passwd(passphrase=None, algorithm='sha1'):
|
||||
"""Generate hashed password and salt for use in notebook configuration.
|
||||
|
||||
In the notebook configuration, set `c.NotebookApp.password` to
|
||||
the generated string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
passphrase : str
|
||||
Password to hash. If unspecified, the user is asked to input
|
||||
and verify a password.
|
||||
algorithm : str
|
||||
Hashing algorithm to use (e.g, 'sha1' or any argument supported
|
||||
by :func:`hashlib.new`).
|
||||
|
||||
Returns
|
||||
-------
|
||||
hashed_passphrase : str
|
||||
Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> passwd('mypassword')
|
||||
'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
|
||||
|
||||
"""
|
||||
if passphrase is None:
|
||||
for i in range(3):
|
||||
p0 = getpass.getpass('Enter password: ')
|
||||
p1 = getpass.getpass('Verify password: ')
|
||||
if p0 == p1:
|
||||
passphrase = p0
|
||||
break
|
||||
else:
|
||||
print('Passwords do not match.')
|
||||
else:
|
||||
raise ValueError('No matching passwords found. Giving up.')
|
||||
|
||||
h = hashlib.new(algorithm)
|
||||
salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
|
||||
h.update(cast_bytes(passphrase, 'utf-8') + str_to_bytes(salt, 'ascii'))
|
||||
|
||||
return ':'.join((algorithm, salt, h.hexdigest()))
|
||||
|
||||
|
||||
def passwd_check(hashed_passphrase, passphrase):
|
||||
"""Verify that a given passphrase matches its hashed version.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hashed_passphrase : str
|
||||
Hashed password, in the format returned by `passwd`.
|
||||
passphrase : str
|
||||
Passphrase to validate.
|
||||
|
||||
Returns
|
||||
-------
|
||||
valid : bool
|
||||
True if the passphrase matches the hash.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from jupyter_notebook.auth.security import passwd_check
|
||||
>>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
|
||||
... 'mypassword')
|
||||
True
|
||||
|
||||
>>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
|
||||
... 'anotherpassword')
|
||||
False
|
||||
"""
|
||||
try:
|
||||
algorithm, salt, pw_digest = hashed_passphrase.split(':', 2)
|
||||
except (ValueError, TypeError):
|
||||
return False
|
||||
|
||||
try:
|
||||
h = hashlib.new(algorithm)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
if len(pw_digest) == 0:
|
||||
return False
|
||||
|
||||
h.update(cast_bytes(passphrase, 'utf-8') + cast_bytes(salt, 'ascii'))
|
||||
|
||||
return h.hexdigest() == pw_digest
|
||||
@ -0,0 +1,25 @@
|
||||
# coding: utf-8
|
||||
from ..security import passwd, passwd_check, salt_len
|
||||
import nose.tools as nt
|
||||
|
||||
def test_passwd_structure():
|
||||
p = passwd('passphrase')
|
||||
algorithm, salt, hashed = p.split(':')
|
||||
nt.assert_equal(algorithm, 'sha1')
|
||||
nt.assert_equal(len(salt), salt_len)
|
||||
nt.assert_equal(len(hashed), 40)
|
||||
|
||||
def test_roundtrip():
|
||||
p = passwd('passphrase')
|
||||
nt.assert_equal(passwd_check(p, 'passphrase'), True)
|
||||
|
||||
def test_bad():
|
||||
p = passwd('passphrase')
|
||||
nt.assert_equal(passwd_check(p, p), False)
|
||||
nt.assert_equal(passwd_check(p, 'a:b:c:d'), False)
|
||||
nt.assert_equal(passwd_check(p, 'a:b'), False)
|
||||
|
||||
def test_passwd_check_unicode():
|
||||
# GH issue #4524
|
||||
phash = u'sha1:23862bc21dd3:7a415a95ae4580582e314072143d9c382c491e4f'
|
||||
assert passwd_check(phash, u"łe¶ŧ←↓→")
|
||||
Loading…
Reference in new issue