2020-10-15 19:58:56 +00:00
|
|
|
import ssl
|
2020-09-03 22:55:23 +00:00
|
|
|
from ldap3.utils.hashed import hashed
|
2020-10-15 19:58:56 +00:00
|
|
|
from ldap3 import SUBTREE, MODIFY_REPLACE, HASHED_SALTED_SHA512
|
|
|
|
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError
|
2020-08-23 21:58:26 +00:00
|
|
|
from flask import current_app as app
|
2020-08-25 02:36:05 +00:00
|
|
|
from flask_ldapconn import LDAPConn
|
2020-10-15 19:58:56 +00:00
|
|
|
from werkzeug.exceptions import BadRequest
|
2020-08-25 02:36:05 +00:00
|
|
|
|
2020-10-15 19:58:56 +00:00
|
|
|
from flaschengeist.modules import AuthPlugin
|
2020-09-03 22:55:23 +00:00
|
|
|
from flaschengeist.system.models.user import User
|
|
|
|
|
2020-09-01 23:09:24 +00:00
|
|
|
|
2020-10-15 19:58:56 +00:00
|
|
|
class AuthLDAP(AuthPlugin):
|
|
|
|
def __init__(self, config):
|
|
|
|
super().__init__()
|
2020-08-23 21:58:26 +00:00
|
|
|
|
2020-10-15 19:58:56 +00:00
|
|
|
defaults = {"PORT": "389", "USE_SSL": "False"}
|
|
|
|
for name in defaults:
|
2020-08-25 02:36:05 +00:00
|
|
|
if name not in config:
|
2020-10-15 19:58:56 +00:00
|
|
|
config[name] = defaults[name]
|
2020-08-25 02:36:05 +00:00
|
|
|
|
2020-08-23 21:58:26 +00:00
|
|
|
app.config.update(
|
2020-09-01 23:09:24 +00:00
|
|
|
LDAP_SERVER=config["URL"],
|
|
|
|
LDAP_PORT=config.getint("PORT"),
|
|
|
|
LDAP_BINDDN=config["BINDDN"],
|
|
|
|
LDAP_USE_TLS=False,
|
|
|
|
LDAP_USE_SSL=config.getboolean("USE_SSL"),
|
|
|
|
LDAP_TLS_VERSION=ssl.PROTOCOL_TLSv1_2,
|
|
|
|
LDAP_REQUIRE_CERT=ssl.CERT_NONE,
|
|
|
|
FORCE_ATTRIBUTE_VALUE_AS_LIST=True,
|
2020-08-23 21:58:26 +00:00
|
|
|
)
|
2020-08-25 02:36:05 +00:00
|
|
|
if "SECRET" in config:
|
|
|
|
app.config["LDAP_SECRET"] = (config["SECRET"],)
|
|
|
|
self.ldap = LDAPConn(app)
|
|
|
|
self.dn = config["BASEDN"]
|
2020-08-23 21:58:26 +00:00
|
|
|
|
|
|
|
def login(self, user, password):
|
|
|
|
if not user:
|
|
|
|
return False
|
2020-10-18 23:41:54 +00:00
|
|
|
return self.ldap.authenticate(user.userid, password, "uid", self.dn)
|
2020-08-25 02:36:05 +00:00
|
|
|
|
2020-09-03 15:56:12 +00:00
|
|
|
def update_user(self, user):
|
2020-09-01 23:09:24 +00:00
|
|
|
self.ldap.connection.search(
|
|
|
|
"ou=user,{}".format(self.dn),
|
2020-10-18 23:41:54 +00:00
|
|
|
"(uid={})".format(user.userid),
|
2020-09-01 23:09:24 +00:00
|
|
|
SUBTREE,
|
|
|
|
attributes=["uid", "givenName", "sn", "mail"],
|
|
|
|
)
|
2020-08-25 02:36:05 +00:00
|
|
|
r = self.ldap.connection.response[0]["attributes"]
|
2020-10-18 23:41:54 +00:00
|
|
|
if r["uid"][0] == user.userid:
|
2020-09-02 11:07:21 +00:00
|
|
|
user.set_attribute("DN", self.ldap.connection.response[0]["dn"])
|
2020-08-25 02:36:05 +00:00
|
|
|
user.firstname = r["givenName"][0]
|
|
|
|
user.lastname = r["sn"][0]
|
|
|
|
if r["mail"]:
|
|
|
|
user.mail = r["mail"][0]
|
|
|
|
if "displayName" in r:
|
2020-09-02 11:07:21 +00:00
|
|
|
user.display_name = r["displayName"][0]
|
2020-10-18 23:41:54 +00:00
|
|
|
for group in self._get_groups(user.userid):
|
2020-10-03 23:25:50 +00:00
|
|
|
user.add_role(group)
|
2020-08-25 02:36:05 +00:00
|
|
|
|
2020-09-02 11:07:21 +00:00
|
|
|
def _get_groups(self, uid):
|
2020-09-03 22:55:23 +00:00
|
|
|
groups = []
|
|
|
|
|
|
|
|
self.ldap.connection.search(
|
|
|
|
"ou=user,{}".format(self.dn), "(uid={})".format(uid), SUBTREE, attributes=["gidNumber"]
|
|
|
|
)
|
|
|
|
main_group_number = self.ldap.connection.response[0]["attributes"]["gidNumber"]
|
|
|
|
if main_group_number:
|
|
|
|
if type(main_group_number) is list:
|
|
|
|
main_group_number = main_group_number[0]
|
|
|
|
self.ldap.connection.search(
|
|
|
|
"ou=group,{}".format(self.dn), "(gidNumber={})".format(main_group_number), attributes=["cn"]
|
2020-09-01 23:09:24 +00:00
|
|
|
)
|
2020-09-03 22:55:23 +00:00
|
|
|
groups.append(self.ldap.connection.response[0]["attributes"]["cn"][0])
|
2020-08-25 02:36:05 +00:00
|
|
|
|
2020-09-03 22:55:23 +00:00
|
|
|
self.ldap.connection.search(
|
|
|
|
"ou=group,{}".format(self.dn), "(memberUID={})".format(uid), SUBTREE, attributes=["cn"]
|
|
|
|
)
|
|
|
|
groups_data = self.ldap.connection.response
|
|
|
|
for data in groups_data:
|
|
|
|
groups.append(data["attributes"]["cn"][0])
|
|
|
|
return groups
|
2020-08-25 02:36:05 +00:00
|
|
|
|
2020-09-03 22:55:23 +00:00
|
|
|
def modify_user(self, user: User, password, new_password=None):
|
|
|
|
try:
|
2020-09-03 23:01:00 +00:00
|
|
|
dn = user.attributes["DN"].value
|
|
|
|
ldap_conn = self.ldap.connect(dn, password)
|
|
|
|
modifier = {}
|
|
|
|
for name, ldap_name in [
|
|
|
|
("firstname", "givenName"),
|
|
|
|
("lastname", "sn"),
|
|
|
|
("mail", "mail"),
|
|
|
|
("display_name", "displayName"),
|
|
|
|
]:
|
|
|
|
if getattr(user, name):
|
|
|
|
modifier[ldap_name] = [(MODIFY_REPLACE, [getattr(user, name)])]
|
2020-09-03 22:55:23 +00:00
|
|
|
if new_password:
|
|
|
|
salted_password = hashed(HASHED_SALTED_SHA512, new_password)
|
|
|
|
modifier["userPassword"] = [(MODIFY_REPLACE, [salted_password])]
|
2020-09-03 23:01:00 +00:00
|
|
|
ldap_conn.modify(dn, modifier)
|
2020-09-03 22:55:23 +00:00
|
|
|
except (LDAPPasswordIsMandatoryError, LDAPBindError):
|
|
|
|
raise BadRequest
|