diff --git a/ldap_syncer/ldap_settings.py b/ldap_syncer/ldap_settings.py index 1eb7369f..0f55df5c 100644 --- a/ldap_syncer/ldap_settings.py +++ b/ldap_syncer/ldap_settings.py @@ -48,6 +48,12 @@ def __init__(self): self.sync_group_as_department = False self.department_repo_permission = None self.department_name_attr = None + +########################## pingan custom : extral conf ################################## + self.custom_user_filter = None + self.employee_type_attr = 'employeeType' + self.special_account_type = '' +########################## pingan custom : extral conf ################################## class Settings(object): def __init__(self, is_test=False): @@ -171,6 +177,8 @@ def read_base_config(self, ldap_config, ldap_sec, sync_sec, is_test, has_sync_se ldap_config.follow_referrals = self.get_option(ldap_sec, 'FOLLOW_REFERRALS', bool, True) ldap_config.user_filter = self.get_option(ldap_sec, 'FILTER') ldap_config.group_filter = self.get_option(ldap_sec, 'GROUP_FILTER') + + ldap_config.custom_user_filter = self.get_option(ldap_sec, 'CUSTOM_FILTER') if ldap_config.host == '' or ldap_config.user_dn == '' or ldap_config.passwd == '' or ldap_config.base_dn == '': if is_test: @@ -257,6 +265,9 @@ def read_sync_user_config(self, ldap_config, ldap_sec, sync_sec): ldap_config.cemail_attr = self.get_option(sync_sec, 'CONTACT_EMAIL_ATTR') ldap_config.role_name_attr = self.get_option(sync_sec, 'ROLE_NAME_ATTR', dval='') ldap_config.auto_reactivate_users = self.get_option(sync_sec, 'AUTO_REACTIVATE_USERS', bool, False) + + special_account_type = self.get_option(sync_sec, 'SPECIAL_EMPLOYEE_TYPE', dval='GM,OPR,TEST,MON,SYS,PRA,ADM') + ldap_config.special_account_type = [sat.strip() for sat in special_account_type.split(',')] def enable_sync(self): return self.enable_user_sync or self.enable_group_sync or self.sync_department_from_ou diff --git a/ldap_syncer/ldap_sync.py b/ldap_syncer/ldap_sync.py index 0bad40e1..3953b4e2 100644 --- a/ldap_syncer/ldap_sync.py +++ b/ldap_syncer/ldap_sync.py @@ -62,6 +62,7 @@ def show_sync_result(self): def start_sync(self): data_ldap = self.get_data_from_ldap() + data_ldap_custom = self.get_data_from_ldap(use_custom_user_filter=True) if data_ldap is None: return @@ -70,15 +71,16 @@ def start_sync(self): return self.sync_data(data_db, data_ldap) + self.cron_ldap_data(data_ldap_custom) def get_data_from_db(self): return None - def get_data_from_ldap(self): + def get_data_from_ldap(self, use_custom_user_filter=False): ret = {} for config in self.settings.ldap_configs: - cur_ret = self.get_data_from_ldap_by_server(config) + cur_ret = self.get_data_from_ldap_by_server(config, use_custom_user_filter) # If get data from one server failed, then the result is failed if cur_ret is None: return None @@ -89,8 +91,11 @@ def get_data_from_ldap(self): return ret - def get_data_from_ldap_by_server(self, config): + def get_data_from_ldap_by_server(self, config, use_custom_user_filter=False): return None def sync_data(self, data_db, data_ldap): pass + + def cron_ldap_data(self, data_ldap): + pass diff --git a/ldap_syncer/ldap_user_sync.py b/ldap_syncer/ldap_user_sync.py index f192a12d..181799a1 100644 --- a/ldap_syncer/ldap_user_sync.py +++ b/ldap_syncer/ldap_user_sync.py @@ -9,8 +9,9 @@ seafile_api, ccnet_api from .ldap_conn import LdapConn from .ldap_sync import LdapSync -from .utils import bytes2str +from .utils import bytes2str, del_mobfile, add_mobfile from ldap import SCOPE_SUBTREE +from datetime import datetime def default_ldap_role_mapping(role): return role @@ -375,7 +376,6 @@ def get_data_from_db(self): dept = user_attrs.get('dept', '') uid = user_attrs.get('uid', '') cemail = user_attrs.get('email', '') - user_data_db[user.email] = LdapUser(user.id, user.password, name, dept, uid, cemail, 1 if user.is_staff else 0, @@ -397,18 +397,28 @@ def get_uid_to_ldap_user(self, data_ldap): return uid_to_ldap_user - def get_data_from_ldap_by_server(self, config): + def get_data_from_ldap_by_server(self, config, use_custom_user_filter=False): if not config.enable_user_sync: return {} ldap_conn = LdapConn(config.host, config.user_dn, config.passwd, config.follow_referrals) ldap_conn.create_conn() if not ldap_conn.conn: return None - # dn <-> LdapUser user_data_ldap = {} + + if use_custom_user_filter: + + if config.custom_user_filter: + search_filter = '(&(objectClass=%s)(%s))' % \ + (config.user_object_class, + config.custom_user_filter) + else: + return None + + # search all users on base dn - if config.user_filter != '': + elif config.user_filter != '': search_filter = '(&(objectClass=%s)(%s))' % \ (config.user_object_class, config.user_filter) @@ -431,7 +441,7 @@ def get_data_from_ldap_by_server(self, config): def get_data_by_base_dn(self, config, ldap_conn, base_dn, search_filter): user_data_ldap = {} - search_attr = [config.login_attr, config.pwd_change_attr] + search_attr = [config.login_attr, config.pwd_change_attr, config.employee_type_attr] if config.role_name_attr: search_attr.append(config.role_name_attr) @@ -461,12 +471,23 @@ def get_data_by_base_dn(self, config, ldap_conn, base_dn, search_filter): if not isinstance(attrs, dict): continue if config.login_attr not in attrs: - continue + # ldap user 没有login_attr 属性,会忽略,这个 login_attr 是一个email + attrs[config.login_attr] = [''] + # continue if config.pwd_change_attr not in attrs: password = '' else: password = attrs[config.pwd_change_attr][0] +############################################### pingan custom: 判断 ad中的emplyee type, 如果属于特殊类型,或者黑名单则不予同步 ########################### + # 特殊类型从ccnet.conf中进行配置 + # 在[LDAP_SYNC]中增加配置 SPECIAL_EMPLOYEE_TYPE=GM,OPR,TEST,MON,SYS,PRA,ADM + if config.employee_type_attr in attrs: + employee_type = attrs[config.empemployee_type_attr][0] + if employee_type in config.special_account_type: + continue +############################################### pingan custom: 判断 ad中的emplyee type, 如果属于特殊类型,或者黑名单则不予同步 ########################### + user_name = None dept = None uid = None @@ -505,13 +526,13 @@ def get_data_by_base_dn(self, config, ldap_conn, base_dn, search_filter): else: uid = attrs[config.uid_attr][0] - if config.cemail_attr != '': - if config.cemail_attr not in attrs: - cemail = '' - else: - cemail = attrs[config.cemail_attr][0] - +############################################### pingan custom: AD中没有邮箱,创建虚拟邮箱进行同步 ########################### email = attrs[config.login_attr][0].lower() + if not email: + email = "%s@pingan.com" % uid + email = email.lower() +############################################### pingan custom: AD中没有邮箱,创建虚拟邮箱进行同步 ########################### + user_name = None if user_name is None else user_name.strip() user_data_ldap[email] = LdapUser(None, password, user_name, dept, uid, cemail, role = role) @@ -526,18 +547,30 @@ def sync_add_user(self, ldap_user, email): return self.auser += 1 logger.debug('Add user [%s] success.' % email) - - ret = 0 - if ldap_user.role: - role = role_mapping(ldap_user.role) - ret = ccnet_api.update_role_emailuser(email, role, False) - - if ret == 0: - self.arole += 1 - logger.debug('Add role [%s] for user [%s] success.' % (role, email)) - - if ret < 0: - logger.warning('Add role [%s] for user [%s] failed.' % (role, email)) + +############################################### pingan custom: 新增用户维护访客角色, 加组 ########################### + role = 'guest' + ret = ccnet_api.update_role_emailuser(email, role, False) + if ret == 0: + self.arole += 1 + logger.debug('Add role [%s] for user [%s] success.' % (role, email)) + if ret < 0: + logger.warning('Add role [%s] for user [%s] failed.' % (role, email)) + + self.add_mobfile(ldap_user) +############################################### pingan custom:新增用户维护访客角色, 加组 ########################### + + # ret = 0 + # if ldap_user.role: + # role = role_mapping(ldap_user.role) + # ret = ccnet_api.update_role_emailuser(email, role, False) + # + # if ret == 0: + # self.arole += 1 + # logger.debug('Add role [%s] for user [%s] success.' % (role, email)) + # + # if ret < 0: + # logger.warning('Add role [%s] for user [%s] failed.' % (role, email)) if ldap_user.config.enable_extra_user_info_sync: self.add_profile(email, ldap_user) @@ -908,3 +941,33 @@ def sync_data(self, data_db, data_ldap): self.update_profile_user_login_id(k, uid) self.close_seahub_db() + +########################### pingan custom: 1. 组的增减接口, 2. 定时同步 ##################################### + + def add_mobfile(self, ldap_user): + op_num = 'xxxxx' + flag = 0 + uid = ldap_user.uid + config = ldap_user.config + user_dn = config.user_dn + password = config.passwd + add_mobfile(flag, [uid], op_num, user_dn, password) + return + + def del_mobfile(self, ldap_user): + op_num = 'xxxxxx' + uid = ldap_user.uid + config = ldap_user.config + user_dn = config.user_dn + password = config.passwd + del_mobfile([uid], op_num, user_dn, password) + + def cron_ldap_data(self, data_ldap): + current_hour = datetime.today().hour + if current_hour != 6: + return + for email, ldap_user_obj in data_ldap.items(): + self.del_mobfile(ldap_user_obj) + +########################### pingan custom: 1. 组的增减接口, 2. 定时同步 ##################################### + diff --git a/ldap_syncer/utils.py b/ldap_syncer/utils.py index 0f85a251..d8954b3b 100644 --- a/ldap_syncer/utils.py +++ b/ldap_syncer/utils.py @@ -5,6 +5,8 @@ from seafevents.app.config import appconfig, load_config from seafevents.db import GroupIdLDAPUuidPair +from requests_ntlm import HttpNtlmAuth +import requests logger = logging.getLogger(__name__) @@ -82,3 +84,62 @@ def remove_useless_group_uuid_pairs(group_ids): logger.error('remote group_id:group_uuid pair failed. \n{}'.format(e)) finally: session.close() + +def del_mobfile(appro, operation_num, user_dn, password): # (['user1'],'xxxxx') + del_url = 'http://am-stg1.626888.paic.com.cn/api/FCloudApi/DelFCloudRightBat' # stg 批量关闭平安网盘权限 + applyer = "xxxx267" # 权限申请人 + group_name = 'stg-GS_mobilefile_free' # stg 权限组 + paras = { + "applyer": "", #申请人 + "operationNum": "del_userxxx", # 签报号 + "userAccounts": [], # 账号列表 + "emailNotify": "false", #是否发邮件 + "emailTemplate":"xxxx", #邮件内容 + } + paras["applyer"] = applyer + paras["operationNum"] = operation_num + paras["userAccounts"] = appro + response = requests.post(url= del_url, json=paras, + auth = HttpNtlmAuth(user_dn, password)) + code = response.status_code + res_json = response.json() # res_json: 域账号 hailong0403 从 STG-GS_MOBILEFILE_FREE 移除成功 + if code == 200 : + logger.info('%s remove from %s success'%(appro,group_name)) + else: + error = res_json.get("invalidUsers") + logger.error('%s remove from %s error: %s'%(appro,group_name,error)) + + +def add_mobfile(flag, appro, operationNum, user_dn, password): # (0,['user1'],'xxxx') + add_url = 'http://am-stg1.626888.paic.com.cn/api/FCloudApi/OpenFCloudRightBat' + applyer = "xxxx267" # 权限申请人 + group_name = 'stg-GS_mobilefile_free' # stg 权限组 + paras = { + "applyer": "", # 申请人 + "operationNum": "pafile21", # 签报号 + "groupName": "", # 权限组 + "userDomainIndex": "0", # 集团域:0, 银行域:1 + "userAccounts": [], # 账号列表 + "emailNotify": "false", # 是否发邮件 + "emailTemplate": "xxxx", # 邮件内容 + "endDate": "2999-12-31", # 过期时间 + "size": "0", # 配额,默认0, 1m + } + + paras["applyer"] = applyer + paras["groupName"] = group_name + paras["userDomainIndex"] = flag + paras["userAccounts"] = appro + paras["operationNum"] = operationNum + response = requests.post(url=add_url, json=paras, + auth=HttpNtlmAuth(user_dn, password)) + + code = response.status_code + res_json = response.json() # res_json: 提交成功。查看结果 + if code == 200: + logger.info('%s add to %s success' % (appro, group_name)) + else: + error = res_json.get("invalidUsers") + logger.error('%s add to %s error: %s' % (appro, group_name, error)) + + diff --git a/requirements.txt b/requirements.txt index 9eb97a57..10713210 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ mock pytest==3.1 pyjwt pymysql +requests-ntlm