aboutsummaryrefslogtreecommitdiff
path: root/stackbin.py
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2022-02-15 16:44:06 -0500
committerB Stack <bgstack15@gmail.com>2022-02-15 16:44:06 -0500
commitbee4591ac60f8f3bd85c2f2b12dc75e09e2c97d7 (patch)
tree053806ad9cb454717d362704184c9d6c8cf6ac85 /stackbin.py
parentpw-protect /admin endpoint (diff)
downloadstackbin-bee4591ac60f8f3bd85c2f2b12dc75e09e2c97d7.tar.gz
stackbin-bee4591ac60f8f3bd85c2f2b12dc75e09e2c97d7.tar.bz2
stackbin-bee4591ac60f8f3bd85c2f2b12dc75e09e2c97d7.zip
split auth into separate python file
Flask can use Blueprint to load paths from two separate source files, so the endpoints and logic can be grouped logically.
Diffstat (limited to 'stackbin.py')
-rwxr-xr-xstackbin.py146
1 files changed, 7 insertions, 139 deletions
diff --git a/stackbin.py b/stackbin.py
index 30b9066..56380e6 100755
--- a/stackbin.py
+++ b/stackbin.py
@@ -20,12 +20,12 @@
# Documentation: see README.md
from datetime import datetime, timedelta
from itsdangerous import Signer
-from flask import (Flask, Response, request, url_for, redirect, g, render_template, session, abort)
+from flask import Blueprint, Flask, Response, request, url_for, redirect, g, render_template, session, abort, current_app
from flask_sqlalchemy import SQLAlchemy
from werkzeug.middleware.proxy_fix import ProxyFix
from pytimeparse.timeparse import timeparse # python3-pytimeparse
import os
-from functools import wraps
+from stackbin_auth import auth, requires_session
# uwsgidecorators load will fail when using initdb.py but is also not necessary
try:
from uwsgidecorators import timer # python3-uwsgidecorators
@@ -68,6 +68,7 @@ def get_unsigned(string, salt="blank"):
return Signer(app.secret_key, salt=salt).unsign(str(string)).decode("utf-8")
app = Flask(__name__)
+app.register_blueprint(auth) # url_prefix='/'
try:
app.config.from_pyfile(os.environ['STACKBIN_CONF'])
except:
@@ -78,64 +79,6 @@ if "STATIC_FOLDER" in app.config:
if "TEMPLATE_FOLDER" in app.config:
app.template_folder=app.config["TEMPLATE_FOLDER"]
-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('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('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 app.config and \
- 'ADMIN_PASSWORD' in app.config and \
- username == app.config['ADMIN_USERNAME'] and pw == app.config['ADMIN_PASSWORD']:
- return function(username, [], *args, **kwargs)
- else:
- return _unauthorized_admin()
-
- return decorated
-
-def _unauthorized_admin():
- return Response(f'<meta http-equiv="Refresh" content="4; url={url_for("login")}">Unauthorized! Invalid admin credential... returning to login form', 401)
-
def url_for_other_page(page):
args = request.view_args.copy()
args['page'] = page
@@ -377,86 +320,11 @@ def get_proxied_path():
app.wsgi_app = ProxyFix(app.wsgi_app,x_for=pl,x_host=pl,x_port=pl,x_prefix=pl,x_proto=pl)
return redirect(url_for('new_paste'))
-@app.route("/logout")
+# stubs, to simplify any templates that ask url_for("login")
+@app.route('/login/')
+def login(user="None"): True
@app.route("/logout/")
-def logout():
- resp = Response(f'<meta http-equiv="Refresh" content="1; url={url_for("new_paste")}">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
-
-@app.route("/login/new")
-@app.route("/login/new/")
-def login_new():
- return redirect(url_for("login", new=""))
-@app.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("login_form"))
- elif request.method == "POST":
- if request.authorization:
- return redirect(url_for("login_basic"),code=307)
- return redirect(url_for("login_generic"))
- #return f"Authentication method not supported yet.",400
-
-@app.route("/login/basic",methods=['POST','GET'])
-@app.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("login_generic"),code=307)
-
-@app.route("/login/form", methods=['POST','GET'])
-@app.route("/login/form/", methods=['POST','GET'])
-def login_form():
- if request.method == "GET":
- return render_template("login_form.html",
- login_url = url_for("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("login_generic"), code=307)
-
-@app.route("/login/generic", methods=['POST','GET'])
-@app.route("/login/generic/", methods=['POST','GET'])
-@requires_admin_credential
-def login_generic(user,groups=[]):
- resp = Response(f'<meta http-equiv="Refresh" content="1; url={url_for("admin")}">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)
- #end_time = datetime.datetime.now(datetime.timezone.utc) + app.permanent_session_lifetime
- #end_time_str = datetime.datetime.strftime(end_time,"%FT%TZ")
- #resp.set_cookie('timestamp',end_time_str)
- session.permanent = True
- session['user']=user
- #session['end_time'] = end_time_str
- print(f"DEBUG: got valid user {user}")
- return resp
+def logout(): True
# Initialize the database if it does not already exist
db.create_all()
bgstack15