Skip to content

Commit

Permalink
fix get ldap users via ccnet_api (#5711)
Browse files Browse the repository at this point in the history
* fix get ldap users via ccnet_api

* improve code

* optimize code
  • Loading branch information
likesclever authored Oct 31, 2023
1 parent 3ed3dff commit 5b17246
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 27 deletions.
77 changes: 50 additions & 27 deletions seahub/api2/endpoints/admin/users.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Copyright (c) 2012-2016 Seafile Ltd.
import os
import json
import logging
from types import FunctionType
from constance import config
Expand All @@ -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 _
Expand All @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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: ['[email protected]', ...]
# 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
Expand All @@ -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': '[email protected]', '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 {'[email protected]': 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] -> {'[email protected]': '[email protected]', ...}['[email protected]'] -> '[email protected]'
"""
"""
email_ctime_map[uid_email_map[uid]] -> email_ctime_map['[email protected]'] ->
{'[email protected]': 1692950099, ...}['[email protected]'] -> 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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 = []
Expand Down
24 changes: 24 additions & 0 deletions seahub/utils/ccnet_db.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 5b17246

Please sign in to comment.