From 5817a1893be4f4e14784de68c5ee8c185f36d63b Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Fri, 18 Mar 2016 21:24:08 +0100 Subject: [PATCH] LDAP auth login method enhancements 1/ Allow user to pass a group mapping in manage_groups=True mode. A group mapping is a structure like: { "ldap_grp1": ["web2py_grp1", "web2py_grp2"], "ldap_grp2": ["ldap_grp2", "web2py_grp3"], } After fetching the ldap user's ldap groups, the list entries are translated, before janitoring the auth_group and auth_membership tables. 2/ Allow to define a callback to execute if the auth_group or auth_membership tables are changed. Typical use-case are cache flushing and app-driven replication. --- gluon/contrib/login_methods/ldap_auth.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/gluon/contrib/login_methods/ldap_auth.py b/gluon/contrib/login_methods/ldap_auth.py index 02fddb19..c724d664 100644 --- a/gluon/contrib/login_methods/ldap_auth.py +++ b/gluon/contrib/login_methods/ldap_auth.py @@ -36,11 +36,13 @@ def ldap_auth(server='ldap', user_lastname_attrib='cn:2', user_mail_attrib='mail', manage_groups=False, + manage_groups_callback=[], db=None, group_dn=None, group_name_attrib='cn', group_member_attrib='memberUid', group_filterstr='objectClass=*', + group_mapping={}, tls=False, logging_level='error'): @@ -207,6 +209,7 @@ def ldap_auth(server='ldap', user_mail_attrib=user_mail_attrib, manage_groups=manage_groups, allowed_groups=allowed_groups, + group_mapping=group_mapping, db=db): if password == '': # http://tools.ietf.org/html/rfc4513#section-5.1.2 logger.warning('blank password not allowed') @@ -262,6 +265,7 @@ def ldap_auth(server='ldap', requested_attrs = ['sAMAccountName'] if manage_user: requested_attrs.extend([user_firstname_attrib, user_lastname_attrib, user_mail_attrib]) + result = con.search_ext_s( ldap_basedn, ldap.SCOPE_SUBTREE, "(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare), filterstr), @@ -444,7 +448,7 @@ def ldap_auth(server='ldap', con.unbind() if manage_groups: - if not do_manage_groups(username, password): + if not do_manage_groups(username, password, group_mapping): return False return True except ldap.INVALID_CREDENTIALS, e: @@ -482,7 +486,7 @@ def ldap_auth(server='ldap', # No match return False - def do_manage_groups(username, password=None, db=db): + def do_manage_groups(username, password=None, group_mapping={}, db=db): """ Manage user groups @@ -498,6 +502,14 @@ def ldap_auth(server='ldap', ldap_groups_of_the_user = get_user_groups_from_ldap( username, password) + if group_mapping != {}: + l = [] + for group in ldap_groups_of_the_user: + if group in group_mapping: + l += group_mapping[group] + ldap_groups_of_the_user = l + logging.info("User groups after remapping: %s" % str(l)) + # # Get all group name where the user is in actually in local db # ############################################################# @@ -540,6 +552,7 @@ def ldap_auth(server='ldap', db_groups_of_the_user.append(group.role) logging.debug('db groups of user %s: %s' % (username, str(db_groups_of_the_user))) + auth_membership_changed = False # # Delete user membership from groups where user is not anymore # ############################################################# @@ -547,6 +560,7 @@ def ldap_auth(server='ldap', if ldap_groups_of_the_user.count(group_to_del) == 0: db((db.auth_membership.user_id == db_user_id) & (db.auth_membership.group_id == db_group_id[group_to_del])).delete() + auth_membership_changed = True # # Create user membership in groups where user is not in already @@ -558,6 +572,12 @@ def ldap_auth(server='ldap', else: gid = db(db.auth_group.role == group_to_add).select(db.auth_group.id).first().id db.auth_membership.insert(user_id=db_user_id, group_id=gid) + auth_membership_changed = True + + if auth_membership_changed: + for callback in manage_groups_callback: + callback() + except: logger.warning("[%s] Groups are not managed successfully!" % str(username)) import traceback