from functools import wraps
from flask import Blueprint, Flask, Response, request, url_for, redirect, g, render_template, session, abort, current_app
auth = Blueprint('auth', __name__)
def requires_session(function):
'''
Requires a valid session, provided by cookie!
'''
@wraps(function)
def decorated(*args, **kwargs):
if not session:
#return Response("requires session",401)
return redirect(url_for('auth.login'))
else:
if 'user' not in session:
return Response("User is not in this session.",401)
s_user = session['user']
c_user = request.cookies.get('user')
#print(f"session user: {s_user}")
#print(f"cookie user: {c_user}")
if session['user'] != c_user:
return Response("Wrong user for this session!.",401)
# otherwise, everything is good!
return function(s_user, [], *args,**kwargs)
# catch-all
#return Response("requires session",401)
return redirect(url_for('auth.login'))
return decorated
def _requires_admin_credential(function):
"""
Requires the user pass the correct admin credential configured
in the conf file.
"""
@wraps(function)
def decorated(*args, **kwargs):
# formdata is in session if we are coming from login_basic()
form = session.get('formdata', None)
if form:
session.pop('formdata')
if 'username' in form:
username = form['username']
if 'password' in form:
pw = form['password']
else:
# then we are coming from the form with POST data
if 'username' not in request.form or 'password' not in request.form:
return _unauthorized_admin()
username = request.form['username']
pw = request.form['password']
if 'ADMIN_USERNAME' in current_app.config and \
'ADMIN_PASSWORD' in current_app.config and \
username == current_app.config['ADMIN_USERNAME'] and pw == current_app.config['ADMIN_PASSWORD']:
return function(username, [], *args, **kwargs)
else:
return _unauthorized_admin()
return decorated
def _unauthorized_admin():
return Response(f'Unauthorized! Invalid admin credential... returning to login form', 401)
@auth.route("/logout")
@auth.route("/logout/")
def logout():
resp = Response(f'logged out')
# not documented but is found on the Internet in a few random places:
session.clear()
#resp.set_cookie('user','',expires=0)
return resp
@auth.route("/login/new")
@auth.route("/login/new/")
def login_new():
return redirect(url_for("auth.login", new=""))
@auth.route("/login/", methods=['POST','GET'])
def login(user="None"):
if request.method == "GET":
if 'user' in session and request.cookies.get('user') == session['user'] and (not 'new' in request.args):
return redirect(url_for("admin"))
auth_header = request.headers.get("Authorization")
# default, show login form
return redirect(url_for("auth.login_form"))
elif request.method == "POST":
if request.authorization:
return redirect(url_for("auth.login_basic"),code=307)
return redirect(url_for("auth.login_generic"))
#return f"Authentication method not supported yet.",400
@auth.route("/login/basic",methods=['POST','GET'])
@auth.route("/login/basic/",methods=['POST','GET'])
def login_basic():
if not request.authorization:
return Response(f"Please provide username and password.",401,{'WWW-Authenticate': 'Basic'})
if 'username' not in request.authorization:
return Response(f"No username provided.",401)
if 'password' not in request.authorization:
return Response(f"No password provided.",401)
username = request.authorization.username
pw = request.authorization.password
form={'username':username,'password':pw}
session['formdata'] = form
return redirect(url_for("auth.login_generic"),code=307)
@auth.route("/login/form", methods=['POST','GET'])
@auth.route("/login/form/", methods=['POST','GET'])
def login_form():
if request.method == "GET":
return render_template("login_form.html",
login_url = url_for("auth.login_form")
)
else:
# assume it is a POST
username=""
if 'username' in request.form:
username = request.form['username']
password=""
if 'password' in request.form:
password = request.form['password']
form={'username':username,'password':password}
session['formdata'] = form
return redirect(url_for("auth.login_generic"), code=307)
@auth.route("/login/generic", methods=['POST','GET'])
@auth.route("/login/generic/", methods=['POST','GET'])
@_requires_admin_credential
def login_generic(user,groups=[]):
resp = Response(f'success')
session['user_id'] = "admin"
resp = login_success(session,resp,user,groups)
return resp
def login_success(session,resp,user,groups=[]):
resp.set_cookie('user',user)
session.permanent = True
session['user']=user
return resp