Mercurial > p > roundup > code
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) |
