This commit is contained in:
shiziyuan9527 2020-07-08 15:47:44 +08:00
parent fbb6fc0277
commit e45810701d
10 changed files with 77 additions and 65 deletions

View File

@ -66,7 +66,7 @@ public class LdapController {
@PostMapping("/test/connect") @PostMapping("/test/connect")
public void testConnect(@RequestBody LdapInfo ldapInfo) { public void testConnect(@RequestBody LdapInfo ldapInfo) {
ldapService.testConnect(ldapInfo); ldapService.testConnect();
} }
@PostMapping("/test/login") @PostMapping("/test/login")

View File

@ -4,13 +4,15 @@ package io.metersphere.ldap.dao;
import io.metersphere.commons.constants.ParamConstants; import io.metersphere.commons.constants.ParamConstants;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.EncryptUtils; import io.metersphere.commons.utils.EncryptUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.ldap.domain.Person; import io.metersphere.ldap.domain.Person;
import io.metersphere.service.SystemParameterService; import io.metersphere.service.SystemParameterService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.realm.ldap.LdapUtils; import org.apache.shiro.realm.ldap.LdapUtils;
import org.springframework.ldap.AuthenticationException; 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.*;
import org.springframework.ldap.core.support.AbstractContextMapper; import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.core.support.DefaultDirObjectFactory; import org.springframework.ldap.core.support.DefaultDirObjectFactory;
@ -38,59 +40,63 @@ public class PersonRepoImpl implements PersonRepo {
return authenticate(dn, credentials, ldapTemplate); 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; DirContext ctx = null;
try { try {
ctx = ldapTemplate.getContextSource().getContext(dn, credentials); 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; 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 { } finally {
// It is imperative that the created DirContext instance is always closed // It is imperative that the created DirContext instance is always closed
LdapUtils.closeContext((LdapContext) ctx); LdapUtils.closeContext((LdapContext) ctx);
} }
} }
@Override @Override
public Person getDnForUser(String username) { public Person getDnForUser(String username) {
LdapTemplate ldapTemplate = getConnection(); LdapTemplate ldapTemplate = getConnection();
String filter = getFilter();
List<Person> result = ldapTemplate.search( String filter = getUserFilter();
query().filter(filter, username), String ou = getUserOu();
getContextMapper());
System.out.println(result.toString()); List<Person> 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) { 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); return result.get(0);
} }
private String getFilter() { private String getUserFilter() {
String filter = service.getValue(ParamConstants.LDAP.FILTER.getValue()); String filter = service.getValue(ParamConstants.LDAP.FILTER.getValue());
if (StringUtils.isBlank(filter)) { if (StringUtils.isBlank(filter)) {
filter = "(sAMAccountName={0})"; MSException.throwException(Translator.get("ldap_user_filter_is_null"));
} }
return filter; 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() { protected ContextMapper getContextMapper() {
return new PersonContextMapper(); return new PersonContextMapper();
} }
@ -113,10 +119,9 @@ public class PersonRepoImpl implements PersonRepo {
String url = service.getValue(ParamConstants.LDAP.URL.getValue()); String url = service.getValue(ParamConstants.LDAP.URL.getValue());
String dn = service.getValue(ParamConstants.LDAP.DN.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()); String password = service.getValue(ParamConstants.LDAP.PASSWORD.getValue());
preConnect(url, dn, ou, password); preConnect(url, dn, password);
String credentials = EncryptUtils.aesDecrypt(password).toString(); String credentials = EncryptUtils.aesDecrypt(password).toString();
@ -124,7 +129,6 @@ public class PersonRepoImpl implements PersonRepo {
sourceLdapCtx.setUrl(url); sourceLdapCtx.setUrl(url);
sourceLdapCtx.setUserDn(dn); sourceLdapCtx.setUserDn(dn);
sourceLdapCtx.setPassword(credentials); sourceLdapCtx.setPassword(credentials);
sourceLdapCtx.setBase(ou);
sourceLdapCtx.setDirObjectFactory(DefaultDirObjectFactory.class); sourceLdapCtx.setDirObjectFactory(DefaultDirObjectFactory.class);
sourceLdapCtx.afterPropertiesSet(); sourceLdapCtx.afterPropertiesSet();
LdapTemplate ldapTemplate = new LdapTemplate(sourceLdapCtx); LdapTemplate ldapTemplate = new LdapTemplate(sourceLdapCtx);
@ -136,12 +140,18 @@ public class PersonRepoImpl implements PersonRepo {
ldapTemplate.setDefaultSearchScope(SearchScope.SUBTREE.getId()); ldapTemplate.setDefaultSearchScope(SearchScope.SUBTREE.getId());
// ldapTemplate 是否可用 // ldapTemplate 是否可用
try {
authenticate(dn, credentials, ldapTemplate); 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; 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)) { if (StringUtils.isBlank(url)) {
MSException.throwException(Translator.get("ldap_url_is_null")); 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")); MSException.throwException(Translator.get("ldap_dn_is_null"));
} }
if (StringUtils.isBlank(ou)) {
MSException.throwException(Translator.get("ldap_ou_is_null"));
}
if (StringUtils.isBlank(password)) { if (StringUtils.isBlank(password)) {
MSException.throwException(Translator.get("ldap_password_is_null")); MSException.throwException(Translator.get("ldap_password_is_null"));
} }

View File

@ -4,13 +4,11 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.controller.request.LoginRequest; import io.metersphere.controller.request.LoginRequest;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.ldap.dao.PersonRepoImpl; import io.metersphere.ldap.dao.PersonRepoImpl;
import io.metersphere.ldap.domain.LdapInfo;
import io.metersphere.ldap.domain.Person; import io.metersphere.ldap.domain.Person;
import org.springframework.ldap.CommunicationException; import org.springframework.ldap.AuthenticationException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
@Service @Service
public class LdapService { public class LdapService {
@ -20,34 +18,22 @@ public class LdapService {
public Person authenticate(LoginRequest request) { public Person authenticate(LoginRequest request) {
String dn = null;
String username = request.getUsername(); String username = request.getUsername();
String credentials = request.getPassword(); String credentials = request.getPassword();
Person person = null; Person person = null;
List<Person> personList = null;
try { 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); person = personRepo.getDnForUser(username);
dn = person.getDn(); personRepo.authenticate(person.getDn(), credentials);
} catch (CommunicationException e) { } catch (AuthenticationException e) {
MSException.throwException(Translator.get("ldap_connect_fail")); MSException.throwException(Translator.get("authentication_failed"));
} }
personRepo.authenticate(dn, credentials);
return person; return person;
} }
public void testConnect(LdapInfo ldap) { public void testConnect() {
personRepo.authenticate(ldap.getDn(), ldap.getPassword()); personRepo.getConnection();
} }
} }

View File

@ -120,9 +120,13 @@ ldap_url_is_null=LDAP address is empty
ldap_dn_is_null=LDAP binding DN is empty ldap_dn_is_null=LDAP binding DN is empty
ldap_ou_is_null=LDAP parameter OU is empty ldap_ou_is_null=LDAP parameter OU is empty
ldap_password_is_null=LDAP password 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 authentication_failed=User authentication failed,wrong user name or password
user_not_found_or_not_unique=User does not exist or is not unique user_not_found_or_not_unique=User does not exist or is not unique
find_more_user=Multiple users found find_more_user=Multiple users found
ldap_authentication_not_enabled=LDAP authentication is not enabled ldap_authentication_not_enabled=LDAP authentication is not enabled
login_fail_email_null=Login failed, user mailbox is empty 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

View File

@ -19,7 +19,7 @@ cannot_delete_current_user=无法删除当前登录用户
connection_failed=连接失败 connection_failed=连接失败
user_already_exists=该用户已存在于当前成员列表中 user_already_exists=该用户已存在于当前成员列表中
cannot_remove_current=无法移除当前登录用户 cannot_remove_current=无法移除当前登录用户
login_fail=失败 login_fail=失败
password_is_incorrect=密码不正确 password_is_incorrect=密码不正确
user_not_exist=用户不存在: user_not_exist=用户不存在:
user_has_been_disabled=用户已被禁用 user_has_been_disabled=用户已被禁用
@ -120,11 +120,15 @@ ldap_url_is_null=LDAP地址为空
ldap_dn_is_null=LDAP绑定DN为空 ldap_dn_is_null=LDAP绑定DN为空
ldap_ou_is_null=LDAP参数OU为空 ldap_ou_is_null=LDAP参数OU为空
ldap_password_is_null=LDAP密码为空 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=用户认证失败,用户名或密码错误 authentication_failed=用户认证失败,用户名或密码错误
user_not_found_or_not_unique=用户不存在或者不唯一 user_not_found_or_not_unique=用户不存在或者不唯一
find_more_user=查找到多个用户 find_more_user=查找到多个用户
ldap_authentication_not_enabled=LDAP认证未启用 ldap_authentication_not_enabled=LDAP认证未启用
login_fail_email_null=登录失败,用户邮箱为空 login_fail_email_null=登录失败,用户邮箱为空
login_fail_ou_error=登录失败请检查用户OU
login_fail_filter_error=登录失败,请检查用户过滤器

View File

@ -120,9 +120,13 @@ ldap_url_is_null=LDAP地址為空
ldap_dn_is_null=LDAP綁定DN為空 ldap_dn_is_null=LDAP綁定DN為空
ldap_ou_is_null=LDAP參數OU為空 ldap_ou_is_null=LDAP參數OU為空
ldap_password_is_null=LDAP密碼為空 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=用戶認證失敗,用戶名或密碼錯誤 authentication_failed=用戶認證失敗,用戶名或密碼錯誤
user_not_found_or_not_unique=用戶不存在或者不唯一 user_not_found_or_not_unique=用戶不存在或者不唯一
find_more_user=查找到多個用戶 find_more_user=查找到多個用戶
ldap_authentication_not_enabled=LDAP認證未啟用 ldap_authentication_not_enabled=LDAP認證未啟用
login_fail_email_null=登錄失敗,用戶郵箱為空 login_fail_email_null=登錄失敗,用戶郵箱為空
login_fail_ou_error=登錄失敗請檢查用戶OU
login_fail_filter_error=登錄失敗,請檢查用戶過濾器

View File

@ -82,7 +82,7 @@
dn: {required: true, message: this.$t('ldap.input_dn'), trigger: ['change', 'blur']}, dn: {required: true, message: this.$t('ldap.input_dn'), trigger: ['change', 'blur']},
password: {required: true, message: this.$t('ldap.input_password'), 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']}, 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: { loginFormRules: {
username: {required: true, message: this.$t('ldap.input_username'), trigger: 'blur'}, username: {required: true, message: this.$t('ldap.input_username'), trigger: 'blur'},
@ -137,6 +137,11 @@
return false; return false;
} }
if (!this.form.filter) {
this.$warning(this.$t('ldap.filter_cannot_be_empty'));
return false;
}
this.loginForm = {}; this.loginForm = {};
this.loginVisible = true; this.loginVisible = true;
}, },

View File

@ -599,7 +599,7 @@ export default {
'input_username': 'please enter user name', 'input_username': 'please enter user name',
'input_url_placeholder': 'Please enter the LDAP address (eg ldap://localhost:389)', 'input_url_placeholder': 'Please enter the LDAP address (eg ldap://localhost:389)',
'input_ou_placeholder': 'Enter user OU (use | to separate each OU)', '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_connect': 'Test Connection',
'test_login': 'Test Login', 'test_login': 'Test Login',
'edit': 'Edit', 'edit': 'Edit',
@ -607,6 +607,7 @@ export default {
'url_cannot_be_empty': 'LDAP address cannot be empty', 'url_cannot_be_empty': 'LDAP address cannot be empty',
'dn_cannot_be_empty': 'LDAP DN cannot be empty', 'dn_cannot_be_empty': 'LDAP DN cannot be empty',
'ou_cannot_be_empty': 'LDAP OU 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', 'password_cannot_be_empty': 'LDAP password cannot be empty',
}, },
schedule: { schedule: {

View File

@ -596,7 +596,7 @@ export default {
'input_username': '请输入用户名', 'input_username': '请输入用户名',
'input_url_placeholder': '请输入LDAP地址 (如 ldap://localhost:389)', 'input_url_placeholder': '请输入LDAP地址 (如 ldap://localhost:389)',
'input_ou_placeholder': '输入用户OU (使用|分隔各OU)', '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_connect': '测试连接',
'test_login': '测试登录', 'test_login': '测试登录',
'edit': '编辑', 'edit': '编辑',
@ -604,6 +604,7 @@ export default {
'url_cannot_be_empty': 'LDAP 地址不能为空', 'url_cannot_be_empty': 'LDAP 地址不能为空',
'dn_cannot_be_empty': 'LDAP DN不能为空', 'dn_cannot_be_empty': 'LDAP DN不能为空',
'ou_cannot_be_empty': 'LDAP OU不能为空', 'ou_cannot_be_empty': 'LDAP OU不能为空',
'filter_cannot_be_empty': 'LDAP 用户过滤器不能为空',
'password_cannot_be_empty': 'LDAP 密码不能为空', 'password_cannot_be_empty': 'LDAP 密码不能为空',
}, },
schedule: { schedule: {

View File

@ -596,7 +596,7 @@ export default {
'input_username': '請輸入用戶名', 'input_username': '請輸入用戶名',
'input_url_placeholder': '請輸入LDAP地址 (如 ldap://localhost:389)', 'input_url_placeholder': '請輸入LDAP地址 (如 ldap://localhost:389)',
'input_ou_placeholder': '輸入用戶OU (使用|分隔各OU)', '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_connect': '測試連接',
'test_login': '測試登錄', 'test_login': '測試登錄',
'edit': '編輯', 'edit': '編輯',
@ -604,6 +604,7 @@ export default {
'url_cannot_be_empty': 'LDAP 地址不能為空', 'url_cannot_be_empty': 'LDAP 地址不能為空',
'dn_cannot_be_empty': 'LDAP DN不能為空', 'dn_cannot_be_empty': 'LDAP DN不能為空',
'ou_cannot_be_empty': 'LDAP OU不能為空', 'ou_cannot_be_empty': 'LDAP OU不能為空',
'filter_cannot_be_empty': 'LDAP 用戶過濾器不能為空',
'password_cannot_be_empty': 'LDAP 密碼不能為空', 'password_cannot_be_empty': 'LDAP 密碼不能為空',
}, },
schedule: { schedule: {