summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 226665a)
raw | patch | inline | side by side (parent: 226665a)
author | schlatterbeck <schlatterbeck@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 15 Apr 2011 08:09:59 +0000 (08:09 +0000) | ||
committer | schlatterbeck <schlatterbeck@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 15 Apr 2011 08:09:59 +0000 (08:09 +0000) |
to configure the default parameter for new password generation. Set this
to a higher value on faster systems which want more security. Thanks to
Eli Collins for implementing this (see issue2550688).
This now passes a config object (default None in which case we fall back
to hard-coded parameters) into the password generation routine. This way
we can add further parameters for password generation in the future.
Also added a small regression test for this new feature.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4595 57a73879-2fb5-44c3-a270-3262357dd7e2
to a higher value on faster systems which want more security. Thanks to
Eli Collins for implementing this (see issue2550688).
This now passes a config object (default None in which case we fall back
to hard-coded parameters) into the password generation routine. This way
we can add further parameters for password generation in the future.
Also added a small regression test for this new feature.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4595 57a73879-2fb5-44c3-a270-3262357dd7e2
diff --git a/CHANGES.txt b/CHANGES.txt
index 4fe82cfcbe7d2afca9d908983087054c920534d1..cc011fc6b04e438d8bbe7c695a989b5bf47003e4 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
is "yes" so if you don't want that passwords are auto-migrated to a
more secure password scheme on user login, set this to "no" before
running your tracker(s) after the upgrade.
+- Add new config-option 'password_pbkdf2_default_rounds' in 'main'
+ section to configure the default parameter for new password
+ generation. Set this to a higher value on faster systems which want
+ more security. Thanks to Eli Collins for implementing this (see
+ issue2550688).
2010-10-08 1.4.16 (r4541)
diff --git a/roundup/admin.py b/roundup/admin.py
index 511046df287691d90d12f80ac398ff1ff17cdbe3..1a4e241df277116f00424244eefa5658264f3a4c 100644 (file)
--- a/roundup/admin.py
+++ b/roundup/admin.py
init.write_select_db(tracker_home, backend, tracker.config.DATABASE)
# GO
- tracker.init(password.Password(adminpw))
+ tracker.init(password.Password(adminpw, config=tracker.config))
return 0
diff --git a/roundup/cgi/actions.py b/roundup/cgi/actions.py
index 41f5979467dee8b5dceed43bdc0cd8298dd08fcf..d48fb595eb75514bd47c74a4bd8abbbfefec8466 100755 (executable)
--- a/roundup/cgi/actions.py
+++ b/roundup/cgi/actions.py
if isinstance(prop, hyperdb.Multilink):
value = value.split(':')
elif isinstance(prop, hyperdb.Password):
- value = password.Password(value)
+ value = password.Password(value, config=self.db.config)
elif isinstance(prop, hyperdb.Interval):
value = date.Interval(value)
elif isinstance(prop, hyperdb.Date):
# XXX we need to make the "default" page be able to display errors!
try:
# set the password
- cl.set(uid, password=password.Password(newpw))
+ cl.set(uid, password=password.Password(newpw, config=self.db.config))
# clear the props from the otk database
otks.destroy(otk)
self.db.commit()
stored = db.user.get(userid, 'password')
if givenpw == stored:
if db.config.WEB_MIGRATE_PASSWORDS and stored.needs_migration():
- db.user.set(userid, password=password.Password(givenpw))
+ newpw = password.Password(givenpw, config=db.config)
+ db.user.set(userid, password=newpw)
db.commit()
return 1
if not givenpw and not stored:
index ce6b630be059c8682650aefa8f48e8f6cc1dbb12..b5c5d497a39e306b871bbd956e3b96de02d11796 100755 (executable)
raise FormError, self._('Password and confirmation text '
'do not match')
try:
- value = password.Password(value)
+ value = password.Password(value, config=self.db.config)
except hyperdb.HyperdbValueError, msg:
raise FormError, msg
index 9a8d165c60e549f76b15b56852078705082f89f2..aa5ab850556f8f9d6167be86a6048ebf1973d09f 100644 (file)
--- a/roundup/configuration.py
+++ b/roundup/configuration.py
"starting with python 2.5. Set this to a higher value if you\n"
"get the error 'Error: field larger than field limit' during\n"
"import."),
+ (IntegerNumberOption, 'password_pbkdf2_default_rounds', '10000',
+ "Sets the default number of rounds used when encoding passwords\n"
+ "using the PBKDF2 scheme. Set this to a higher value on faster\n"
+ "systems which want more security."),
)),
("tracker", (
(Option, "name", "Roundup issue tracker",
diff --git a/roundup/mailgw.py b/roundup/mailgw.py
index 922dc12656a8d6dafc601aba82223b97fad1a32c..1664484c12081791864a7cf05eea35c6e9eb6118 100644 (file)
--- a/roundup/mailgw.py
+++ b/roundup/mailgw.py
try:
return db.user.create(username=trying, address=address,
realname=realname, roles=db.config.NEW_EMAIL_USER_ROLES,
- password=password.Password(password.generatePassword()),
+ password=password.Password(password.generatePassword(), config=db.config),
**user_props)
except exceptions.Reject:
return 0
diff --git a/roundup/password.py b/roundup/password.py
index adb2cc4c5e1b6353076c497fea8ab2e3d49da518..eab300775b9c8a7869904c08aebc21d528f69160 100644 (file)
--- a/roundup/password.py
+++ b/roundup/password.py
raw_salt = h64decode(salt)
return rounds, salt, raw_salt, digest
-def encodePassword(plaintext, scheme, other=None):
+def encodePassword(plaintext, scheme, other=None, config=None):
"""Encrypt the plaintext password.
"""
if plaintext is None:
else:
raw_salt = getrandbytes(20)
salt = h64encode(raw_salt)
- #FIXME: find way to access config, so default rounds
- # can be altered for faster/slower hosts via config.ini
- rounds = 10000
+ if config:
+ rounds = config.PASSWORD_PBKDF2_DEFAULT_ROUNDS
+ else:
+ rounds = 10000
if rounds < 1000:
raise PasswordValueError, "invalid PBKDF2 hash (rounds too low)"
raw_digest = pbkdf2(plaintext, raw_salt, rounds, 20)
deprecated_schemes = ["SHA", "MD5", "crypt", "plaintext"]
known_schemes = ["PBKDF2"] + deprecated_schemes
- def __init__(self, plaintext=None, scheme=None, encrypted=None, strict=False):
+ def __init__(self, plaintext=None, scheme=None, encrypted=None, strict=False, config=None):
"""Call setPassword if plaintext is not None."""
if scheme is None:
scheme = self.default_scheme
if plaintext is not None:
- self.setPassword (plaintext, scheme)
+ self.setPassword (plaintext, scheme, config=config)
elif encrypted is not None:
- self.unpack(encrypted, scheme, strict=strict)
+ self.unpack(encrypted, scheme, strict=strict, config=config)
else:
self.scheme = self.default_scheme
self.password = None
return True
return False
- def unpack(self, encrypted, scheme=None, strict=False):
+ def unpack(self, encrypted, scheme=None, strict=False, config=None):
"""Set the password info from the scheme:<encryted info> string
(the inverse of __str__)
"""
self.plaintext = None
else:
# currently plaintext - encrypt
- self.setPassword(encrypted, scheme)
+ self.setPassword(encrypted, scheme, config=config)
if strict and self.scheme not in self.known_schemes:
raise PasswordValueError, "unknown encryption scheme: %r" % (self.scheme,)
- def setPassword(self, plaintext, scheme=None):
+ def setPassword(self, plaintext, scheme=None, config=None):
"""Sets encrypts plaintext."""
if scheme is None:
scheme = self.default_scheme
self.scheme = scheme
- self.password = encodePassword(plaintext, scheme)
+ self.password = encodePassword(plaintext, scheme, config=config)
self.plaintext = plaintext
def __str__(self):
diff --git a/test/test_cgi.py b/test/test_cgi.py
index 2d63ed4c26df63cb442ecfdcc4dbd933ad219981..7fbe89ce442440091c434b23a51bff5a84ffe755 100644 (file)
--- a/test/test_cgi.py
+++ b/test/test_cgi.py
self.assertEqual(pw, 'foo')
self.assertEqual(pw, pw1)
+ def testPasswordConfigOption(self):
+ chef = self.db.user.lookup('Chef')
+ form = dict(__login_name='Chef', __login_password='foo')
+ cl = self._make_client(form)
+ self.db.config.PASSWORD_PBKDF2_DEFAULT_ROUNDS = 1000
+ pw1 = password.Password('foo', scheme='crypt')
+ self.assertEqual(pw1.needs_migration(), True)
+ self.db.user.set(chef, password=pw1)
+ self.db.commit()
+ actions.LoginAction(cl).handle()
+ pw = self.db.user.get(chef, 'password')
+ self.assertEqual('PBKDF2', pw.scheme)
+ self.assertEqual(1000, password.pbkdf2_unpack(pw.password)[0])
+
#
# Boolean
#