From 5b17246c1fc1397d7f4c65dafa854da1d1ea8db1 Mon Sep 17 00:00:00 2001 From: WJH <40563566+loveclever@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:12:13 +0800 Subject: [PATCH] fix get ldap users via ccnet_api (#5711) * fix get ldap users via ccnet_api * improve code * optimize code --- seahub/api2/endpoints/admin/users.py | 77 ++++++++++++++++++---------- seahub/utils/ccnet_db.py | 24 +++++++++ 2 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 seahub/utils/ccnet_db.py diff --git a/seahub/api2/endpoints/admin/users.py b/seahub/api2/endpoints/admin/users.py index b7ee9e81931..e1b9581cd85 100644 --- a/seahub/api2/endpoints/admin/users.py +++ b/seahub/api2/endpoints/admin/users.py @@ -1,6 +1,5 @@ # Copyright (c) 2012-2016 Seafile Ltd. import os -import json import logging from types import FunctionType from constance import config @@ -11,6 +10,7 @@ from rest_framework.response import Response from rest_framework.views import APIView +from django.db import connection from django.db.models import Q from django.core.cache import cache from django.utils.translation import gettext as _ @@ -25,7 +25,7 @@ from seahub.api2.throttling import UserRateThrottle from seahub.api2.utils import api_error, to_python_boolean from seahub.api2.models import TokenV2 - +from seahub.utils.ccnet_db import get_ccnet_db_name import seahub.settings as settings from seahub.settings import SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER, INIT_PASSWD, \ SEND_EMAIL_ON_RESETTING_USER_PASSWD @@ -98,10 +98,36 @@ json_content_type = 'application/json; charset=utf-8' -class LdapUser(object): - def __init__(self, email, ctime): +class UserObj(object): + def __init__(self, email, ctime, is_staff, is_active, role): self.email = email self.ctime = ctime + self.is_staff = is_staff + self.is_active = is_active + self.role = role + + +def get_user_objs_from_ccnet(email_list): + db_name, error_msg = get_ccnet_db_name() + if error_msg: + logger.error(error_msg) + return list(), api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') + + sql = """SELECT e.email, is_staff, is_active, ctime, role FROM `%s`.`EmailUser` e + LEFT JOIN UserRole r ON e.emali=r.email WHERE e.email IN %%s""" % db_name + try: + with connection.cursor() as cursor: + cursor.execute(sql, (email_list,)) + res = cursor.fetchall() + except Exception as e: + logger.error('Failed to query email_user object list from ccnet_db, error: %s.' % e) + return list(), api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') + + user_objs = list() + for email, is_staff, is_active, ctime, role in res: + user_objs.append(UserObj(email, ctime, is_staff, is_active, role)) + + return user_objs, None def ldap_bind(server_url, dn, authc_id, password, enable_sasl, sasl_mechanism): @@ -164,7 +190,7 @@ def get_ldap_users(server_url, admin_dn, admin_password, enable_sasl, sasl_mecha break ctrl.cookie = page_ctrls[0].cookie - # get ldap user's uid list, uid means login_attr, likes: ['ldap@email.com', ...] + # get ldap user's uid list, uid means login_attr, likes: ['uid1', 'uid2', 'uid3', 'uid5', ...] ldap_uid_list = list() for pair in result_data: user_dn, attrs = pair @@ -175,32 +201,25 @@ def get_ldap_users(server_url, admin_dn, admin_password, enable_sasl, sasl_mecha uid = attrs[login_attr][0].lower().decode() ldap_uid_list.append(uid) - # get uid_email_map, likes {'ldap@email.com': 'seafile@email.com', ...} - ldap_users = SocialAuthUser.objects.filter(provider__in=[LDAP_PROVIDER, MULTI_LDAP_1_PROVIDER], - uid__in=ldap_uid_list) + # get uid_email_map, likes {'uid2': '2@2.com', 'uid3': '3@3.com', 'uid4': '4@4.com', ...} + imported_ldap_users = SocialAuthUser.objects.filter(provider__in=[LDAP_PROVIDER, MULTI_LDAP_1_PROVIDER], + uid__in=ldap_uid_list) uid_email_map = dict() - for user in ldap_users: + for user in imported_ldap_users: uid_email_map[user.uid] = user.username - # get email_ctime_map, likes {'seafile@email.com': 1692950099, ...} - email_ctime_map = dict() - db_users = ccnet_api.get_emailusers_in_list('DB', json.dumps(list(uid_email_map.values()))) - for user in db_users: - email_ctime_map[user.email] = user.ctime - users = list() + email_list = list() for uid in ldap_uid_list: - """ - uid_email_map[uid] -> {'ldap@email.com': 'seafile@email.com', ...}['ldap@email.com'] -> 'seafile@email.com' - """ - """ - email_ctime_map[uid_email_map[uid]] -> email_ctime_map['seafile@email.com'] -> - {'seafile@email.com': 1692950099, ...}['seafile@email.com'] -> 1692950099 - """ - if uid in uid_email_map and uid_email_map[uid] in email_ctime_map: - users.append(LdapUser(uid_email_map[uid], email_ctime_map[uid_email_map[uid]])) + if uid in uid_email_map: + email_list.append(uid_email_map[uid]) else: - users.append(LdapUser(uid, None)) + users.append(UserObj(uid, None, None, None, None)) + + user_objs, error = get_user_objs_from_ccnet(email_list) + if error: + raise Exception('Failed to query email_user object list from ccnet_db.') + users.extend(user_objs) return users @@ -536,7 +555,9 @@ def get_info_of_users_order_by_quota_usage(self, source, direction, if ENABLE_MULTI_LDAP: multi_ldap_users = SocialAuthUser.objects.filter(provider=MULTI_LDAP_1_PROVIDER) email_list.extend([user.username for user in multi_ldap_users]) - users = ccnet_api.get_emailusers_in_list('DB', json.dumps(email_list)) + users, error = get_user_objs_from_ccnet(email_list) + if error: + return error for user in users: email = user.email @@ -681,7 +702,9 @@ def get(self, request): if ENABLE_MULTI_LDAP: multi_ldap_users = SocialAuthUser.objects.filter(provider=MULTI_LDAP_1_PROVIDER) email_list.extend([user.username for user in multi_ldap_users]) - all_ldap_users = ccnet_api.get_emailusers_in_list('DB', json.dumps(email_list)) + all_ldap_users, error = get_user_objs_from_ccnet(email_list) + if error: + return error users = all_ldap_users[start: start + per_page] data = [] diff --git a/seahub/utils/ccnet_db.py b/seahub/utils/ccnet_db.py new file mode 100644 index 00000000000..b6d4d113406 --- /dev/null +++ b/seahub/utils/ccnet_db.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +import os +import configparser + + +def get_ccnet_db_name(): + ccnet_conf_dir = os.environ.get('SEAFILE_CENTRAL_CONF_DIR') or os.environ.get('CCNET_CONF_DIR') + if not ccnet_conf_dir: + error_msg = 'Environment variable ccnet_conf_dir is not define.' + return None, error_msg + + ccnet_conf_path = os.path.join(ccnet_conf_dir, 'ccnet.conf') + config = configparser.ConfigParser() + config.read(ccnet_conf_path) + + if config.has_section('Database'): + db_name = config.get('Database', 'DB', fallback='ccnet') + else: + db_name = 'ccnet' + + if config.get('Database', 'ENGINE') != 'mysql': + error_msg = 'Failed to init ccnet db, only mysql db supported.' + return None, error_msg + return db_name, None