Browse Source

hash with salt

Davide Alberani 9 years ago
parent
commit
46bc6fb9f7
2 changed files with 38 additions and 5 deletions
  1. 27 5
      eventman_server.py
  2. 11 0
      utils.py

+ 27 - 5
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<salt>.+)\$(?P<hash>.+)')
+
     @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<event_id>\w+)/+updates/?", WebSocketEventUpdatesHandler)
     application = tornado.web.Application([
             (r"/persons/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\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"})
         ],

+ 11 - 0
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):