The new scheme uses bcrypt and a random salt for each user. This is not compatible with old passwords. Fixes #13pull/34/head
| @@ -2,7 +2,7 @@ | |||||
| CREATE TABLE users ( | CREATE TABLE users ( | ||||
| userid INT UNSIGNED AUTO_INCREMENT, | userid INT UNSIGNED AUTO_INCREMENT, | ||||
| username VARCHAR(45) UNIQUE NOT NULL, | username VARCHAR(45) UNIQUE NOT NULL, | ||||
| password VARCHAR(45) NOT NULL, | |||||
| password VARCHAR(60) NOT NULL, | |||||
| full_name VARCHAR(200) NOT NULL, | full_name VARCHAR(200) NOT NULL, | ||||
| company VARCHAR(50), | company VARCHAR(50), | ||||
| email VARCHAR(50) NOT NULL, | email VARCHAR(50) NOT NULL, | ||||
| @@ -84,7 +84,7 @@ CREATE TABLE task_files ( | |||||
| * Initial data | * Initial data | ||||
| */ | */ | ||||
| insert into users values (NULL, "admin", "48bead1bb864138c2cafaf1bd41332ab", "Admin Modsen", "ntnu", 'mail@ntnu.no', "street", "trondheim", "trondheim", "1234", "norway"); | |||||
| insert into users values (NULL, "admin", "$2b$12$iKbYZ0MFwWWxoYUXKRhFiOPo7itaQO2DIRnLgXbECsj8XKVzkNCSi", "Admin Modsen", "ntnu", 'mail@ntnu.no', "street", "trondheim", "trondheim", "1234", "norway"); | |||||
| insert into project_category values (NULL, "Gardening"); | insert into project_category values (NULL, "Gardening"); | ||||
| insert into project_category values (NULL, "Programming"); | insert into project_category values (NULL, "Programming"); | ||||
| @@ -2,6 +2,33 @@ from models.database import db | |||||
| import mysql.connector | import mysql.connector | ||||
| def get_user(username): | |||||
| """ | |||||
| Get the user with the given username | |||||
| :param username: The username | |||||
| :type username: str | |||||
| :return: user | |||||
| """ | |||||
| db.connect() | |||||
| cursor = db.cursor() | |||||
| query = ("SELECT userid, username, password from users where username = %s") | |||||
| user = None | |||||
| try: | |||||
| cursor.execute(query, (username,)) | |||||
| users = cursor.fetchall() | |||||
| if len(users): | |||||
| user = users[0] | |||||
| except mysql.connector.Error as err: | |||||
| print("Failed executing query: {}".format(err)) | |||||
| cursor.fetchall() | |||||
| exit(1) | |||||
| finally: | |||||
| cursor.close() | |||||
| db.close() | |||||
| return user | |||||
| def get_users(): | def get_users(): | ||||
| """ | """ | ||||
| Retreive all registrered users from the database | Retreive all registrered users from the database | ||||
| @@ -73,32 +100,3 @@ def get_user_name_by_id(userid): | |||||
| cursor.close() | cursor.close() | ||||
| db.close() | db.close() | ||||
| return username | return username | ||||
| def match_user(username, password): | |||||
| """ | |||||
| Check if user credentials are correct, return if exists | |||||
| :param username: The user attempting to authenticate | |||||
| :param password: The corresponding password | |||||
| :type username: str | |||||
| :type password: str | |||||
| :return: user | |||||
| """ | |||||
| db.connect() | |||||
| cursor = db.cursor() | |||||
| query = ("SELECT userid, username from users where username = %s and password = %s") | |||||
| user = None | |||||
| try: | |||||
| cursor.execute(query, (username, password)) | |||||
| users = cursor.fetchall() | |||||
| if len(users): | |||||
| user = users[0] | |||||
| except mysql.connector.Error as err: | |||||
| print("Failed executing query: {}".format(err)) | |||||
| cursor.fetchall() | |||||
| exit(1) | |||||
| finally: | |||||
| cursor.close() | |||||
| db.close() | |||||
| return user | |||||
| @@ -1,3 +1,4 @@ | |||||
| web.py==0.40 | web.py==0.40 | ||||
| mysql-connector-python==8.0.* | mysql-connector-python==8.0.* | ||||
| python-dotenv | python-dotenv | ||||
| bcrypt | |||||
| @@ -5,7 +5,7 @@ import models.session | |||||
| import models.user | import models.user | ||||
| import random | import random | ||||
| import string | import string | ||||
| import hashlib | |||||
| import bcrypt | |||||
| import time | import time | ||||
| # Get html templates | # Get html templates | ||||
| @@ -45,11 +45,9 @@ class Login(): | |||||
| data = web.input(username="", password="", remember=False) | data = web.input(username="", password="", remember=False) | ||||
| # Validate login credential with database query | # Validate login credential with database query | ||||
| password_hash = hashlib.md5(b'TDT4237' + data.password.encode('utf-8')).hexdigest() | |||||
| user = models.user.match_user(data.username, password_hash) | |||||
| user = models.user.get_user(data.username) | |||||
| # If there is a matching user/password in the database the user is logged in | |||||
| if user: | |||||
| if bcrypt.checkpw(data.password.encode('UTF-8'), user[2].encode('UTF-8')): | |||||
| self.login(user[1], user[0], data.remember) | self.login(user[1], user[0], data.remember) | ||||
| raise web.seeother("/") | raise web.seeother("/") | ||||
| else: | else: | ||||
| @@ -3,7 +3,7 @@ from views.forms import register_form | |||||
| from views.utils import get_nav_bar, csrf_protected | from views.utils import get_nav_bar, csrf_protected | ||||
| import models.register | import models.register | ||||
| import models.user | import models.user | ||||
| import hashlib | |||||
| import bcrypt | |||||
| import re | import re | ||||
| # Get html templates | # Get html templates | ||||
| @@ -41,9 +41,10 @@ class Register: | |||||
| if models.user.get_user_id_by_name(data.username): | if models.user.get_user_id_by_name(data.username): | ||||
| return render.register(nav, register, "Invalid user, already exists.") | return render.register(nav, register, "Invalid user, already exists.") | ||||
| models.register.set_user(data.username, | |||||
| hashlib.md5(b'TDT4237' + data.password.encode('utf-8')).hexdigest(), | |||||
| data.full_name, data.company, data.email, data.street_address, | |||||
| data.city, data.state, data.postal_code, data.country) | |||||
| password_hash = bcrypt.hashpw(data.password.encode('UTF-8'), bcrypt.gensalt()) | |||||
| models.register.set_user(data.username, password_hash, data.full_name, data.company, | |||||
| data.email, data.street_address, data.city, data.state, | |||||
| data.postal_code, data.country) | |||||
| return render.register(nav, register_form, "User registered!") | return render.register(nav, register_form, "User registered!") | ||||