diff options
Diffstat (limited to 'session_app.py.publish')
-rwxr-xr-x | session_app.py.publish | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/session_app.py.publish b/session_app.py.publish new file mode 100755 index 0000000..915693a --- /dev/null +++ b/session_app.py.publish @@ -0,0 +1,190 @@ +#!/usr/bin/env python +# Startdate: 2021-06-17 +# goals: +# accept kerberos or ldap "authorization: basic gowinablz;nuiowekj==" auth, to create a cookie for a session that lasts for 15 minutes. use the cookie to get to protected URLs +# References: +# https://code.tutsplus.com/tutorials/flask-authentication-with-ldap--cms-23101 +# https://www.techlifediary.com/python-web-development-tutorial-using-flask-session-cookies/ +# delete cookie https://stackoverflow.com/a/14386413/3569534 +# timeout sessions https://stackoverflow.com/a/11785722/3569534 +# future: https://code.tutsplus.com/tutorials/flask-authentication-with-ldap--cms-23101 +# better timeout session: https://stackoverflow.com/a/49891626/3569534 +# Improve: +# purge sessions after 15 minutes? +# Run: +# FLASK_APP=session_app.py FLASK_DEBUG=1 flask run --host 0.0.0.0 +# Dependencies: +# apt-get install python3-flask +# pip3 install Flask-kerberos kerberos + +from flask import Flask, Response, redirect, url_for, render_template, request + +from flask_kerberos import init_kerberos, requires_authentication, _unauthorized, _forbidden, _gssapi_authenticate +from flask import _request_ctx_stack as stack, make_response, session +#from flask.ext.login import LoginManager +import kerberos +from functools import wraps +from socket import gethostname +import binascii, datetime + +from functools import wraps +import os + +DEBUG=True +app = Flask(__name__) +app.config.from_object(__name__) +app.debug=True +secret_key_value = os.urandom(24) +secret_key_value_hex_encoded = binascii.hexlify(secret_key_value) +app.config['SECRET_KEY'] = secret_key_value_hex_encoded +#app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=7) +#session.permanent = True +minutes = 2 +app.permanent_session_lifetime=datetime.timedelta(minutes=minutes) + +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) + 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 Response(f"session user: {s_user}<br/>cookie user: {c_user}", 200) + # return to the passed function, from https://github.com/ArtemAngelchev/flask-basicauth-ldap/blob/master/flask_basicauth_ldap.py + return function(*args,**kwargs) + # catch-all + return Response("requires session",401) + return decorated + +# imported from flask_kerberos and modified, because I want custom 401 message +def requires_authn_kerberos(function): + ''' + Require that the wrapped view function only be called by users + authenticated with Kerberos. The view function will have the authenticated + users principal passed to it as its first argument. + + :param function: flask view function + :type function: function + :returns: decorated function + :rtype: function + ''' + @wraps(function) + def decorated(*args, **kwargs): + header = request.headers.get("Authorization") + if header: + ctx = stack.top + token = ''.join(header.split()[1:]) + rc = _gssapi_authenticate(token) + if rc == kerberos.AUTH_GSS_COMPLETE: + response = function(ctx.kerberos_user, *args, **kwargs) + response = make_response(response) + if ctx.kerberos_token is not None: + response.headers['WWW-Authenticate'] = ' '.join(['negotiate', ctx.kerberos_token]) + return response + elif rc != kerberos.AUTH_GSS_CONTINUE: + return _forbidden() + return _unauthorized_kerberos() + return decorated + +def _unauthorized_kerberos(): + ''' + Indicate that authentication is required + ''' + # from https://billstclair.com/html-redirect2.html + return Response(f'<meta http-equiv="Refresh" content="4; url={url_for("login_ldap")}">Unauthorized! No kerberos auth provided. Trying <a href="{url_for("login_ldap")}">ldap</a> automatically in a moment.', 401, {'WWW-Authenticate': 'Negotiate'}) + +@app.route("/") +def index(): + return render_template('index.html') + +@app.route("/open/") +def open(): + header = request.headers.get("Authorization") + if header: + print("Header!") + token = ''.join(header.split()[1:]) + print("token",token) + print("something") + return "<html><body>here</body></html>", 200 + +@app.route("/protected/") +@requires_session +def protected_page(): + return protected_page_real() + +def protected_page_real(): + s_user = session['user'] + c_user = request.cookies.get('user') + cookie=request.cookies + print(cookie) + return render_template('view.html', c_user = c_user, s_user=s_user, cookie=cookie) + +@app.route("/login/") +#@requires_authn_kerberos +def login(user="None"): + # prefer kerberos + return redirect(url_for("login_kerberos")) + +@app.route("/login/kerberos") +@requires_authn_kerberos +def login_kerberos(user): + resp = Response(f'<meta http-equiv="Refresh" content="1; url={url_for("protected_page")}">success with kerberos') + #resp.headers['login'] = "from-kerberos" + resp.set_cookie('user',user) + resp.set_cookie('type',"kerberos") + 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 + return resp + +# WORKHERE: ldap auth +# WIP 2021-06-18 17:42; make this unauthenticated GET send to a form. +@app.route("/login/ldap", methods=['POST','GET']) +#@app.route("/login/ldap/<user>") +def login_ldap(user = "none"): + resp = Response(f"success, from user {user}") + resp.headers['login'] = "from-ldap" + resp.set_cookie('user',user) + resp.set_cookie('type',"ldap") + session['user']=user + resp.set_cookie('timestamp',app.permanent_session_lifetime) + return resp + +@app.route("/logout") +def logout(): + resp = Response(f"logged out") + # Doing anything with session here leaves a cookie. + #session['user']="" + resp.set_cookie('user','',expires=0) + resp.set_cookie('type','',expires=0) + resp.set_cookie('session','',expires=0) + resp.set_cookie('timestamp','',expires=0) + return resp + +## This bumps the session lifetime to two minutes farther out from each web request with this session. +#@app.before_request +#def make_session_permanent(): +# session.permanent = True +# session['end_time'] = datetime.datetime.now()+app.permanent_session_lifetime + +# keytab from `/usr/sbin/ipa-getkeytab -p HTTP/d2-03a.ipa.example.com -k session.keytab` +os.environ['KRB5_KTNAME'] = "./session.keytab" +os.environ['KRB5_TRACE'] = "./kerberos.log" +init_kerberos(app, hostname="d2-03a.ipa.internal.com", service="HTTP") +if __name__ == '__main__': + init_kerberos(app, hostname="d2-03a.ipa.internal.com", service="HTTP") + app.run(host='0.0.0.0',debug=True) |