|
|
@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.github.pagehelper.util.StringUtil;
|
|
|
-import com.gtiit.shr.config.InsertBatchMethod;
|
|
|
import com.gtiit.shr.entity.enums.TaskNameEnum;
|
|
|
import com.gtiit.shr.entity.enums.TaskStatusEnum;
|
|
|
import com.gtiit.shr.entity.enums.TypeEnum;
|
|
|
@@ -32,8 +31,6 @@ import javax.naming.directory.DirContext;
|
|
|
import javax.naming.directory.ModificationItem;
|
|
|
import javax.naming.directory.SearchControls;
|
|
|
import javax.naming.directory.SearchResult;
|
|
|
-
|
|
|
-
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
@@ -43,7 +40,6 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* AD同步服务实现类
|
|
|
*/
|
|
|
@@ -52,9 +48,12 @@ import org.springframework.util.StringUtils;
|
|
|
public class ADSyncServiceImpl implements ADSyncService {
|
|
|
private static final Logger logger = LoggerFactory.getLogger(ADSyncServiceImpl.class);
|
|
|
// 定义需要同步的AD域用户字段
|
|
|
- public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn", "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5","AccountExpirationDate", "extensionAttribute8", "extensionAttribute9",
|
|
|
- "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};
|
|
|
+// public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn", "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5","AccountExpirationDate", "extensionAttribute8", "extensionAttribute9",
|
|
|
+// "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};
|
|
|
|
|
|
+ //删除"AccountExpirationDate",属性 202511
|
|
|
+ public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn", "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5", "extensionAttribute8", "extensionAttribute9",
|
|
|
+ "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};
|
|
|
@Autowired
|
|
|
FinalParamUtil finalParamUtil;
|
|
|
@Autowired
|
|
|
@@ -67,6 +66,8 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
private String root;
|
|
|
@Value("${api.ad.top}")
|
|
|
private String top;
|
|
|
+ @Value("${api.ad.alumni}")
|
|
|
+ private String alumniRoot; // 新增:Alumni根路径配置
|
|
|
@Value("${api.ad.userPassword}")
|
|
|
private String userPassword;
|
|
|
@Value("${scheduled.ad.person.able}")
|
|
|
@@ -75,17 +76,13 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
public String responeParamJson;
|
|
|
public SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
|
|
|
-
|
|
|
-
|
|
|
@Scheduled(
|
|
|
cron = "${scheduled.ad.person.cron}"
|
|
|
)
|
|
|
-
|
|
|
public void doSyncUsers() throws Exception {
|
|
|
if (TaskStatusEnum.ABLE.getValue().equals(this.adcronStatus)) {
|
|
|
this.synADUserToType((String)null, (String)null, (String)null, TypeEnum.AUTO.getValue());
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
// 手动同步AD域用户
|
|
|
@@ -93,8 +90,6 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
return this.synADUserToType(startDate, endDate, personNumber, TypeEnum.MANUAL.getValue());
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
// 同步AD域用户到指定类型
|
|
|
private JSONObject synADUserToType(String startDate, String endDate, String personNumber, String type) throws Exception {
|
|
|
JSONObject result = new JSONObject();
|
|
|
@@ -122,7 +117,6 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
try {
|
|
|
this.dc = this.adUtils.getDirContext();
|
|
|
|
|
|
-
|
|
|
Iterator dataIter = datas.iterator();
|
|
|
|
|
|
while(dataIter.hasNext()) {
|
|
|
@@ -134,7 +128,22 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
this.insertLog("同步日志:AD域用户同步失败!原因:【sAMAccountName】属性不能为空!", "否", type);
|
|
|
} else {
|
|
|
String name = "";
|
|
|
- String originName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", this.sAMAccountName);
|
|
|
+ String originName = "";
|
|
|
+
|
|
|
+ // 修改点:先搜索Alumni OU及其所有子OU
|
|
|
+ if (StringUtil.isNotEmpty(alumniRoot)) {
|
|
|
+ originName = this.searchUserInAlumniAndSubtree(this.dc, this.sAMAccountName);
|
|
|
+ if (StringUtil.isNotEmpty(originName)) {
|
|
|
+ logger.info("在Alumni路径中找到用户: {} -> {}", this.sAMAccountName, originName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果在Alumni中找到用户,使用Alumni中的路径
|
|
|
+ if (StringUtils.isEmpty(originName)) {
|
|
|
+ // 如果在Alumni中没找到,使用原来的搜索逻辑
|
|
|
+ originName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", this.sAMAccountName);
|
|
|
+ }
|
|
|
+
|
|
|
if (StringUtils.isEmpty(originName)) {
|
|
|
name = "CN=" + this.sAMAccountName + "," + this.root;
|
|
|
} else {
|
|
|
@@ -152,6 +161,14 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
Attributes attributes = this.dc.getAttributes(name);
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
sb.append("同步日志:AD域用户【").append(this.sAMAccountName).append("】同步,");
|
|
|
+
|
|
|
+ // 修改点:添加来源标识
|
|
|
+ if (name.contains("OU=Alumni")) {
|
|
|
+ sb.append("(来自Alumni路径) ");
|
|
|
+ } else {
|
|
|
+ sb.append("(来自常规路径) ");
|
|
|
+ }
|
|
|
+
|
|
|
String[] filedArr = fileds;
|
|
|
int arrlen = filedArr.length;
|
|
|
boolean isContinue = false;
|
|
|
@@ -163,24 +180,27 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
String extensionAttribute6Str = extensionAttribute6 != null ? (String)extensionAttribute6.get() : null;
|
|
|
|
|
|
try {
|
|
|
- String managerStr = dataMap.get("manager").toString();
|
|
|
- managerName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", managerStr);
|
|
|
+ String managerStr = dataMap.get("manager") == null ? "" : dataMap.get("manager").toString();
|
|
|
+ // 修改点:manager搜索也要支持Alumni路径
|
|
|
+ if (StringUtil.isNotEmpty(managerStr)) {
|
|
|
+ managerName = this.searchUserInAllPaths(this.dc, managerStr);
|
|
|
+ }
|
|
|
} catch (NamingException var38) {
|
|
|
- sb.append("同步“manager”属性失败,上级负责人【").append(dataMap.get("manager").toString()).append("】在AD域中不存在;");
|
|
|
+ String managerAccount = dataMap.get("manager") != null ? dataMap.get("manager").toString() : "null";
|
|
|
+ sb.append("同步manager属性失败,上级负责人【").append(managerAccount).append("】在AD域中不存在;");
|
|
|
}
|
|
|
//202506 针对兼职身份(extensionAttribute6 值为Part Time)且在AD中已有帐号的中国员工(extensionAttribute8 chinese),
|
|
|
//job title 和 department 属性值不变
|
|
|
- if ( null != extensionAttribute6Str && "Part Time".equals(extensionAttribute6Str) && null != extensionAttribute8Str &&
|
|
|
+ if (null != extensionAttribute6Str && "Part Time".equals(extensionAttribute6Str) && null != extensionAttribute8Str &&
|
|
|
"Chinese".equals(extensionAttribute8Str)) {
|
|
|
isContinue = true;
|
|
|
//15 Part Time 将兼职职位名称同步至 AD的extensionAttribute15
|
|
|
Attribute att15 = attributes.get("extensionAttribute15");
|
|
|
- String titleVal = dataMap.get("extensionAttribute15") == null ? "" : (String)dataMap.get("extensionAttribute15") ;
|
|
|
- if(null == att15 || StringUtil.isEmpty((String)att15.get())){
|
|
|
+ String titleVal = dataMap.get("extensionAttribute15") == null ? "" : (String)dataMap.get("extensionAttribute15");
|
|
|
+ if (null == att15 || StringUtil.isEmpty((String) att15.get())) {
|
|
|
msg = this.addInformation(name, "extensionAttribute15", titleVal, managerName);
|
|
|
-// msg = "新增extensionAttribute15属性成功!";
|
|
|
sb.append(msg);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
this.modifyInformation(name, "extensionAttribute15", titleVal, managerName);
|
|
|
msg = "更新extensionAttribute15属性成功!";
|
|
|
sb.append(msg);
|
|
|
@@ -188,12 +208,11 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
|
|
|
//Division 兼职所属部门同步到AD的Division属性
|
|
|
Attribute divisionAtt = attributes.get("Division");
|
|
|
- String departmentVal = (String)dataMap.get("Division");
|
|
|
- if(null == divisionAtt || StringUtil.isEmpty((String)divisionAtt.get())){
|
|
|
- msg = addInformation(name, "Division", departmentVal, managerName);
|
|
|
-// msg = "新增Division属性成功!";
|
|
|
+ String departmentVal = (String) dataMap.get("Division");
|
|
|
+ if (null == divisionAtt || StringUtil.isEmpty((String) divisionAtt.get())) {
|
|
|
+ msg = addInformation(name, "Division", departmentVal, managerName);
|
|
|
sb.append(msg);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
this.modifyInformation(name, "Division", departmentVal, managerName);
|
|
|
msg = "更新Division属性成功!";
|
|
|
sb.append(msg);
|
|
|
@@ -201,34 +220,36 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
|
|
|
//将用户的manager属性更新到新的AD属性 extensionAttribute14
|
|
|
Attribute extensionAttribute14 = attributes.get("extensionAttribute14");
|
|
|
- String extensionAttribute14Str = (String)dataMap.get("extensionAttribute14");
|
|
|
- if(null == extensionAttribute14 || StringUtil.isEmpty((String)extensionAttribute14.get())){
|
|
|
- msg = addInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
|
|
|
-// msg = "新增extensionAttribute14Str属性成功!";
|
|
|
+ String extensionAttribute14Str = (String) dataMap.get("extensionAttribute14");
|
|
|
+ if (null == extensionAttribute14 || StringUtil.isEmpty((String) extensionAttribute14.get())) {
|
|
|
+ msg = addInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
|
|
|
sb.append(msg);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
this.modifyInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
|
|
|
- msg = "更新extensionAttribute14Str属性成功!";
|
|
|
+ msg = "更新extensionAttribute14属性成功!";
|
|
|
sb.append(msg);
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
- for(int ii = 0; ii < arrlen; ++ii) {
|
|
|
+ // 修复bug:将userAccountControl的更新移到循环外部,避免重复设置
|
|
|
+ boolean userAccountControlUpdated = false;
|
|
|
+
|
|
|
+ for (int ii = 0; ii < arrlen; ++ii) {
|
|
|
field = filedArr[ii];
|
|
|
Attribute attribute = attributes.get(field);
|
|
|
- shr_value = (String)dataMap.get(field);
|
|
|
- ad_value = attribute != null ? (String)attribute.get() : null;
|
|
|
+ shr_value = (String) dataMap.get(field);
|
|
|
+ ad_value = attribute != null ? (String) attribute.get() : null;
|
|
|
|
|
|
if (("givenName".equals(field) || "displayName".equals(field)) && StringUtil.isNotEmpty(shr_value)) {
|
|
|
shr_value = shr_value.substring(0, 1).toUpperCase() + shr_value.substring(1);
|
|
|
}
|
|
|
|
|
|
//保留 这些人员AD 中现有的 job title 和 department 属性值不变
|
|
|
- if(isContinue && ("title".equals(field) || "department".equals(field) || "manager".equals(field)) ) {
|
|
|
+ if (isContinue && ("title".equals(field) || "department".equals(field) || "manager".equals(field))) {
|
|
|
continue;
|
|
|
}
|
|
|
- if("extensionAttribute14".equals(field) && "extensionAttribute15".equals(field) && "Division".equals(field)){
|
|
|
+ // 修复bug:使用||而不是&&,这样任何一个字段匹配都会跳过
|
|
|
+ if ("extensionAttribute14".equals(field) || "extensionAttribute15".equals(field) || "Division".equals(field)) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
@@ -236,11 +257,11 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
if (!shr_value.equals(ad_value)) {
|
|
|
try {
|
|
|
this.modifyInformation(name, field, shr_value, managerName);
|
|
|
- msg = "更新“" + field + "”属性成功!";
|
|
|
+ msg = "更新" + field + "属性成功!";
|
|
|
sb.append(msg);
|
|
|
} catch (NamingException var33) {
|
|
|
message = var33.getMessage();
|
|
|
- msg = "更新“" + field + "”属性失败,原因:" + message + ";";
|
|
|
+ msg = "更新" + field + "属性失败,原因:" + message + ";";
|
|
|
sb.append(msg);
|
|
|
}
|
|
|
}
|
|
|
@@ -251,34 +272,41 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
}
|
|
|
|
|
|
this.removeInformation(name, field, shr_value, managerName);
|
|
|
- msg = "删除“" + field + "”属性成功!";
|
|
|
+ msg = "删除" + field + "属性成功!";
|
|
|
sb.append(msg);
|
|
|
} catch (NamingException var37) {
|
|
|
message = var37.getMessage();
|
|
|
- msg = "删除“" + field + "”属性失败,原因:" + message + ";";
|
|
|
+ msg = "删除" + field + "属性失败,原因:" + message + ";";
|
|
|
sb.append(msg);
|
|
|
}
|
|
|
} else if (StringUtil.isNotEmpty(shr_value) && StringUtil.isEmpty(ad_value)) {
|
|
|
try {
|
|
|
msg = addInformation(name, field, shr_value, managerName);
|
|
|
-// msg = "新增“" + field + "”属性成功!";
|
|
|
sb.append(msg);
|
|
|
} catch (NamingException var32) {
|
|
|
+ // 修复bug:当addInformation失败时,不应该再调用modifyInformation
|
|
|
+ // 因为modifyInformation需要属性已存在,而这里属性不存在
|
|
|
message = var32.getMessage();
|
|
|
- msg = "新增“" + field + "”属性失败,原因:" + message + ";";
|
|
|
+ msg = "新增" + field + "属性失败,原因:" + message + ";";
|
|
|
sb.append(msg);
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- try {
|
|
|
+ // 修复bug:userAccountControl只在循环外设置一次
|
|
|
+ try {
|
|
|
+ Attribute uacAttribute = attributes.get("userAccountControl");
|
|
|
+ String currentUAC = uacAttribute != null ? (String) uacAttribute.get() : null;
|
|
|
+ if (!"544".equals(currentUAC)) {
|
|
|
this.modifyInformation(name, "userAccountControl", "544", managerName);
|
|
|
- msg = "添加“userAccountControl”属性成功!";
|
|
|
- sb.append(msg);
|
|
|
- } catch (NamingException var31) {
|
|
|
- message = var31.getMessage();
|
|
|
- msg = "添加“userAccountControl”属性失败,原因:" + message + ";";
|
|
|
+ msg = "更新userAccountControl属性成功!";
|
|
|
sb.append(msg);
|
|
|
+ userAccountControlUpdated = true;
|
|
|
}
|
|
|
+ } catch (NamingException var31) {
|
|
|
+ message = var31.getMessage();
|
|
|
+ msg = "更新userAccountControl属性失败,原因:" + message + ";";
|
|
|
+ sb.append(msg);
|
|
|
}
|
|
|
|
|
|
info = sb.toString();
|
|
|
@@ -289,44 +317,68 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
this.insertLog(sb.toString(), "是", type);
|
|
|
} catch (NamingException var39) {
|
|
|
try {
|
|
|
+ // 修复bug:创建用户时需要设置完整的objectClass
|
|
|
Attributes attrs = new BasicAttributes(true);
|
|
|
+// attrs.put("objectClass", new String[]{"top", "person", "organizationalPerson", "user"});
|
|
|
attrs.put("objectClass", "user");
|
|
|
attrs.put("sAMAccountName", dataMap.get("sAMAccountName"));
|
|
|
+ // 设置必须的属性
|
|
|
+// attrs.put("cn", dataMap.get("sAMAccountName")); // Common Name是必须的
|
|
|
+
|
|
|
this.dc.createSubcontext(name, attrs);
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
sb.append("同步日志:AD域用户【").append(this.sAMAccountName).append("】新增成功!");
|
|
|
|
|
|
+ // 修改点:新增用户时也标识来源
|
|
|
+ if (name.contains("OU=Alumni")) {
|
|
|
+ sb.append("(新增到Alumni路径) ");
|
|
|
+ } else {
|
|
|
+ sb.append("(新增到常规路径) ");
|
|
|
+ }
|
|
|
+
|
|
|
String[] filedArr = fileds;
|
|
|
int arrlen = filedArr.length;
|
|
|
|
|
|
- for(int i = 0; i < arrlen; i++) {
|
|
|
+ for (int i = 0; i < arrlen; i++) {
|
|
|
String filed = filedArr[i];
|
|
|
- shr_value = (String)dataMap.get(filed);
|
|
|
- if (!"sAMAccountName".equals(filed) && StringUtil.isNotEmpty((String)dataMap.get(filed))) {
|
|
|
+ shr_value = (String) dataMap.get(filed);
|
|
|
+ if (!"sAMAccountName".equals(filed) && StringUtil.isNotEmpty(shr_value)) {
|
|
|
try {
|
|
|
if ("manager".equals(filed)) {
|
|
|
- managerName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", shr_value);
|
|
|
- msg = addInformation(name, filed, shr_value, managerName);
|
|
|
+ // 修改点:manager搜索也要支持Alumni路径
|
|
|
+ String managerAccount = (String) dataMap.get(filed);
|
|
|
+ if (StringUtil.isNotEmpty(managerAccount)) {
|
|
|
+ managerName = this.searchUserInAllPaths(this.dc, managerAccount);
|
|
|
+ if (StringUtil.isNotEmpty(managerName)) {
|
|
|
+ msg = addInformation(name, filed, shr_value, managerName);
|
|
|
+ } else {
|
|
|
+ msg = "AD域中未找到manager账户: " + managerAccount;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ msg = "manager账户名为空";
|
|
|
+ }
|
|
|
} else {
|
|
|
msg = addInformation(name, filed, shr_value, managerName);
|
|
|
}
|
|
|
- sb.append(msg);
|
|
|
-
|
|
|
+ if (msg != null) {
|
|
|
+ sb.append(msg);
|
|
|
+ }
|
|
|
} catch (NamingException var30) {
|
|
|
msg = var30.getMessage();
|
|
|
- message = "添加“" + filed + "”属性失败,原因:" + msg + ";";
|
|
|
+ message = "添加" + filed + "属性失败,原因:" + msg + ";";
|
|
|
sb.append(message);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 为新创建的用户设置userAccountControl
|
|
|
try {
|
|
|
this.modifyInformation(name, "userAccountControl", "544", managerName);
|
|
|
- msg = "添加“userAccountControl”属性成功!";
|
|
|
+ msg = "添加userAccountControl属性成功!";
|
|
|
sb.append(msg);
|
|
|
} catch (NamingException var29) {
|
|
|
message = var29.getMessage();
|
|
|
- field = "添加“userAccountControl”属性失败,原因:" + message + ";";
|
|
|
+ field = "添加userAccountControl属性失败,原因:" + message + ";";
|
|
|
sb.append(field);
|
|
|
}
|
|
|
|
|
|
@@ -342,7 +394,7 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
result.put("code", "500");
|
|
|
result.put("msg", "AD服务器连接失败,失败原因为:" + var34.getMessage());
|
|
|
return result;
|
|
|
- }finally {
|
|
|
+ } finally {
|
|
|
if (this.dc != null) {
|
|
|
try {
|
|
|
this.dc.close();
|
|
|
@@ -362,24 +414,106 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 搜索用户,返回用户在AD域中的...
|
|
|
public String searchUser(DirContext ctx, String searchBase, String searchFilter, String username) throws Exception {
|
|
|
+ if (StringUtil.isEmpty(username)) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
SearchControls searchControls = new SearchControls();
|
|
|
searchControls.setSearchScope(2);
|
|
|
- NamingEnumeration<SearchResult> results = ctx.search(searchBase, searchFilter, new Object[]{username}, searchControls);
|
|
|
- String managerName = "";
|
|
|
-
|
|
|
- String mangerDN;
|
|
|
- SearchResult searchResult;
|
|
|
- for(mangerDN = ""; results.hasMoreElements(); mangerDN = searchResult.getNameInNamespace()) {
|
|
|
- searchResult = (SearchResult)results.nextElement();
|
|
|
- Attributes attributes = searchResult.getAttributes();
|
|
|
+
|
|
|
+ NamingEnumeration<SearchResult> results = null;
|
|
|
+ String mangerDN = "";
|
|
|
+
|
|
|
+ try {
|
|
|
+ results = ctx.search(searchBase, searchFilter, new Object[]{username}, searchControls);
|
|
|
+
|
|
|
+ if (results.hasMoreElements()) {
|
|
|
+ SearchResult searchResult = results.nextElement();
|
|
|
+ mangerDN = searchResult.getNameInNamespace();
|
|
|
+
|
|
|
+ // 记录重复用户(如果有)
|
|
|
+ while (results.hasMoreElements()) {
|
|
|
+ SearchResult additionalResult = results.nextElement();
|
|
|
+ logger.warn("在路径 {} 中找到重复用户 {}: {}", searchBase, username, additionalResult.getNameInNamespace());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (NamingException e) {
|
|
|
+ logger.error("搜索用户 {} 时发生错误: {}", username, e.getMessage());
|
|
|
+ throw e;
|
|
|
+ } finally {
|
|
|
+ // 修复bug:正确关闭结果集
|
|
|
+ if (results != null) {
|
|
|
+ try {
|
|
|
+ results.close();
|
|
|
+ } catch (NamingException e) {
|
|
|
+ logger.debug("关闭搜索结果集时发生错误: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return mangerDN;
|
|
|
}
|
|
|
|
|
|
+ // 新增方法:在Alumni OU及其所有子OU中搜索用户
|
|
|
+ private String searchUserInAlumniAndSubtree(DirContext ctx, String username) throws Exception {
|
|
|
+ if (StringUtil.isEmpty(alumniRoot) || StringUtil.isEmpty(username)) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ SearchControls searchControls = new SearchControls();
|
|
|
+ searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); // 搜索整个子树
|
|
|
+
|
|
|
+ NamingEnumeration<SearchResult> results = null;
|
|
|
+ try {
|
|
|
+ results = ctx.search(alumniRoot,
|
|
|
+ "(&(objectClass=user)(sAMAccountName={0}))",
|
|
|
+ new Object[]{username}, searchControls);
|
|
|
+
|
|
|
+ if (results.hasMoreElements()) {
|
|
|
+ SearchResult searchResult = results.nextElement();
|
|
|
+ String foundPath = searchResult.getNameInNamespace();
|
|
|
+ logger.info("在Alumni路径中找到用户 {}: {}", username, foundPath);
|
|
|
+
|
|
|
+ // 记录重复用户(如果有)
|
|
|
+ while (results.hasMoreElements()) {
|
|
|
+ SearchResult additionalResult = results.nextElement();
|
|
|
+ logger.warn("在Alumni路径中找到重复用户 {}: {}", username, additionalResult.getNameInNamespace());
|
|
|
+ }
|
|
|
+ return foundPath;
|
|
|
+ }
|
|
|
+ } catch (NamingException e) {
|
|
|
+ logger.warn("在Alumni OU中搜索用户{}时发生错误: {}", username, e.getMessage());
|
|
|
+ } finally {
|
|
|
+ // 修复bug:正确关闭结果集
|
|
|
+ if (results != null) {
|
|
|
+ try {
|
|
|
+ results.close();
|
|
|
+ } catch (NamingException e) {
|
|
|
+ logger.debug("关闭搜索结果集时发生错误: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增方法:在所有路径中搜索用户(先常规路径,后Alumni路径)
|
|
|
+ private String searchUserInAllPaths(DirContext ctx, String username) throws Exception {
|
|
|
+ if (StringUtil.isEmpty(username)) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 先在常规路径中搜索
|
|
|
+ String result = this.searchUser(ctx, this.top, "sAMAccountName={0}", username);
|
|
|
+ if (StringUtil.isNotEmpty(result)) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果在常规路径中没找到,在Alumni路径中搜索
|
|
|
+ return this.searchUserInAlumniAndSubtree(ctx, username);
|
|
|
+ }
|
|
|
|
|
|
// 插入同步日志
|
|
|
private void insertLog(String errorReason, String sucess, String type) {
|
|
|
@@ -405,53 +539,71 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
}
|
|
|
|
|
|
// 添加用户信息到AD域
|
|
|
- public String addInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
|
|
|
+ public String addInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
|
|
|
+ // 首先检查 fieldValue 是否为空
|
|
|
+ if (StringUtil.isEmpty(fieldValue)) {
|
|
|
+ logger.warn("跳过添加属性 {},因为值为空", field);
|
|
|
+ return "跳过添加属性 " + field + ",因为值为空";
|
|
|
+ }
|
|
|
+
|
|
|
if ("manager".equals(field)) {
|
|
|
- ModificationItem item = new ModificationItem(1, new BasicAttribute("manager", managerName));
|
|
|
- this.dc.modifyAttributes(name, new ModificationItem[]{item});
|
|
|
+ if (StringUtil.isNotEmpty(managerName)) {
|
|
|
+ ModificationItem item = new ModificationItem(1, new BasicAttribute("manager", managerName));
|
|
|
+ this.dc.modifyAttributes(name, new ModificationItem[]{item});
|
|
|
+ return "新增manager属性成功!";
|
|
|
+ } else {
|
|
|
+ logger.warn("managerName为空,不设置manager属性");
|
|
|
+ return "managerName为空,无法设置manager属性";
|
|
|
+ }
|
|
|
} else {
|
|
|
BasicAttributes basicAttributes = new BasicAttributes();
|
|
|
basicAttributes.put(field, fieldValue);
|
|
|
- //为空则不处理
|
|
|
- if(StringUtil.isEmpty(fieldValue)){
|
|
|
- return "新增"+field + "的值为空不进行处理";
|
|
|
+
|
|
|
+ try {
|
|
|
+ this.dc.modifyAttributes(name, 1, basicAttributes);
|
|
|
+ return "新增" + field + "属性成功!";
|
|
|
+ } catch (NamingException e) {
|
|
|
+ // 如果ADD失败,可能是因为属性已存在,尝试使用REPLACE
|
|
|
+ try {
|
|
|
+ this.dc.modifyAttributes(name, 2, basicAttributes);
|
|
|
+ return "更新" + field + "属性成功!";
|
|
|
+ } catch (NamingException e2) {
|
|
|
+ logger.error("添加属性 {} 失败: {}", field, e2.getMessage());
|
|
|
+ throw e2;
|
|
|
+ }
|
|
|
}
|
|
|
- this.dc.modifyAttributes(name, 1, basicAttributes);
|
|
|
}
|
|
|
- return "新增"+field + "的值为"+fieldValue+"已同步成功!";
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 修改AD域中的用户信息
|
|
|
public void modifyInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
|
|
|
if ("manager".equals(field)) {
|
|
|
- ModificationItem item = new ModificationItem(2, new BasicAttribute("manager", managerName));
|
|
|
- this.dc.modifyAttributes(name, new ModificationItem[]{item});
|
|
|
+ if (StringUtil.isNotEmpty(managerName)) {
|
|
|
+ ModificationItem item = new ModificationItem(2, new BasicAttribute("manager", managerName));
|
|
|
+ this.dc.modifyAttributes(name, new ModificationItem[]{item});
|
|
|
+ }
|
|
|
} else {
|
|
|
BasicAttributes basicAttributes = new BasicAttributes();
|
|
|
- basicAttributes.put(field, fieldValue);
|
|
|
+ basicAttributes.put(field, StringUtil.isEmpty(fieldValue) ? null : fieldValue);
|
|
|
//如果为空则删除
|
|
|
- if(StringUtil.isEmpty(fieldValue)){
|
|
|
+ if (StringUtil.isEmpty(fieldValue)) {
|
|
|
this.dc.modifyAttributes(name, 3, basicAttributes);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
this.dc.modifyAttributes(name, 2, basicAttributes);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 从AD域中移除用户信息
|
|
|
public void removeInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
|
|
|
if ("manager".equals(field)) {
|
|
|
- ModificationItem item = new ModificationItem(3, new BasicAttribute("manager", managerName));
|
|
|
+ ModificationItem item = new ModificationItem(3, new BasicAttribute("manager", null));
|
|
|
this.dc.modifyAttributes(name, new ModificationItem[]{item});
|
|
|
} else {
|
|
|
BasicAttributes basicAttributes = new BasicAttributes();
|
|
|
- basicAttributes.put(field, fieldValue);
|
|
|
+ basicAttributes.put(field, null);
|
|
|
this.dc.modifyAttributes(name, 3, basicAttributes);
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
public long getNTLongTimestamp(Date date) {
|
|
|
@@ -461,4 +613,4 @@ public class ADSyncServiceImpl implements ADSyncService {
|
|
|
timestamp += 116445312000000000L;
|
|
|
return timestamp;
|
|
|
}
|
|
|
-}
|
|
|
+}
|