aboutsummaryrefslogtreecommitdiff
path: root/stackbin_auth.py
blob: 34629803ef10af5e2f143aab506b946079ecec63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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'<meta http-equiv="Refresh" content="4; url={url_for("auth.login")}">Unauthorized! Invalid admin credential... returning to login form', 401)

@auth.route("/logout")
@auth.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

@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'<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)
   session.permanent = True
   session['user']=user
   return resp
bgstack15