Generate the salt used for hashing user passwords individually for each server instance

This commit is contained in:
Gina Häußge 2014-10-27 09:35:55 +01:00
parent b4699825d6
commit ce67e28f96
4 changed files with 42 additions and 4 deletions

View file

@ -8,6 +8,7 @@
server start and written back into ``config.yaml``
* Event subscriptions are now enabled by default (it was an accident that they weren't)
* Generate the key used for session hashing individually for each server instance
* Generate the salt used for hashing user passwords individually for each server instance
### Bug Fixes

View file

@ -120,7 +120,7 @@ def login():
user = octoprint.server.userManager.findUser(username)
if user is not None:
if user.check_password(octoprint.users.UserManager.createPasswordHash(password)):
if octoprint.server.userManager.checkPassword(username, password):
login_user(user, remember=remember)
identity_changed.send(current_app._get_current_object(), identity=Identity(user.get_id()))
return jsonify(user.asDict())

View file

@ -114,6 +114,7 @@ default_settings = {
},
"accessControl": {
"enabled": True,
"salt": None,
"userManager": "octoprint.users.FilebasedUserManager",
"userfile": None,
"autologinLocal": False,

View file

@ -1,6 +1,9 @@
# coding=utf-8
from __future__ import absolute_import
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms of the AGPLv3 License"
from flask.ext.login import UserMixin
from flask.ext.principal import Identity
@ -15,8 +18,38 @@ class UserManager(object):
valid_roles = ["user", "admin"]
@staticmethod
def createPasswordHash(password):
return hashlib.sha512(password + "mvBUTvwzBzD3yPwvnJ4E4tXNf3CGJvvW").hexdigest()
def createPasswordHash(password, salt=None):
if not salt:
salt = settings().get(["accessControl", "salt"])
if salt is None:
import string
from random import choice
chars = string.ascii_lowercase + string.ascii_uppercase + string.digits
salt = "".join(choice(chars) for _ in xrange(32))
settings().set(["accessControl", "salt"], salt)
settings().save()
return hashlib.sha512(password + salt).hexdigest()
def checkPassword(self, username, password):
user = self.findUser(username)
if not user:
return False
hash = UserManager.createPasswordHash(password)
if user.check_password(hash):
# new hash matches, correct password
return True
else:
# new hash doesn't match, but maybe the old one does, so check that!
oldHash = UserManager.createPasswordHash(password, salt="mvBUTvwzBzD3yPwvnJ4E4tXNf3CGJvvW")
if user.check_password(oldHash):
# old hash matches, we migrate the stored password hash to the new one and return True since it's the correct password
self.changeUserPassword(username, password)
return True
else:
# old hash doesn't match either, wrong password
return False
def addUser(self, username, password, active, roles):
pass
@ -97,7 +130,10 @@ class FilebasedUserManager(UserManager):
self._dirty = False
self._load()
def addUser(self, username, password, active=False, roles=["user"], apikey=None):
def addUser(self, username, password, active=False, roles=None, apikey=None):
if not roles:
roles = ["user"]
if username in self._users.keys():
raise UserAlreadyExists(username)