Made saved users be in the DB, not in dict in memory of workers in gunicorn - otherwise we had BUG-39, and also added input validation to username to stop ldap injection on login form

This commit is contained in:
2021-06-26 16:46:26 +10:00
parent 2357ee9a3d
commit 886776f737
2 changed files with 21 additions and 14 deletions

32
main.py
View File

@@ -7,12 +7,10 @@ from wtforms import SubmitField, StringField, HiddenField, SelectField, IntegerF
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from status import st, Status from status import st, Status
from shared import CreateSelect, CreateFoldersSelect, LocationIcon, DB_URL from shared import CreateSelect, CreateFoldersSelect, LocationIcon, DB_URL
from flask_login import login_required, current_user
# for ldap auth # for ldap auth
from flask_ldap3_login import LDAP3LoginManager from flask_ldap3_login import LDAP3LoginManager
from flask_login import LoginManager, login_user, UserMixin, current_user from flask_login import LoginManager, login_user, login_required, UserMixin, current_user
from flask_ldap3_login.forms import LDAPLoginForm from flask_ldap3_login.forms import LDAPLoginForm
import re import re
@@ -49,11 +47,6 @@ login_manager = LoginManager(app) # Setup a Flask-Login Manager
ldap_manager = LDAP3LoginManager(app) # Setup a LDAP3 Login Manager. ldap_manager = LDAP3LoginManager(app) # Setup a LDAP3 Login Manager.
login_manager.login_view = "login" # default login route, failed with url_for, so hard-coded login_manager.login_view = "login" # default login route, failed with url_for, so hard-coded
# Create a dictionary to store the users in when they authenticate
# This example stores users in memory.
users = {}
################################# Now, import non-book classes ################################### ################################# Now, import non-book classes ###################################
from settings import Settings from settings import Settings
@@ -63,6 +56,7 @@ from refimg import Refimg
from job import Job, GetNumActiveJobs from job import Job, GetNumActiveJobs
from ai import aistats from ai import aistats
from path import StoragePathNames from path import StoragePathNames
from user import PAUser
####################################### GLOBALS ####################################### ####################################### GLOBALS #######################################
# allow jinja2 to call these python functions directly # allow jinja2 to call these python functions directly
@@ -98,9 +92,8 @@ class User(UserMixin):
# returns None. # returns None.
@login_manager.user_loader @login_manager.user_loader
def load_user(id): def load_user(id):
if id in users: pau=PAUser.query.filter(PAUser.dn==id).first()
return users[id] return pau
return None
# Declare The User Saver for Flask-Ldap3-Login # Declare The User Saver for Flask-Ldap3-Login
# This method is called whenever a LDAPLoginForm() successfully validates. # This method is called whenever a LDAPLoginForm() successfully validates.
@@ -108,9 +101,14 @@ def load_user(id):
# login controller. # login controller.
@ldap_manager.save_user @ldap_manager.save_user
def save_user(dn, username, data, memberships): def save_user(dn, username, data, memberships):
user = User(dn, username, data) pau=PAUser.query.filter(PAUser.dn==dn).first()
users[dn] = user # if we already have a valid user/session, and say the web has restarted, just re-use it, dont make more users
return user if pau:
return pau
pau=PAUser(dn=dn)
db.session.add(pau)
db.session.commit()
return pau
# default page, just the navbar # default page, just the navbar
@app.route("/", methods=["GET"]) @app.route("/", methods=["GET"])
@@ -129,9 +127,15 @@ def login():
form = LDAPLoginForm() form = LDAPLoginForm()
form.submit.label.text="Login" form.submit.label.text="Login"
# the re matches on any special LDAP chars, we dont want someone
# ldap-injecting our username, so send them back to the login page instead
if request.method == 'POST' and re.search( r'[()\\*&!]', request.form['username']):
print( f"WARNING: Detected special LDAP chars in username: {request.form['username']}")
return redirect('/login')
if form.validate_on_submit(): if form.validate_on_submit():
# Successfully logged in, We can now access the saved user object # Successfully logged in, We can now access the saved user object
# via form.user. # via form.user.
print( f"form user = {form.user}" )
login_user(form.user, remember=True) # Tell flask-login to log them in. login_user(form.user, remember=True) # Tell flask-login to log them in.
next = request.args.get("next") next = request.args.get("next")
if next: if next:

View File

@@ -2,6 +2,8 @@ alter database PA set timezone to 'Australia/Victoria';
create table SETTINGS( ID integer, IMPORT_PATH varchar, STORAGE_PATH varchar, RECYCLE_BIN_PATH varchar, constraint PK_SETTINGS_ID primary key(ID) ); create table SETTINGS( ID integer, IMPORT_PATH varchar, STORAGE_PATH varchar, RECYCLE_BIN_PATH varchar, constraint PK_SETTINGS_ID primary key(ID) );
create table PA_USER( ID integer, dn varchar, constraint PK_PA_USER_ID primary key(ID) );
create table FILE_TYPE ( ID integer, NAME varchar(32) unique, constraint PK_FILE_TYPE_ID primary key(ID) ); create table FILE_TYPE ( ID integer, NAME varchar(32) unique, constraint PK_FILE_TYPE_ID primary key(ID) );
create table PATH_TYPE ( ID integer, NAME varchar(16) unique, constraint PK_PATH_TYPE_ID primary key(ID) ); create table PATH_TYPE ( ID integer, NAME varchar(16) unique, constraint PK_PATH_TYPE_ID primary key(ID) );
@@ -69,6 +71,7 @@ create table PA_JOB_MANAGER_FE_MESSAGE ( ID integer, JOB_ID integer, ALERT varch
constraint PA_JOB_MANAGER_FE_ACKS_ID primary key(ID), constraint PA_JOB_MANAGER_FE_ACKS_ID primary key(ID),
constraint FK_PA_JOB_MANAGER_FE_MESSAGE_JOB_ID foreign key(JOB_ID) references JOB(ID) ); constraint FK_PA_JOB_MANAGER_FE_MESSAGE_JOB_ID foreign key(JOB_ID) references JOB(ID) );
create sequence PA_USER_ID_SEQ;
create sequence PATH_ID_SEQ; create sequence PATH_ID_SEQ;
create sequence PATH_TYPE_ID_SEQ; create sequence PATH_TYPE_ID_SEQ;
create sequence FILE_ID_SEQ; create sequence FILE_ID_SEQ;