Skip to content

Commit 3e49151

Browse files
committed
issue 2550880: Ability to choose password store scheme and SSHA support.
Discussion on list is tending in favor of this patch. Embedded test works, my manual test with a SSHA password assigned to a user allowed the user to log in. Ran the test suite and the tests that were not skipped passed.
1 parent d9dd275 commit 3e49151

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

roundup/cgi/form_parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ def parse(self, create=0, num_re=re.compile('^\d+$')):
386386
raise FormError, self._('Password and confirmation text '
387387
'do not match')
388388
try:
389-
value = password.Password(value, config=self.db.config)
389+
value = password.Password(value, scheme = proptype.scheme,
390+
config=self.db.config)
390391
except hyperdb.HyperdbValueError, msg:
391392
raise FormError, msg
392393

roundup/hyperdb.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,15 @@ def sort_repr (self, cls, val, name):
7171

7272
class Password(_Type):
7373
"""An object designating a Password property."""
74+
def __init__(self, scheme=None, required=False, default_value = None):
75+
super(Password, self).__init__(required, default_value)
76+
self.scheme = scheme
77+
7478
def from_raw(self, value, **kw):
7579
if not value:
7680
return None
7781
try:
78-
return password.Password(encrypted=value, strict=True)
82+
return password.Password(encrypted=value, scheme=self.scheme, strict=True)
7983
except password.PasswordValueError, message:
8084
raise HyperdbValueError, \
8185
_('property %s: %s')%(kw['propname'], message)

roundup/password.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
__docformat__ = 'restructuredtext'
2121

2222
import re, string, random
23+
import os
2324
from base64 import b64encode, b64decode
2425
from hashlib import md5, sha1
2526

@@ -81,6 +82,16 @@ def _pbkdf2(password, salt, rounds, keylen):
8182
out += block
8283
return out[:keylen]
8384

85+
def ssha(password, salt):
86+
''' Make ssha digest from password and salt.
87+
Based on code of Roberto Aguilar <[email protected]>
88+
https://gist.github.com/rca/7217540
89+
'''
90+
shaval = sha1(password)
91+
shaval.update( salt )
92+
ssha_digest = b64encode( '{}{}'.format(shaval.digest(), salt) ).strip()
93+
return ssha_digest
94+
8495
def pbkdf2(password, salt, rounds, keylen):
8596
"""pkcs#5 password-based key derivation v2.0
8697
@@ -149,6 +160,16 @@ def encodePassword(plaintext, scheme, other=None, config=None):
149160
raise PasswordValueError, "invalid PBKDF2 hash (rounds too low)"
150161
raw_digest = pbkdf2(plaintext, raw_salt, rounds, 20)
151162
return "%d$%s$%s" % (rounds, salt, h64encode(raw_digest))
163+
elif scheme == 'SSHA':
164+
if other:
165+
raw_other = b64decode(other)
166+
salt = raw_other[20:]
167+
else:
168+
#new password
169+
# variable salt length
170+
salt_len = random.randrange(36, 52)
171+
salt = os.urandom(salt_len)
172+
s = ssha(plaintext, salt)
152173
elif scheme == 'SHA':
153174
s = sha1(plaintext).hexdigest()
154175
elif scheme == 'MD5':
@@ -241,7 +262,7 @@ class Password(JournalPassword):
241262
#TODO: code to migrate from old password schemes.
242263

243264
deprecated_schemes = ["SHA", "MD5", "crypt", "plaintext"]
244-
known_schemes = ["PBKDF2"] + deprecated_schemes
265+
known_schemes = ["PBKDF2", "SSHA"] + deprecated_schemes
245266

246267
def __init__(self, plaintext=None, scheme=None, encrypted=None, strict=False, config=None):
247268
"""Call setPassword if plaintext is not None."""
@@ -319,6 +340,13 @@ def test():
319340
assert 'sekrit' == p
320341
assert 'not sekrit' != p
321342

343+
# SSHA
344+
p = Password('sekrit', 'SSHA')
345+
assert p == 'sekrit'
346+
assert p != 'not sekrit'
347+
assert 'sekrit' == p
348+
assert 'not sekrit' != p
349+
322350
# PBKDF2 - low level function
323351
from binascii import unhexlify
324352
k = pbkdf2("password", "ATHENA.MIT.EDUraeburn", 1200, 32)

0 commit comments

Comments
 (0)