package com.uas.eis.serviceImpl; import com.uas.eis.core.LdapConnectionManager; import com.uas.eis.core.config.ADConfig; import com.uas.eis.dao.BaseDao; import com.uas.eis.entity.ADUser; import com.uas.eis.entity.Employee; import com.uas.eis.entity.HrOrg; import com.uas.eis.utils.PinyinUtils; import com.uas.eis.utils.StringUtil; import org.apache.directory.api.ldap.model.cursor.CursorException; import org.apache.directory.api.ldap.model.cursor.EntryCursor; import org.apache.directory.api.ldap.model.entry.*; import org.apache.directory.api.ldap.model.exception.LdapException; import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; import org.apache.directory.api.ldap.model.message.ModifyDnRequest; import org.apache.directory.api.ldap.model.message.SearchScope; import org.apache.directory.api.ldap.model.name.Rdn; import org.apache.directory.ldap.client.api.LdapConnection; import org.apache.directory.api.ldap.model.name.Dn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.*; @Service public class ADSyncService { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired @Lazy private LdapConnectionManager ldapConnectionManager; @Autowired private ADConfig adConfig; @Autowired private BaseDao baseDao; @Autowired private UasSyncService uasSyncService; public void syncUser() throws IOException { LdapConnection connection = ldapConnectionManager.getConnection(); List employeeList = uasSyncService.getADUserList(); List adUserList = getUsers(connection); List orgList = uasSyncService.getADOrgList(); for (Employee employee : employeeList) { if(employee.getEm_adid()!=null){ //判断是否需要更新组织 if("离职".equals(employee.getEm_class())){ deleteUser(employee.getEm_adid(),connection); baseDao.updateByCondition("employee","em_adid=null","em_code='"+employee.getEm_code()+"'"); } Optional orgOptional = orgList.stream().filter(org -> org.getOr_code().equals(employee.getOrcode())).findFirst(); logger.info("同步用户更新:{}",employee.getEm_name()); if(orgOptional.isPresent()){ String newOUPath = getOUPath(orgOptional.get().getOr_path()); logger.info("同步用户更新:oldpath{},newpath{}",getUserOUPath(employee.getEm_adid()),newOUPath); if(employee.getEm_code().equals("ADMIN") && !getUserOUPath(employee.getEm_adid()).equals(newOUPath)){ moveUser(employee.getEm_adid(),"CN="+employee.getEm_name()+","+newOUPath,connection); baseDao.updateByCondition("employee","em_adid='CN="+employee.getEm_name()+","+newOUPath+"'","em_code='"+employee.getEm_code()+"'"); } } }else if (!"生产序列--普工".equals(employee.getEm_emptype()) && !"其它人员".equals(employee.getEm_emptype())) { Optional orgOptional = orgList.stream().filter(org -> org.getOr_code().equals(employee.getOrcode())).findFirst(); if(orgOptional.isPresent()){ String ouPath = getOUPath(orgOptional.get().getOr_path()); addUser(PinyinUtils.getCustomPinyin(employee.getEm_name()),employee.getEm_name(),ouPath,employee.getEm_password()); baseDao.updateByCondition("employee","em_adid='CN="+employee.getEm_name()+","+ouPath+"'","em_code='"+employee.getEm_code()+"'"); } } } } public void addUser(String userName,String displayName, String ouName, String password) { LdapConnection connection = ldapConnectionManager.getConnection(); Dn dn = null; logger.info("添加用户:{},displayName:{},ouName:{},password{}",userName,displayName,ouName,password); try { dn = new Dn("CN="+displayName+"," + ouName); Entry entry = new DefaultEntry( dn, "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: user", "sAMAccountName: " + userName, "userPrincipalName: " + userName + "@" + adConfig.getBaseDn().replace("DC=", "").replace(",", "."), "userPassword: " + password ); //处理中文写入异常问题 entry.add("cn",displayName); entry.add("displayName",displayName); entry.add("givenName", displayName.substring(0, 1)); entry.add("sn", displayName.substring(1)); connection.add(entry); } catch (Exception e) { logger.error("添加用户失败:{},错误{}",userName,e.getMessage()); } } public void deleteUser(String userDn, LdapConnection connection) { if(connection==null || !connection.isConnected()){ connection = ldapConnectionManager.getConnection(); } try { logger.info("删除用户:{}",userDn); Dn dn = new Dn(userDn); connection.delete(dn); logger.info("删除用户成功:{}",userDn); } catch (LdapException e) { logger.error("删除用户失败:{}",userDn); } } public void moveUser(String oldUserDnStr, String newRdnStr, LdapConnection connection) { logger.info("用户 {} 移动组织 {}", oldUserDnStr, newRdnStr); if (connection == null || !connection.isConnected()) { connection = ldapConnectionManager.getConnection(); } try { connection.moveAndRename(oldUserDnStr, newRdnStr,true); logger.info("用户 {} 已成功移动到组织 {}", oldUserDnStr, newRdnStr); } catch (Exception e) { logger.error("移动用户失败: {}", oldUserDnStr, e); throw new RuntimeException("移动用户失败: " + e.getMessage()); } } //初始化用户 public void initUser() throws IOException { LdapConnection connection = ldapConnectionManager.getConnection(); List employeeList = uasSyncService.getADUserList(); List adUserList = getUsers(connection); for (ADUser adUser : adUserList) { for (Employee employee : employeeList) { if(employee.getEm_name().equals(adUser.getUserCn())){ baseDao.updateByCondition("employee","em_adid='"+adUser.getUserDn()+"'", "em_code ='"+employee.getEm_code()+"'"); break; } } } } public List getUsers(LdapConnection connection) throws IOException { List userList = new ArrayList<>(); if(connection==null || !connection.isConnected()){ connection = ldapConnectionManager.getConnection(); } try { // 搜索所有用户 String filter = "(objectClass=organizationalPerson)"; EntryCursor result = connection.search( "OU=User,"+adConfig.getBaseDn(), // AD基础DN,从配置文件获取 filter, SearchScope.SUBTREE ); Entry entry; while (result.next()) { try { entry =result.get(); ADUser adUser = new ADUser(); adUser.setUserDn(entry.getDn().toString()); adUser.setUserCn(entry.get("cn").get().getString()); adUser.setAccountName(entry.get("sAMAccountName").get().getString()); adUser.setUserPrincipalName(entry.get("userPrincipalName").get().getString()); userList.add(adUser); } catch (CursorException e) { e.printStackTrace(); } } return userList; } catch (LdapException e) { e.printStackTrace(); } catch (CursorException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return null; } public void syncOrg() throws IOException { LdapConnection connection = ldapConnectionManager.getConnection(); List orgList = uasSyncService.getADOrgList(); logger.info("同步组织数量:{}",orgList.size()); List orgDns = getOrganizations(connection); //判断组织是否存在 for (HrOrg org : orgList) { if("已审核".equals(org.getOr_status())) { if(!orgDns.isEmpty()){ boolean isExist = false; for(String orgDn : orgDns){ String orgDescription = orgDn.substring(orgDn.indexOf(";")+1); String orgPath = orgDn.split(";")[0]; // 组织编号匹配成功 if(StringUtil.hasText(orgDescription) && orgDescription.equals(org.getOr_code())){ //组织编号一致 if(! orgPath.startsWith(getOUPath(org.getOr_path()))){ //组织路径不一致,则更新组织层级信息 logger.info("updateOrg 更新组织信息:old{},new{},orgCode{}",orgPath,getOUPath(org.getOr_path()) , orgDescription); updateOrg(orgPath, getOUPath(org.getOr_path()), connection); } isExist =true; break; } //组织编号匹配不成功,路径匹配相同 if(orgPath.equals(getOUPath(org.getOr_path()))){ if(!StringUtil.hasText(orgDescription)){ //更新AD域组织编号信息 updateOrgDescription(orgDn.split(";")[0], org.getOr_code()); } isExist =true; break; } } //不存在的组织 if(!isExist){ //添加组织 addOrg(org, connection); } } } } //判断AD域组织存在但没有已审核的组织信息,删除AD域组织 for(String orgDn : orgDns){ String orgDescription = orgDn.substring(orgDn.indexOf(";")+1); if(StringUtil.hasText(orgDescription)){ //未成功匹配的组织资料 if(!orgList.stream().anyMatch(org -> !"已禁用".equals(org.getOr_status()) && org.getOr_code().equals(orgDescription))){ //删除AD域组织 deleteOrg(orgDn.split(";")[0], connection); } } } } public void addOrg(HrOrg org, LdapConnection connection) { if(connection==null || !connection.isConnected()){ connection=ldapConnectionManager.getConnection(); } try { logger.info("添加组织{}",org.getOr_path()); Dn dn = new Dn(getOUPath(org.getOr_path())); Entry entry = new DefaultEntry( dn, "objectClass: top", "objectClass: organizationalUnit" ); entry.add("description", org.getOr_code()); connection.add(entry); logger.info("添加组织{}成功",org.getOr_path()); } catch (Exception e) { logger.error("添加组织失败",e); } } public void deleteOrg(String ouName, LdapConnection connection) { if(connection==null || !connection.isConnected()){ connection=ldapConnectionManager.getConnection(); } Dn dn = null; logger.info("删除组织{}",ouName); try { dn = new Dn( ouName ); String filter = "(objectClass=organizationalUnit)||(objectClass=user)"; EntryCursor result = connection.search( ouName, filter, SearchScope.ONELEVEL, // 搜索所有子节点 "dn" ); if (result.next()) { System.out.println(result.get().toString()); logger.info("组织下存在下级,无法删除{}",ouName); }else { connection.delete(dn); } } catch (Exception e) { throw new RuntimeException(e); } logger.info("删除组织{}成功",ouName); } public void updateOrg(String oldOUName,String newOuName, LdapConnection connection) { if(connection==null || !connection.isConnected()){ connection=ldapConnectionManager.getConnection(); } logger.info("更新组织{}为{}",oldOUName,newOuName); try { connection.moveAndRename(oldOUName,newOuName,true); } catch (Exception e) { logger.error(e.getMessage()); e.printStackTrace(); } logger.info("更新组织{}为{} 成功",oldOUName,newOuName); } /** * 修改自定义description属性 * */ public void updateOrgDescription(String orgName, String newDescription) throws IOException { LdapConnection connection = null; try { connection = ldapConnectionManager.getConnection(); Dn dn = new Dn( orgName); Entry entry = new DefaultEntry( dn, "objectClass: top", "objectClass: organizationalUnit" ); connection.modify(dn, new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, "description", newDescription)); } catch (Exception e) { logger.info("updateOrgDescription 更新组织描述失败:{}",e.getMessage()); }finally { if (connection != null) { connection.close(); } } } /** * 通过自定义description查看组织信息 * */ public List findOrganizationsByDescription(String description) throws IOException { LdapConnection connection = null; try { connection = ldapConnectionManager.getConnection(); // 设置LDAP搜索过滤器,匹配organizationalUnit且description包含搜索词 String filter = String.format("(&(objectClass=organizationalUnit)(description=*%s*))", description); EntryCursor result = connection.search( adConfig.getBaseDn(), // 从配置的基础DN开始搜索 filter, SearchScope.SUBTREE, // 搜索所有子节点 "dn" // 只返回DN属性 ); List orgDns = new ArrayList<>(); return orgDns; } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return null; } private String getOUPath(String orpath){ String[] paths=orpath.split("-"); String ouPath=""; for(int i=paths.length-1;i>=0;i--){ ouPath+="OU="+paths[i]+","; } return ouPath.substring(0,ouPath.length()-1)+",OU=User,"+adConfig.getBaseDn(); } private String getUserOUPath(String userPath){ return userPath.substring(userPath.indexOf(",")+1); } public List getOrganizations(LdapConnection connection) throws IOException { if(connection==null || !connection.isConnected()){ connection = ldapConnectionManager.getConnection(); } try { // 搜索所有组织单元 List orgDns = new ArrayList<>(); String filter = "(objectClass=organizationalUnit)"; EntryCursor result = connection.search( "OU=User,"+adConfig.getBaseDn(), // AD基础DN,从配置文件获取 filter, SearchScope.SUBTREE, // 搜索所有子节点 new String[] {"dn", "description"} ); Entry entry = null; while (result.next()) { try { entry =result.get(); //排除掉根目录 if(!entry.getDn().toString().startsWith("OU=User")){ orgDns.add(String.format("%s;%s", entry.getDn().toString(), StringUtil.hasText(entry.get("description"))?entry.get("description").get():"")); } } catch (CursorException e) { e.printStackTrace(); } } return orgDns; } catch (LdapException e) { e.printStackTrace(); } catch (CursorException e) { throw new RuntimeException(e); } finally { if (connection != null) { connection.close(); } } return null; } }