minor vers master il y a 5 ans
| @@ -11,6 +11,8 @@ CREATE TABLE users ( | |||||
| state VARCHAR(50), | state VARCHAR(50), | ||||
| postal_code VARCHAR(50), | postal_code VARCHAR(50), | ||||
| country VARCHAR(50), | country VARCHAR(50), | ||||
| login_attempts INT UNSIGNED, | |||||
| last_login_attempt INT UNSIGNED, | |||||
| PRIMARY KEY (userid) | PRIMARY KEY (userid) | ||||
| ); | ); | ||||
| @@ -84,7 +86,7 @@ CREATE TABLE task_files ( | |||||
| * Initial data | * Initial data | ||||
| */ | */ | ||||
| insert into users values (NULL, "admin", "$2b$12$iKbYZ0MFwWWxoYUXKRhFiOPo7itaQO2DIRnLgXbECsj8XKVzkNCSi", "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", 0, 0); | |||||
| 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"); | ||||
| @@ -28,7 +28,7 @@ def set_user(username, password, full_name, company, email, | |||||
| """ | """ | ||||
| db.connect() | db.connect() | ||||
| cursor = db.cursor() | cursor = db.cursor() | ||||
| query = ("INSERT INTO users VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)") | |||||
| query = ("INSERT INTO users VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 0, 0)") | |||||
| try: | try: | ||||
| cursor.execute(query, (username, password, full_name, company, email, street_address, | cursor.execute(query, (username, password, full_name, company, email, street_address, | ||||
| city, state, postal_code, country)) | city, state, postal_code, country)) | ||||
| @@ -12,7 +12,7 @@ def get_user(username): | |||||
| """ | """ | ||||
| db.connect() | db.connect() | ||||
| cursor = db.cursor() | cursor = db.cursor() | ||||
| query = ("SELECT userid, username, password from users where username = %s") | |||||
| query = ("SELECT userid, username, password, login_attempts, last_login_attempt from users where username = %s") | |||||
| user = None | user = None | ||||
| try: | try: | ||||
| cursor.execute(query, (username,)) | cursor.execute(query, (username,)) | ||||
| @@ -51,6 +51,25 @@ def get_users(): | |||||
| return users | return users | ||||
| def set_login_attempts(userid, num, timestamp): | |||||
| """ | |||||
| Set the number and timestamp of the failed login attempts for the given user. | |||||
| """ | |||||
| db.connect() | |||||
| cursor = db.cursor() | |||||
| query = ("UPDATE users SET login_attempts = %s, last_login_attempt = %s WHERE userid = %s") | |||||
| try: | |||||
| cursor.execute(query, (num, timestamp, userid)) | |||||
| db.commit() | |||||
| except mysql.connector.Error as err: | |||||
| print("Failed executing query: {}".format(err)) | |||||
| cursor.fetchall() | |||||
| exit(1) | |||||
| finally: | |||||
| cursor.close() | |||||
| db.close() | |||||
| def get_user_id_by_name(username): | def get_user_id_by_name(username): | ||||
| """ | """ | ||||
| Get the id of the unique username | Get the id of the unique username | ||||
| @@ -14,6 +14,10 @@ render = web.template.render('templates/') | |||||
| # The remember cookie should be valid for a week | # The remember cookie should be valid for a week | ||||
| remember_timeout = 3600*24*7 | remember_timeout = 3600*24*7 | ||||
| # The timeout between login attempts, after the 3rd incorrect one | |||||
| login_timeout = 60 | |||||
| login_attempts_threshold = 2 | |||||
| class Login(): | class Login(): | ||||
| @@ -47,9 +51,22 @@ class Login(): | |||||
| # Validate login credential with database query | # Validate login credential with database query | ||||
| user = models.user.get_user(data.username) | user = models.user.get_user(data.username) | ||||
| if bcrypt.checkpw(data.password.encode('UTF-8'), user[2].encode('UTF-8')): | |||||
| self.login(user[1], user[0], data.remember) | |||||
| if user is None: | |||||
| return render.login(nav, login_form, "- User authentication failed") | |||||
| userid, username, password_hash, login_attempts, last_login_attempt = user | |||||
| if login_attempts > login_attempts_threshold and last_login_attempt + login_timeout > time.time(): | |||||
| return render.login(nav, login_form, "- There have been too many incorrect login attempts for your account. You have to wait a minute before you can log in.") | |||||
| if bcrypt.checkpw(data.password.encode('UTF-8'), password_hash.encode('UTF-8')): | |||||
| models.user.set_login_attempts(userid, 0, time.time()) | |||||
| self.login(username, userid, data.remember) | |||||
| raise web.seeother("/") | raise web.seeother("/") | ||||
| else: | |||||
| models.user.set_login_attempts(userid, login_attempts+1, time.time()) | |||||
| if login_attempts == login_attempts_threshold: | |||||
| return render.login(nav, login_form, "- Too many incorrect login attempts. You have to wait a minute before trying again.") | |||||
| else: | else: | ||||
| return render.login(nav, login_form, "- User authentication failed") | return render.login(nav, login_form, "- User authentication failed") | ||||