0001-fields-use-django-hashers-to-support-more-hashed-pas.patch
tests/test_form_pages.py | ||
---|---|---|
19 | 19 |
except ImportError: |
20 | 20 |
Image = None |
21 | 21 | |
22 |
import django |
|
23 |
from django.contrib.auth.hashers import ( |
|
24 |
BCryptPasswordHasher, BCryptSHA256PasswordHasher, CryptPasswordHasher, |
|
25 |
MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, |
|
26 |
SHA1PasswordHasher, UnsaltedMD5PasswordHasher, UnsaltedSHA1PasswordHasher) |
|
27 |
if django.VERSION >= (1, 10, 0): |
|
28 |
from django.contrib.auth.hashers import Argon2PasswordHasher |
|
29 | ||
22 | 30 |
from quixote.http_request import Upload as QuixoteUpload |
23 | 31 |
from wcs.qommon.emails import docutils |
24 | 32 |
from wcs.qommon.form import UploadedFile |
... | ... | |
1936 | 1944 |
def form_password_field_submit(app, password): |
1937 | 1945 |
formdef = create_formdef() |
1938 | 1946 |
formdef.enable_tracking_codes = True |
1939 |
formdef.fields = [fields.PasswordField(id='0', label='password', |
|
1940 |
formats=['sha1', 'md5', 'cleartext'])] |
|
1947 |
formats=['sha1', 'md5', 'cleartext', |
|
1948 |
'bcrypt', 'bcrypt_sha256', 'crypt', 'pbkdf2_sha1', 'pbkdf2_sha256', |
|
1949 |
'salted_md5', 'salted_sha1', 'unsalted_md5', 'unsalted_sha1'] |
|
1950 |
if django.VERSION >= (1, 10, 0): |
|
1951 |
try: |
|
1952 |
Argon2PasswordHasher().encode('x', Argon2PasswordHasher().salt()) |
|
1953 |
except ValueError, AttributeError: |
|
1954 |
pass |
|
1955 |
else: |
|
1956 |
formats.append('argon2') |
|
1957 |
formdef.fields = [fields.PasswordField(id='0', label='password', formats=formats)] |
|
1941 | 1958 |
formdef.store() |
1942 | 1959 |
page = app.get('/test/') |
1943 | 1960 |
formdef.data_class().wipe() |
... | ... | |
1954 | 1971 |
assert formdef.data_class().count() == 1 |
1955 | 1972 |
data_id = formdef.data_class().select()[0].id |
1956 | 1973 |
data = formdef.data_class().get(data_id) |
1957 |
assert data.data == {'0': { |
|
1958 |
'sha1': hashlib.sha1(password).hexdigest(), |
|
1959 |
'md5': hashlib.md5(password).hexdigest(), |
|
1960 |
'cleartext': unicode(password, 'utf-8'), |
|
1961 |
}} |
|
1974 |
assert data.data['0']['sha1'] == hashlib.sha1(password).hexdigest() |
|
1975 |
assert data.data['0']['md5'] == hashlib.md5(password).hexdigest() |
|
1976 |
assert data.data['0']['cleartext'] == unicode(password, 'utf-8') |
|
1977 |
assert set(formats) == set(data.data['0'].keys()) |
|
1978 |
for (key, val) in data.data['0'].items(): |
|
1979 |
if key == 'argon2': |
|
1980 |
assert Argon2PasswordHasher().verify(password, val) |
|
1981 |
elif key == 'bcrypt': |
|
1982 |
assert BCryptPasswordHasher().verify(password, val) |
|
1983 |
elif key == 'bcrypt_sha256': |
|
1984 |
assert BCryptSHA256PasswordHasher().verify(password, val) |
|
1985 |
elif key == 'crypt': |
|
1986 |
assert CryptPasswordHasher().verify(password, val) |
|
1987 |
elif key == 'pbkdf2_sha1': |
|
1988 |
assert PBKDF2SHA1PasswordHasher().verify(password, val) |
|
1989 |
elif key == 'pbkdf2_sha256': |
|
1990 |
assert PBKDF2PasswordHasher().verify(password, val) |
|
1991 |
elif key == 'salted_md5': |
|
1992 |
algorithm, salt, hash = val.split('$', 2) |
|
1993 |
assert val == MD5PasswordHasher().encode(password, salt.encode()) |
|
1994 |
elif key == 'salted_sha1': |
|
1995 |
algorithm, salt, hash = val.split('$', 2) |
|
1996 |
assert val == SHA1PasswordHasher().encode(password, salt.encode()) |
|
1997 |
elif key == 'unsalted_md5': |
|
1998 |
assert UnsaltedMD5PasswordHasher().verify(password, val) |
|
1999 |
elif key == 'unsalted_sha1': |
|
2000 |
assert UnsaltedSHA1PasswordHasher().verify(password, val) |
|
1962 | 2001 | |
1963 | 2002 |
def test_form_password_field_submit(pub): |
1964 | 2003 |
user = create_user(pub) |
wcs/fields.py | ||
---|---|---|
28 | 28 |
from quixote import get_request, get_publisher |
29 | 29 |
from quixote.html import htmltext, TemplateIO |
30 | 30 | |
31 |
import django |
|
32 |
if django.VERSION >= (1, 10, 0): |
|
33 |
from django.contrib.auth.hashers import Argon2PasswordHasher |
|
31 | 34 |
from django.utils.encoding import smart_text |
32 | 35 |
from django.utils.formats import date_format as django_date_format |
33 | 36 |
from django.utils.html import urlize |
... | ... | |
2301 | 2304 |
formats = [('cleartext', _('Clear text')), |
2302 | 2305 |
('md5', _('MD5')), |
2303 | 2306 |
('sha1', _('SHA1')), |
2307 |
('bcrypt', _('BCRYPT')), |
|
2308 |
#('bcrypt_sha256', _('BCRYPT SHA256')), |
|
2309 |
('crypt', _('CRYPT')), |
|
2310 |
#('pbkdf2_sha1', _('PBKDF2 SHA1')), |
|
2311 |
('pbkdf2_sha256', _('PBKDF2')), |
|
2312 |
#('salted_md5', _('salted MD5')), |
|
2313 |
('salted_sha1', _('salted SHA1')), |
|
2314 |
#('unsalted_md5', _('unsalted MD5')), |
|
2315 |
#('unsalted_sha1', _('unsalted SHA1')), |
|
2304 | 2316 |
] |
2317 |
if django.VERSION >= (1, 10, 0): |
|
2318 |
try: |
|
2319 |
Argon2PasswordHasher().encode('x', Argon2PasswordHasher().salt()) |
|
2320 |
except ValueError, AttributeError: |
|
2321 |
pass |
|
2322 |
else: |
|
2323 |
formats.append(('argon2', _('ARGON2'))) |
|
2305 | 2324 |
form.add(CheckboxesWidget, 'formats', title=_('Storage formats'), |
2306 | 2325 |
value=self.formats, options=formats, inline=True) |
2307 | 2326 |
form.add(IntWidget, 'min_length', title=_('Minimum length'), |
wcs/qommon/form.py | ||
---|---|---|
65 | 65 |
from django.utils.six.moves.html_parser import HTMLParser |
66 | 66 |
from django.utils.six import StringIO |
67 | 67 | |
68 |
import django |
|
68 | 69 |
from django.conf import settings |
70 |
from django.contrib.auth.hashers import ( |
|
71 |
BCryptPasswordHasher, BCryptSHA256PasswordHasher, CryptPasswordHasher, |
|
72 |
MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, |
|
73 |
SHA1PasswordHasher, UnsaltedMD5PasswordHasher, UnsaltedSHA1PasswordHasher) |
|
74 |
if django.VERSION >= (1, 10, 0): |
|
75 |
from django.contrib.auth.hashers import Argon2PasswordHasher |
|
69 | 76 |
from django.utils.safestring import mark_safe |
70 | 77 | |
71 | 78 |
from .template import render as render_template, Template, TemplateError |
... | ... | |
2180 | 2187 |
self.get_widget('pwd1').set_error(' '.join(set_errors)) |
2181 | 2188 |
pwd1 = None |
2182 | 2189 | |
2190 |
def make_encoder(cls): |
|
2191 |
hasher = cls() |
|
2192 |
def encoder(password): |
|
2193 |
salt = hasher.salt().encode() # encode needed for salted md5 and sha1 |
|
2194 |
return hasher.encode(password, salt) |
|
2195 |
return encoder |
|
2196 | ||
2183 | 2197 |
PASSWORD_FORMATS = { |
2184 | 2198 |
'cleartext': lambda x: x, |
2185 | 2199 |
'md5': lambda x: hashlib.md5(x).hexdigest(), |
2186 | 2200 |
'sha1': lambda x: hashlib.sha1(x).hexdigest(), |
2201 |
'bcrypt': make_encoder(BCryptPasswordHasher), |
|
2202 |
'bcrypt_sha256': make_encoder(BCryptSHA256PasswordHasher), |
|
2203 |
'crypt': make_encoder(CryptPasswordHasher), |
|
2204 |
'pbkdf2_sha1': make_encoder(PBKDF2SHA1PasswordHasher), |
|
2205 |
'pbkdf2_sha256': make_encoder(PBKDF2PasswordHasher), |
|
2206 |
'salted_md5': make_encoder(MD5PasswordHasher), |
|
2207 |
'salted_sha1': make_encoder(SHA1PasswordHasher), |
|
2208 |
'unsalted_md5': make_encoder(UnsaltedMD5PasswordHasher), |
|
2209 |
'unsalted_sha1': make_encoder(UnsaltedSHA1PasswordHasher), |
|
2187 | 2210 |
} |
2211 |
if django.VERSION >= (1, 10, 0): |
|
2212 |
encoder = make_encoder(Argon2PasswordHasher) |
|
2213 |
try: |
|
2214 |
encoder('x') |
|
2215 |
except ValueError, AttributeError: |
|
2216 |
pass |
|
2217 |
else: |
|
2218 |
PASSWORD_FORMATS.update({'argon2': encoder}) |
|
2188 | 2219 | |
2189 | 2220 |
if pwd1: |
2190 | 2221 |
self.value = {} |
2191 |
- |