ldapweb/webapp/auth.py

71 lines
2.2 KiB
Python

import functools
import ldap
import flask
import urllib
from webapp import app, context, config, ldaputils
bp = flask.Blueprint('auth', __name__)
def login_required(f):
@functools.wraps(f)
def func(*a, **kw):
conn = context.get_connection()
if not conn:
flask.session.clear()
flask.flash('You must log in to continue', category='warning')
return flask.redirect('/login?' + urllib.parse.urlencode({'goto': flask.request.path}))
return f(*a, **kw)
return func
def req_to_ctx():
return dict(flask.request.form.items())
@bp.route('/login', methods=["GET"])
def login_form():
return flask.render_template('login.html', **req_to_ctx())
def _connect_to_ldap(dn, password):
try:
return app.connections.bind(dn, password)
except ldap.LDAPError as error_message:
print("Could not connect to server:", error_message)
return None
@bp.route('/login', methods=["POST"])
def login_action():
# LDAP usernames/DNs are case-insensitive, so we normalize them just in
# case,
username = flask.request.form.get("username", "").lower()
password = flask.request.form.get("password", "")
goto = flask.request.values.get("goto", "/")
dn = ldaputils.user_dn(username)
conn = _connect_to_ldap(dn, password)
if conn:
# Now that we have logged in, we can retrieve the 'real' username (which
# might be cased differently from the login name).
res = conn.search_s(dn, ldap.SCOPE_SUBTREE)
for (k, vs) in res[0][1].items():
if k == 'uid':
username = vs[0].decode()
# Check if user belongs to admin group
is_admin = bool(conn.search_s(dn, ldap.SCOPE_SUBTREE, ldaputils.member_of_any(config.ldap_admin_groups)))
flask.session["username"] = username
flask.session['dn'] = dn
flask.session['is_admin'] = is_admin
context.refresh_profile()
return flask.redirect(goto)
else:
flask.flash("Invalid credentials.", category='danger')
return login_form()
@bp.route('/logout')
@login_required
def logout_action():
app.connections.unbind(flask.session['dn'])
flask.session.clear()
return flask.redirect('/')