diff --git a/events/db.py b/events/db.py index ea4ae0e2..69dc8364 100644 --- a/events/db.py +++ b/events/db.py @@ -9,7 +9,7 @@ from sqlalchemy.sql import exists from .models import Event, UserEvent, FileAudit, FileUpdate, PermAudit, \ - Activity, UserActivity, FileHistory + Activity, UserActivity, FileHistory, ExternalFileDownloadLog from seafevents.app.config import appconfig @@ -323,10 +323,19 @@ def save_file_audit_event(session, timestamp, etype, user, ip, device, file_audit = FileAudit(timestamp, etype, user, ip, device, org_id, repo_id, file_path) + session.add(file_audit) + session.commit() + +def save_external_file_download_log(session, timestamp, user, ip, repo_id, file_path, size): + if timestamp is None: + timestamp = datetime.datetime.utcnow() + + file_audit = ExternalFileDownloadLog(timestamp, user, ip, repo_id, file_path, size, datetime.datetime.now(), user, datetime.datetime.now(), user) session.add(file_audit) session.commit() + def save_perm_audit_event(session, timestamp, etype, from_user, to, org_id, repo_id, file_path, perm): if timestamp is None: diff --git a/events/handlers.py b/events/handlers.py index 0ba50399..519f710e 100644 --- a/events/handlers.py +++ b/events/handlers.py @@ -13,11 +13,14 @@ from seafobj import CommitDiffer, commit_mgr, fs_mgr from seafobj.commit_differ import DiffEntry from seafevents.events.db import save_file_audit_event, save_file_update_event, \ - save_perm_audit_event, save_user_activity, save_filehistory, update_user_activity_timestamp + save_perm_audit_event, save_user_activity, save_filehistory, update_user_activity_timestamp, \ + save_external_file_download_log from seafevents.app.config import appconfig from .change_file_path import ChangeFilePathHandler from .models import Activity +logger = logging.getLogger('seafevents') + def RepoUpdateEventHandler(session, msg): elements = msg['content'].split('\t') if len(elements) != 3: @@ -425,7 +428,7 @@ def FileAuditEventHandler(session, msg): if len(elements) != 6: logging.warning("got bad message: %s", elements) return - + timestamp = datetime.datetime.utcfromtimestamp(msg['ctime']) msg_type = elements[0] user_name = elements[1] @@ -498,6 +501,28 @@ def DraftPublishEventHandler(session, msg): save_user_activity(session, record) +def ExternalFileAuditEventHandler(session, msg): + elements = msg['content'].split('\t') + if len(elements) != 6: + logging.warning("got bad message: %s", elements) + return + + timestamp = datetime.datetime.utcfromtimestamp(msg['ctime']) + user_name = elements[1] + ip = elements[2] + repo_id = elements[4] + file_path = elements[5] + + repo = seafile_api.get_repo(repo_id) + if repo.repo_type != 'external': + return + dirent = seafile_api.get_dirent_by_path(repo_id, file_path) + logging.warning(dirent.__dict__) + if not file_path.startswith('/'): + file_path = '/' + file_path + save_external_file_download_log(session, timestamp, user_name, ip, repo_id, file_path, dirent.size) + + def register_handlers(handlers, enable_audit): handlers.add_handler('seaf_server.event:repo-update', RepoUpdateEventHandler) if enable_audit: @@ -511,3 +536,11 @@ def register_handlers(handlers, enable_audit): handlers.add_handler('seahub.audit:file-download-share-link', FileAuditEventHandler) handlers.add_handler('seahub.audit:perm-change', PermAuditEventHandler) handlers.add_handler('seahub.draft:publish', DraftPublishEventHandler) + + # + handlers.add_handler('seahub.audit:file-download-web', ExternalFileAuditEventHandler) + handlers.add_handler('seahub.audit:file-download-api', ExternalFileAuditEventHandler) + handlers.add_handler('seahub.audit:file-download-share-link', ExternalFileAuditEventHandler) + + # handlers.add_handler('seaf_server.event:repo-download-sync', ExternalFileAuditEventHandler) + # handlers.add_handler('seaf_server.event:seadrive-download-file', ExternalFileAuditEventHandler) diff --git a/events/models.py b/events/models.py index a8477a19..da404985 100644 --- a/events/models.py +++ b/events/models.py @@ -267,3 +267,31 @@ def __str__(self): RepoID = %s, FilePath = %s, Permission = %s>" % \ (self.etype, self.from_user, self.to, self.repo_id, self.file_path, self.permission) + + +class ExternalFileDownloadLog(Base): + __tablename__ = 'ex_repo_download_log' + + id = Column(Integer, primary_key=True, autoincrement=True) + timestamp = Column(DateTime, nullable=False, index=True) + user = Column(String(length=255), nullable=False, index=True) + ip = Column(String(length=45), nullable=False) + repo_id = Column(String(length=36), nullable=False, index=True) + file_path = Column(Text, nullable=False) + size = Column(BigInteger, nullable=False) + created_time = Column(DateTime, nullable=False) + created_by = Column(String(length=255), nullable=False) + updated_time = Column(DateTime, nullable=False) + updated_by = Column(String(length=255), nullable=False) + + def __init__(self, timestamp, user, ip, repo_id, file_path, size, created_at, created_by, updated_at, updated_by): + self.timestamp = timestamp + self.user = user + self.ip = ip + self.repo_id = repo_id + self.file_path = file_path + self.size = size + self.created_time = created_at + self.updated_time = updated_at + self.created_by = created_by + self.updated_by = updated_by diff --git a/ldap_syncer/ldap_settings.py b/ldap_syncer/ldap_settings.py index 84ee95fe..078ddc57 100644 --- a/ldap_syncer/ldap_settings.py +++ b/ldap_syncer/ldap_settings.py @@ -55,6 +55,8 @@ def __init__(self): self.duplicated_user_filter = None # employee_type_attr: AD 中的一个自定义属性,标识账号类型 self.employee_type_attr = 'employeeType' + # external_user_filter: 用于过滤外部资料库权限的用户 + self.external_user_filter = None class Settings(object): def __init__(self, is_test=False): @@ -180,6 +182,7 @@ def read_base_config(self, ldap_config, ldap_sec, sync_sec, is_test, has_sync_se ldap_config.group_filter = self.get_option(ldap_sec, 'GROUP_FILTER') ldap_config.duplicated_user_filter = self.get_option(ldap_sec, 'DUPLICATED_USER_FILTER') + ldap_config.external_user_filter = self.get_option(ldap_sec, 'EXTERNAL_USER_FILTER') if ldap_config.host == '' or ldap_config.user_dn == '' or ldap_config.passwd == '' or ldap_config.base_dn == '': if is_test: diff --git a/ldap_syncer/ldap_sync.py b/ldap_syncer/ldap_sync.py index c3890106..ec29e428 100644 --- a/ldap_syncer/ldap_sync.py +++ b/ldap_syncer/ldap_sync.py @@ -64,6 +64,7 @@ def start_sync(self): data_ldap = self.get_data_from_ldap() data_ldap_custom = self.get_data_from_ldap(use_duplicated_user_filter=True) data_ladp_all = self.get_data_from_ldap(scope_all=True) + data_ldap_external = self.get_data_from_ldap(use_external_user_filter=True) if data_ldap is None: return @@ -71,17 +72,17 @@ def start_sync(self): if data_db is None: return - self.sync_data(data_db, data_ldap, data_ladp_all) + self.sync_data(data_db, data_ldap, data_ladp_all, data_ldap_external) self.cleanup_duplicated_ldap_data(data_ldap_custom) def get_data_from_db(self): return None - def get_data_from_ldap(self, use_duplicated_user_filter=False, scope_all=False): + def get_data_from_ldap(self, use_duplicated_user_filter=False, scope_all=False, use_external_user_filter=False): ret = {} for config in self.settings.ldap_configs: - cur_ret = self.get_data_from_ldap_by_server(config, use_duplicated_user_filter, scope_all) + cur_ret = self.get_data_from_ldap_by_server(config, use_duplicated_user_filter, scope_all, use_external_user_filter) # If get data from one server failed, then the result is failed if cur_ret is None: return None @@ -92,10 +93,10 @@ def get_data_from_ldap(self, use_duplicated_user_filter=False, scope_all=False): return ret - def get_data_from_ldap_by_server(self, config, use_duplicated_user_filter=False, scope_all=False): + def get_data_from_ldap_by_server(self, config, use_duplicated_user_filter=False, scope_all=False, use_external_user_filter=False): return None - def sync_data(self, data_db, data_ldap, data_ldap_all): + def sync_data(self, data_db, data_ldap, data_ldap_all, data_ldap_external): pass def cleanup_duplicated_ldap_data(self, data_ldap): diff --git a/ldap_syncer/ldap_user_sync.py b/ldap_syncer/ldap_user_sync.py index abde859a..21620ed8 100644 --- a/ldap_syncer/ldap_user_sync.py +++ b/ldap_syncer/ldap_user_sync.py @@ -414,7 +414,7 @@ def get_uid_to_ldap_user(self, data_ldap): return uid_to_ldap_user - def get_data_from_ldap_by_server(self, config, use_duplicated_user_filter=False, scope_all=False): + def get_data_from_ldap_by_server(self, config, use_duplicated_user_filter=False, scope_all=False, use_external_user_filter=False): if not config.enable_user_sync: return {} ldap_conn = LdapConn(config.host, config.user_dn, config.passwd, config.follow_referrals) @@ -438,6 +438,16 @@ def get_data_from_ldap_by_server(self, config, use_duplicated_user_filter=False, config.duplicated_user_filter) else: return None + + # 使用 外部权限的用户 过滤 + elif use_external_user_filter: + + if config.external_user_filter: + search_filter = '(&(objectClass=%s)(%s))' % \ + (config.user_object_class, + config.external_user_filter) + else: + return None # search all users on base dn elif config.user_filter != '': @@ -584,8 +594,29 @@ def add_or_update_user_role_time(self, email, role): logger.debug('Update role time to user %s successs.' % email) except Exception as e: logger.debug('Failed to update role time to user %s: %s.' % (email, e)) - - def sync_add_user(self, ldap_user, email, set_guest=False): + + def set_external_user(self, email, set_external=False): + self.cursor.execute('select 1 from ex_repo_user where email=%s', [email]) + if self.cursor.rowcount == 0: + if set_external: + sql = 'insert into ex_repo_user (email, created_time, created_by, updated_time, updated_by) values (%s,%s,%s,%s,%s)' + try: + self.cursor.execute(sql, [email, datetime.now(), 'ldap_sync', datetime.now(), 'ladp_sync']) + if self.cursor.rowcount == 1: + logger.debug('Create external user %s successs.' % email) + except Exception as e: + logger.debug('Failed to create external user %s: %s.' % (email, e)) + else: + if not set_external: + sql = 'delete from ex_repo_user where email=%s' + try: + self.cursor.execute(sql, [email]) + if self.cursor.rowcount == 1: + logger.debug('Create external user %s successs.' % email) + except Exception as e: + logger.debug('Failed to create external user %s: %s.' % (email, e)) + + def sync_add_user(self, ldap_user, email, set_guest=False, set_external=False): user_id = add_ldap_user(email, ldap_user.password, 0, 1 if self.settings.activate_user else 0) if user_id <= 0: @@ -625,7 +656,9 @@ def sync_add_user(self, ldap_user, email, set_guest=False): self.add_profile(email, ldap_user) self.add_dept(email, ldap_user.dept) - def sync_update_user(self, ldap_user, db_user, email, new_email, set_guest=False): + self.set_external_user(email, set_external) + + def sync_update_user(self, ldap_user, db_user, email, new_email, set_guest=False, set_external=False): # PingAn customization: reactivate user when it's added back to AD. if (email != new_email) or (db_user.password != ldap_user.password) or (db_user.is_active==0): db_user.is_active = 1 @@ -684,6 +717,8 @@ def sync_update_user(self, ldap_user, db_user, email, new_email, set_guest=False return logger.debug('Reactivate user [%s] success.' % email) + self.set_external_user(email, set_external) + def sync_migrate_user(self, old_user, new_user): if ccnet_api.update_emailuser_id(old_user, new_user) < 0: logger.warning('Failed to update emailuser id to %s.' % new_user) @@ -927,7 +962,7 @@ def sync_del_user(self, db_user, email): # Note: customized for PinaAn's requirements. Do not deactivate renamed users in ldap. # The checking of rename is based on profile_profile.login_id database field and uid attribute. - def sync_data(self, data_db, data_ldap, data_ldap_all): + def sync_data(self, data_db, data_ldap, data_ldap_all, data_ldap_external=None): ''' :param data_db: seafile数据库中的用户数据 @@ -952,49 +987,26 @@ def sync_data(self, data_db, data_ldap, data_ldap_all): logger.debug('User[%s] not found in ldap, ' 'DEACTIVE_USER_IF_NOTFOUND option is not set, so not deactive it.' % del_user) - # collect migrated users - # nums = 0 - # for k, v in data_ldap_all.items(): - # if uid_to_users: - # uid = v.uid.lower() - # if uid in uid_to_users: - # found_active = False - # users = uid_to_users[uid] - # for user in users: - # if k == user: - # found_active = True - # break - # - # if found_active: - # for user in users: - # if k == user: - # continue - # nums = nums + 1 - # continue - # - # for user in users: - # nums = nums + 1 - # - # if nums > 0: - # logger.debug('%d users need migrate.' % nums) - # sync new and existing users from ldap to db for k, v in data_ldap_all.items(): set_guest = False + set_external = False if k not in data_ldap.keys(): # 如果用户不在设置的安全组里 set_guest = True + if k in data_ldap_external.keys(): + set_external = True if uid_to_users: uid = v.uid.lower() if uid not in uid_to_users: if self.settings.import_new_user: - self.sync_add_user(v, k, set_guest=set_guest) + self.sync_add_user(v, k, set_guest=set_guest, set_external=set_external) else: found_active = False users = uid_to_users[uid] for user in users: if k == user: if user in data_db: - self.sync_update_user(v, data_db[user], user, k, set_guest=set_guest) + self.sync_update_user(v, data_db[user], user, k, set_guest=set_guest, set_external=set_external) found_active = True break @@ -1009,7 +1021,7 @@ def sync_data(self, data_db, data_ldap, data_ldap_all): continue email = users[0] - self.sync_update_user(v, data_db[email], email, k, set_guest=set_guest) + self.sync_update_user(v, data_db[email], email, k, set_guest=set_guest, set_external=set_external) for user in users: self.sync_migrate_user(user, k) if email != user: