From 1e87406fdb4cbb747c566d77a35cc976d5431b06 Mon Sep 17 00:00:00 2001 From: Simon Pirkelmann Date: Mon, 22 Mar 2021 21:22:51 +0100 Subject: [PATCH] added LDAP authorization --- bin/launch_webadmin | 3 ++- imaginaerraum_door_admin/webapp.py | 34 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/bin/launch_webadmin b/bin/launch_webadmin index d110a46..bb1c1d1 100755 --- a/bin/launch_webadmin +++ b/bin/launch_webadmin @@ -3,13 +3,14 @@ import argparse from imaginaerraum_door_admin.webapp import create_application - parser = argparse.ArgumentParser() parser.add_argument("--token_file", default="/etc/door_tokens", help="path to the file with door tokens and users") parser.add_argument("--nfc_socket", default="/tmp/nfc.sock", help="socket for handling NFC reader commands") parser.add_argument("--template_folder", default="templates", help="path to Flask templates folder") parser.add_argument("--static_folder", default="static", help="path to Flask static folder") parser.add_argument("--admin_file", help="Path to file for creating initial admin users") +parser.add_argument("--ldap_url", default="ldaps://do.imaginaerraum.de", + help="URL for LDAP server for alternative user authorization") parser.add_argument("--mqtt_host", default="10.10.21.2", help="IP address of MQTT broker") parser.add_argument("--port", default=80, help="Port for running the Flask server") parser.add_argument("--mail_server", default="smtp.googlemail.com", help="email server for sending security messages") diff --git a/imaginaerraum_door_admin/webapp.py b/imaginaerraum_door_admin/webapp.py index 0cc77e3..dc24c0e 100644 --- a/imaginaerraum_door_admin/webapp.py +++ b/imaginaerraum_door_admin/webapp.py @@ -9,8 +9,10 @@ from flask_security import Security, SQLAlchemyUserDatastore, auth_required, has from flask_security.models import fsqla_v2 as fsqla from flask_security.forms import LoginForm, Required, PasswordField from flask_mail import Mail +from flask_security.utils import find_user from email_validator import validate_email import bleach +import ldap3 from datetime import date from .door_handle import DoorHandle @@ -96,10 +98,42 @@ def create_application(config): class User(db.Model, fsqla.FsUserMixin): username = db.Column(db.String(255)) + # LDAP + ldap_server = ldap3.Server(config.ldap_url) + + def validate_ldap(user, password): + # try to connect to the LDAP server + # if the connection completes successfully the given user and password is authorized + try: + con = ldap3.Connection(ldap_server, user="uid=%s,ou=Users,dc=imaginaerraum,dc=de" % (user.username,), + password=password, auto_bind=True) + except Exception: + return False + return con is not None + class ExtendedLoginForm(LoginForm): email = StringField('Benutzername oder E-Mail', [Required()]) password = PasswordField('Passwort', [Required()]) + def validate(self): + # authorization in LDAP uses username -> get username associated with email from the database + user = find_user(self.email.data) + # try authorizing using LDAP + response_ldap = validate_ldap(user, self.password.data) + + if response_ldap: + # if LDAP authorization succeeds we update the currently stored password in the Flask user datastore + # with the one used for LDAP authorization. This way we can authorize with the LDAP password later + # even if the server is not reachable + user.password = hash_password(self.password.data) + + # try authorizing using Flask security + response_orig = super(ExtendedLoginForm, self).validate() + + # if any of the authorization methods is successful we authorize the user + return response_ldap or response_orig + + app.config['SECURITY_MSG_USERID_NOT_PROVIDED'] = ('User ID not provided', 'error') # Setup Flask-Security user_datastore = SQLAlchemyUserDatastore(db, User, Role)