comparison roundup/password.py @ 4484:52e13bf0bb40

Add new config-option 'migrate_passwords' in section 'web'... ...to auto-migrate passwords at web-login time. Default for the new option 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.
author Ralf Schlatterbeck <schlatterbeck@users.sourceforge.net>
date Thu, 14 Apr 2011 18:10:58 +0000
parents 22bc0426e348
children 95aace124a8e
comparison
equal deleted inserted replaced
4483:22bc0426e348 4484:52e13bf0bb40
114 114
115 class PasswordValueError(ValueError): 115 class PasswordValueError(ValueError):
116 """ The password value is not valid """ 116 """ The password value is not valid """
117 pass 117 pass
118 118
119 def pbkdf2_unpack(pbkdf2):
120 """ unpack pbkdf2 encrypted password into parts,
121 assume it has format "{rounds}${salt}${digest}
122 """
123 if isinstance(pbkdf2, unicode):
124 pbkdf2 = pbkdf2.encode("ascii")
125 try:
126 rounds, salt, digest = pbkdf2.split("$")
127 except ValueError:
128 raise PasswordValueError, "invalid PBKDF2 hash (wrong number of separators)"
129 if rounds.startswith("0"):
130 raise PasswordValueError, "invalid PBKDF2 hash (zero-padded rounds)"
131 try:
132 rounds = int(rounds)
133 except ValueError:
134 raise PasswordValueError, "invalid PBKDF2 hash (invalid rounds)"
135 raw_salt = h64decode(salt)
136 return rounds, salt, raw_salt, digest
137
119 def encodePassword(plaintext, scheme, other=None): 138 def encodePassword(plaintext, scheme, other=None):
120 """Encrypt the plaintext password. 139 """Encrypt the plaintext password.
121 """ 140 """
122 if plaintext is None: 141 if plaintext is None:
123 plaintext = "" 142 plaintext = ""
124 if scheme == "PBKDF2": 143 if scheme == "PBKDF2":
125 if other: 144 if other:
126 #assume it has format "{rounds}${salt}${digest}" 145 rounds, salt, raw_salt, digest = pbkdf2_unpack(other)
127 if isinstance(other, unicode):
128 other = other.encode("ascii")
129 try:
130 rounds, salt, digest = other.split("$")
131 except ValueError:
132 raise PasswordValueError, "invalid PBKDF2 hash (wrong number of separators)"
133 if rounds.startswith("0"):
134 raise PasswordValueError, "invalid PBKDF2 hash (zero-padded rounds)"
135 try:
136 rounds = int(rounds)
137 except ValueError:
138 raise PasswordValueError, "invalid PBKDF2 hash (invalid rounds)"
139 raw_salt = h64decode(salt)
140 else: 146 else:
141 raw_salt = getrandbytes(20) 147 raw_salt = getrandbytes(20)
142 salt = h64encode(raw_salt) 148 salt = h64encode(raw_salt)
143 #FIXME: find way to access config, so default rounds 149 #FIXME: find way to access config, so default rounds
144 # can be altered for faster/slower hosts via config.ini 150 # can be altered for faster/slower hosts via config.ini
247 else: 253 else:
248 self.scheme = self.default_scheme 254 self.scheme = self.default_scheme
249 self.password = None 255 self.password = None
250 self.plaintext = None 256 self.plaintext = None
251 257
258 def needs_migration(self):
259 """ Password has insecure scheme or other insecure parameters
260 and needs migration to new password scheme
261 """
262 if self.scheme != 'PBKDF2':
263 return True
264 rounds, salt, raw_salt, digest = pbkdf2_unpack(self.password)
265 if rounds < 1000:
266 return True
267 return False
268
252 def unpack(self, encrypted, scheme=None, strict=False): 269 def unpack(self, encrypted, scheme=None, strict=False):
253 """Set the password info from the scheme:<encryted info> string 270 """Set the password info from the scheme:<encryted info> string
254 (the inverse of __str__) 271 (the inverse of __str__)
255 """ 272 """
256 m = self.pwre.match(encrypted) 273 m = self.pwre.match(encrypted)

Roundup Issue Tracker: http://roundup-tracker.org/