From e45810701d6e1f881db726d7e3b535caaeb81a15 Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Wed, 8 Jul 2020 15:47:44 +0800 Subject: [PATCH] ldap --- .../ldap/controller/LdapController.java | 2 +- .../metersphere/ldap/dao/PersonRepoImpl.java | 74 ++++++++++--------- .../metersphere/ldap/service/LdapService.java | 28 ++----- .../resources/i18n/messages_en_US.properties | 8 +- .../resources/i18n/messages_zh_CN.properties | 8 +- .../resources/i18n/messages_zh_TW.properties | 6 +- .../settings/system/LdapSetting.vue | 7 +- frontend/src/i18n/en-US.js | 3 +- frontend/src/i18n/zh-CN.js | 3 +- frontend/src/i18n/zh-TW.js | 3 +- 10 files changed, 77 insertions(+), 65 deletions(-) diff --git a/backend/src/main/java/io/metersphere/ldap/controller/LdapController.java b/backend/src/main/java/io/metersphere/ldap/controller/LdapController.java index 3c89a17c4d..0956c66abf 100644 --- a/backend/src/main/java/io/metersphere/ldap/controller/LdapController.java +++ b/backend/src/main/java/io/metersphere/ldap/controller/LdapController.java @@ -66,7 +66,7 @@ public class LdapController { @PostMapping("/test/connect") public void testConnect(@RequestBody LdapInfo ldapInfo) { - ldapService.testConnect(ldapInfo); + ldapService.testConnect(); } @PostMapping("/test/login") diff --git a/backend/src/main/java/io/metersphere/ldap/dao/PersonRepoImpl.java b/backend/src/main/java/io/metersphere/ldap/dao/PersonRepoImpl.java index 00793de941..c6f98f31f9 100644 --- a/backend/src/main/java/io/metersphere/ldap/dao/PersonRepoImpl.java +++ b/backend/src/main/java/io/metersphere/ldap/dao/PersonRepoImpl.java @@ -4,13 +4,15 @@ package io.metersphere.ldap.dao; import io.metersphere.commons.constants.ParamConstants; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.EncryptUtils; -import io.metersphere.commons.utils.LogUtil; import io.metersphere.i18n.Translator; import io.metersphere.ldap.domain.Person; import io.metersphere.service.SystemParameterService; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.realm.ldap.LdapUtils; import org.springframework.ldap.AuthenticationException; +import org.springframework.ldap.InvalidNameException; +import org.springframework.ldap.InvalidSearchFilterException; +import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.core.*; import org.springframework.ldap.core.support.AbstractContextMapper; import org.springframework.ldap.core.support.DefaultDirObjectFactory; @@ -38,59 +40,63 @@ public class PersonRepoImpl implements PersonRepo { return authenticate(dn, credentials, ldapTemplate); } - private boolean authenticate(String dn, String credentials, LdapTemplate ldapTemplate) { + private boolean authenticate(String dn, String credentials, LdapTemplate ldapTemplate) throws AuthenticationException { DirContext ctx = null; try { ctx = ldapTemplate.getContextSource().getContext(dn, credentials); -// ldapTemplate.authenticate(dn, credentials); - // Take care here - if a base was specified on the ContextSource - // that needs to be removed from the user DN for the lookup to succeed. - // ctx.lookup(userDn); return true; - } catch (AuthenticationException e) { - LogUtil.error("ldap authenticate failed..." + e); - System.out.println("Login failed: " + e); - MSException.throwException(Translator.get("authentication_failed")); - return false; - } catch (Exception e) { - // Context creation failed - authentication did not succeed - LogUtil.error("ldap authenticate failed..." + e); - System.out.println("Login failed: " + e); - MSException.throwException(Translator.get("ldap_connect_fail")); - return false; } finally { // It is imperative that the created DirContext instance is always closed LdapUtils.closeContext((LdapContext) ctx); } } + @Override public Person getDnForUser(String username) { LdapTemplate ldapTemplate = getConnection(); - String filter = getFilter(); - List result = ldapTemplate.search( - query().filter(filter, username), - getContextMapper()); + String filter = getUserFilter(); + String ou = getUserOu(); - System.out.println(result.toString()); + List result = null; + try { + result = ldapTemplate.search(query().base(ou).filter(filter, username), getContextMapper()); + } catch (NameNotFoundException e) { + MSException.throwException(Translator.get("login_fail_ou_error")); + } catch (InvalidNameException e) { + MSException.throwException(Translator.get("login_fail_ou_error")); + } catch (InvalidSearchFilterException e) { + MSException.throwException(Translator.get("login_fail_filter_error")); + } if (result.size() != 1) { - throw new RuntimeException(Translator.get("user_not_found_or_not_unique")); + MSException.throwException(Translator.get("user_not_found_or_not_unique")); } + return result.get(0); } - private String getFilter() { + private String getUserFilter() { String filter = service.getValue(ParamConstants.LDAP.FILTER.getValue()); if (StringUtils.isBlank(filter)) { - filter = "(sAMAccountName={0})"; + MSException.throwException(Translator.get("ldap_user_filter_is_null")); } return filter; } + private String getUserOu() { + String ou = service.getValue(ParamConstants.LDAP.OU.getValue()); + + if (StringUtils.isBlank(ou)) { + MSException.throwException(Translator.get("ldap_ou_is_null")); + } + + return ou; + } + protected ContextMapper getContextMapper() { return new PersonContextMapper(); } @@ -113,10 +119,9 @@ public class PersonRepoImpl implements PersonRepo { String url = service.getValue(ParamConstants.LDAP.URL.getValue()); String dn = service.getValue(ParamConstants.LDAP.DN.getValue()); - String ou = service.getValue(ParamConstants.LDAP.OU.getValue()); String password = service.getValue(ParamConstants.LDAP.PASSWORD.getValue()); - preConnect(url, dn, ou, password); + preConnect(url, dn, password); String credentials = EncryptUtils.aesDecrypt(password).toString(); @@ -124,7 +129,6 @@ public class PersonRepoImpl implements PersonRepo { sourceLdapCtx.setUrl(url); sourceLdapCtx.setUserDn(dn); sourceLdapCtx.setPassword(credentials); - sourceLdapCtx.setBase(ou); sourceLdapCtx.setDirObjectFactory(DefaultDirObjectFactory.class); sourceLdapCtx.afterPropertiesSet(); LdapTemplate ldapTemplate = new LdapTemplate(sourceLdapCtx); @@ -136,12 +140,18 @@ public class PersonRepoImpl implements PersonRepo { ldapTemplate.setDefaultSearchScope(SearchScope.SUBTREE.getId()); // ldapTemplate 是否可用 - authenticate(dn, credentials, ldapTemplate); + try { + authenticate(dn, credentials, ldapTemplate); + } catch (AuthenticationException e) { + MSException.throwException(Translator.get("ldap_connect_fail_user")); + } catch (Exception e) { + MSException.throwException(Translator.get("ldap_connect_fail")); + } return ldapTemplate; } - private void preConnect(String url, String dn, String ou, String password) { + private void preConnect(String url, String dn, String password) { if (StringUtils.isBlank(url)) { MSException.throwException(Translator.get("ldap_url_is_null")); @@ -151,10 +161,6 @@ public class PersonRepoImpl implements PersonRepo { MSException.throwException(Translator.get("ldap_dn_is_null")); } - if (StringUtils.isBlank(ou)) { - MSException.throwException(Translator.get("ldap_ou_is_null")); - } - if (StringUtils.isBlank(password)) { MSException.throwException(Translator.get("ldap_password_is_null")); } diff --git a/backend/src/main/java/io/metersphere/ldap/service/LdapService.java b/backend/src/main/java/io/metersphere/ldap/service/LdapService.java index d0d0467a2c..849a1d1565 100644 --- a/backend/src/main/java/io/metersphere/ldap/service/LdapService.java +++ b/backend/src/main/java/io/metersphere/ldap/service/LdapService.java @@ -4,13 +4,11 @@ import io.metersphere.commons.exception.MSException; import io.metersphere.controller.request.LoginRequest; import io.metersphere.i18n.Translator; import io.metersphere.ldap.dao.PersonRepoImpl; -import io.metersphere.ldap.domain.LdapInfo; import io.metersphere.ldap.domain.Person; -import org.springframework.ldap.CommunicationException; +import org.springframework.ldap.AuthenticationException; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; @Service public class LdapService { @@ -20,34 +18,22 @@ public class LdapService { public Person authenticate(LoginRequest request) { - String dn = null; String username = request.getUsername(); String credentials = request.getPassword(); Person person = null; - List personList = null; + try { -// // select user by sAMAccountName -// personList = personRepo.findByName(username); -// -// if (personList.size() == 1) { -// dn = personRepo.getDnForUser(username); -// } else if (personList.size() == 0) { -// MSException.throwException(Translator.get("user_not_exist") + username); -// } else { -// MSException.throwException(Translator.get("find_more_user")); -// } person = personRepo.getDnForUser(username); - dn = person.getDn(); - } catch (CommunicationException e) { - MSException.throwException(Translator.get("ldap_connect_fail")); + personRepo.authenticate(person.getDn(), credentials); + } catch (AuthenticationException e) { + MSException.throwException(Translator.get("authentication_failed")); } - personRepo.authenticate(dn, credentials); return person; } - public void testConnect(LdapInfo ldap) { - personRepo.authenticate(ldap.getDn(), ldap.getPassword()); + public void testConnect() { + personRepo.getConnection(); } } diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 9dabf8d3c3..1d14244156 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -120,9 +120,13 @@ ldap_url_is_null=LDAP address is empty ldap_dn_is_null=LDAP binding DN is empty ldap_ou_is_null=LDAP parameter OU is empty ldap_password_is_null=LDAP password is empty -ldap_connect_fail=Connection failed +ldap_connect_fail=Connection LDAP failed +ldap_connect_fail_user=Connection LDAP failed, wrong DN or password bound +ldap_user_filter_is_null=LDAP user filter is empty authentication_failed=User authentication failed,wrong user name or password user_not_found_or_not_unique=User does not exist or is not unique find_more_user=Multiple users found ldap_authentication_not_enabled=LDAP authentication is not enabled -login_fail_email_null=Login failed, user mailbox is empty \ No newline at end of file +login_fail_email_null=Login failed, user mailbox is empty +login_fail_ou_error=Login failed, please check the user OU +login_fail_filter_error=Login failed, please check the user filter \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index fef626ea70..1a0bb91584 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -19,7 +19,7 @@ cannot_delete_current_user=无法删除当前登录用户 connection_failed=连接失败 user_already_exists=该用户已存在于当前成员列表中 cannot_remove_current=无法移除当前登录用户 -login_fail=登陆失败 +login_fail=登录失败 password_is_incorrect=密码不正确 user_not_exist=用户不存在: user_has_been_disabled=用户已被禁用 @@ -120,11 +120,15 @@ ldap_url_is_null=LDAP地址为空 ldap_dn_is_null=LDAP绑定DN为空 ldap_ou_is_null=LDAP参数OU为空 ldap_password_is_null=LDAP密码为空 -ldap_connect_fail=连接失败 +ldap_connect_fail=连接LDAP失败 +ldap_connect_fail_user=连接LDAP失败,绑定的DN或密码错误 +ldap_user_filter_is_null=LDAP用户过滤器为空 authentication_failed=用户认证失败,用户名或密码错误 user_not_found_or_not_unique=用户不存在或者不唯一 find_more_user=查找到多个用户 ldap_authentication_not_enabled=LDAP认证未启用 login_fail_email_null=登录失败,用户邮箱为空 +login_fail_ou_error=登录失败,请检查用户OU +login_fail_filter_error=登录失败,请检查用户过滤器 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index 04c273276d..79d31c162b 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -120,9 +120,13 @@ ldap_url_is_null=LDAP地址為空 ldap_dn_is_null=LDAP綁定DN為空 ldap_ou_is_null=LDAP參數OU為空 ldap_password_is_null=LDAP密碼為空 -ldap_connect_fail=連接失敗 +ldap_connect_fail=連接LDAP失敗 +ldap_connect_fail_user=連接LDAP失敗,綁定的DN或密碼錯誤 +ldap_user_filter_is_null=LDAP用戶過濾器為空 authentication_failed=用戶認證失敗,用戶名或密碼錯誤 user_not_found_or_not_unique=用戶不存在或者不唯一 find_more_user=查找到多個用戶 ldap_authentication_not_enabled=LDAP認證未啟用 login_fail_email_null=登錄失敗,用戶郵箱為空 +login_fail_ou_error=登錄失敗,請檢查用戶OU +login_fail_filter_error=登錄失敗,請檢查用戶過濾器 diff --git a/frontend/src/business/components/settings/system/LdapSetting.vue b/frontend/src/business/components/settings/system/LdapSetting.vue index 62e4a97fc7..25053afc78 100644 --- a/frontend/src/business/components/settings/system/LdapSetting.vue +++ b/frontend/src/business/components/settings/system/LdapSetting.vue @@ -82,7 +82,7 @@ dn: {required: true, message: this.$t('ldap.input_dn'), trigger: ['change', 'blur']}, password: {required: true, message: this.$t('ldap.input_password'), trigger: ['change', 'blur']}, ou: {required: true, message: this.$t('ldap.input_ou'), trigger: ['change', 'blur']}, - filter: {required: true, message: this.$t('ldap.input_ou'), trigger: ['change', 'blur']} + filter: {required: true, message: this.$t('ldap.input_filter'), trigger: ['change', 'blur']} }, loginFormRules: { username: {required: true, message: this.$t('ldap.input_username'), trigger: 'blur'}, @@ -137,6 +137,11 @@ return false; } + if (!this.form.filter) { + this.$warning(this.$t('ldap.filter_cannot_be_empty')); + return false; + } + this.loginForm = {}; this.loginVisible = true; }, diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 922d011d6c..107bc42045 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -599,7 +599,7 @@ export default { 'input_username': 'please enter user name', 'input_url_placeholder': 'Please enter the LDAP address (eg ldap://localhost:389)', 'input_ou_placeholder': 'Enter user OU (use | to separate each OU)', - 'input_filter_placeholder': 'Input filter [Possible options are cn or uid or sAMAccountName=%(user)s]', + 'input_filter_placeholder': 'Input filter [Possible options are cn or uid or sAMAccountName={0}, eg: (uid={0})]', 'test_connect': 'Test Connection', 'test_login': 'Test Login', 'edit': 'Edit', @@ -607,6 +607,7 @@ export default { 'url_cannot_be_empty': 'LDAP address cannot be empty', 'dn_cannot_be_empty': 'LDAP DN cannot be empty', 'ou_cannot_be_empty': 'LDAP OU cannot be empty', + 'filter_cannot_be_empty': 'LDAP user filter cannot be empty', 'password_cannot_be_empty': 'LDAP password cannot be empty', }, schedule: { diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 58a82c5099..45434392d5 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -596,7 +596,7 @@ export default { 'input_username': '请输入用户名', 'input_url_placeholder': '请输入LDAP地址 (如 ldap://localhost:389)', 'input_ou_placeholder': '输入用户OU (使用|分隔各OU)', - 'input_filter_placeholder': '输入过滤器 [可能的选项是cn或uid或sAMAccountName=%(user)s]', + 'input_filter_placeholder': '输入过滤器 [可能的选项是cn或uid或sAMAccountName={0}, 如:(uid={0})]', 'test_connect': '测试连接', 'test_login': '测试登录', 'edit': '编辑', @@ -604,6 +604,7 @@ export default { 'url_cannot_be_empty': 'LDAP 地址不能为空', 'dn_cannot_be_empty': 'LDAP DN不能为空', 'ou_cannot_be_empty': 'LDAP OU不能为空', + 'filter_cannot_be_empty': 'LDAP 用户过滤器不能为空', 'password_cannot_be_empty': 'LDAP 密码不能为空', }, schedule: { diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 9eda033d19..0ea369ad9b 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -596,7 +596,7 @@ export default { 'input_username': '請輸入用戶名', 'input_url_placeholder': '請輸入LDAP地址 (如 ldap://localhost:389)', 'input_ou_placeholder': '輸入用戶OU (使用|分隔各OU)', - 'input_filter_placeholder': '輸入過濾器 [可能的選項是cn或uid或sAMAccountName=%(user)s]', + 'input_filter_placeholder': '輸入過濾器 [可能的選項是cn或uid或sAMAccountName={0}, 如:(uid={0})]', 'test_connect': '測試連接', 'test_login': '測試登錄', 'edit': '編輯', @@ -604,6 +604,7 @@ export default { 'url_cannot_be_empty': 'LDAP 地址不能為空', 'dn_cannot_be_empty': 'LDAP DN不能為空', 'ou_cannot_be_empty': 'LDAP OU不能為空', + 'filter_cannot_be_empty': 'LDAP 用戶過濾器不能為空', 'password_cannot_be_empty': 'LDAP 密碼不能為空', }, schedule: {