diff --git a/eventman_server.py b/eventman_server.py index b352e9b..8b4be29 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -540,20 +540,37 @@ class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler): class LoginHandler(RootHandler): """Handle user authentication requests.""" + re_split_salt = re.compile(r'\$(?P.+)\$(?P.+)') + @gen.coroutine def get(self, **kwds): with open(self.angular_app_path + "/login.html", 'r') as fd: self.write(fd.read()) + def _authorize(self, username, password): + res = self.db.query('users', {'username': username}) + if not res: + return False + user = res[0] + db_password = user.get('password') or '' + if not db_password: + return False + match = self.re_split_salt.match(db_password) + if not match: + return False + salt = match.group('salt') + if utils.hash_password(password, salt=salt) == db_password: + return True + return False + @gen.coroutine def post(self): username = self.get_body_argument('username') password = self.get_body_argument('password') - if username != 'admin' and password != 'eventman': - self.redirect('/login?failed=1') - else: + if self._authorize(username, password): self.set_secure_cookie("user", username) - self.redirect('/') + self.redirect('/') + self.redirect('/login?failed=1') class LogoutHandler(RootHandler): @@ -592,6 +609,11 @@ def run(): db_connector = backend.EventManDB(url=options.mongodbURL, dbName=options.dbName) init_params = dict(db=db_connector, data_dir=options.data, listen_port=options.port) + # If not present, we store a user 'admin' with password 'eventman' into the database. + if not db_connector.query('users', {'username': 'admin'}): + db_connector.add('users', + {'username': 'admin', 'password': utils.hash_password('eventman')}) + _ws_handler = (r"/ws/+event/+(?P\w+)/+updates/?", WebSocketEventUpdatesHandler) application = tornado.web.Application([ (r"/persons/?(?P\w+)?/?(?P\w+)?/?(?P\w+)?", PersonsHandler, init_params), @@ -600,7 +622,7 @@ def run(): (r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params), (r"/settings", SettingsHandler, init_params), _ws_handler, - (r'/login', LoginHandler), + (r'/login', LoginHandler, init_params), (r'/logout', LogoutHandler), (r'/(.*)', tornado.web.StaticFileHandler, {"path": "angular_app"}) ], diff --git a/utils.py b/utils.py index af40f82..57744b5 100644 --- a/utils.py +++ b/utils.py @@ -18,6 +18,9 @@ limitations under the License. import csv import json +import string +import random +import hashlib import datetime import StringIO from bson.objectid import ObjectId @@ -73,6 +76,14 @@ def csvParse(csvStr, remap=None, merge=None): return reply, results +def hash_password(password, salt=None): + if salt is None: + salt_pool = string.ascii_letters + string.digits + salt = ''.join(random.choice(salt_pool) for x in xrange(32)) + hash_ = hashlib.sha512('%s%s' % (salt, password)) + return '$%s$%s' % (salt, hash_.hexdigest()) + + class ImprovedEncoder(json.JSONEncoder): """Enhance the default JSON encoder to serialize datetime and ObjectId instances.""" def default(self, o):