This commit is contained in:
chenjianxing 2020-07-08 17:56:17 +08:00
commit 93b011a4ac
13 changed files with 105 additions and 80 deletions

View File

@ -54,14 +54,14 @@
</if>
</select>
<select id="listByMethod" resultType="io.metersphere.track.dto.TestCaseDTO">
SELECT id,name,status,project_id,type from api_test
SELECT id,name,status,project_id,"api" as type from api_test
<where>
<if test="request.projectId!=null">
and project_id=#{request.projectId}
</if>
</where>
UNION ALL
select id,name,status,project_id,type from load_test
select id,name,status,project_id,"perform" as type from load_test
<where>
<if test="request.projectId!=null">
and project_id= #{request.projectId}

View File

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

View File

@ -1,11 +1,9 @@
package io.metersphere.ldap.dao;
import java.util.List;
import io.metersphere.ldap.domain.Person;
public interface PersonRepo {
List findByName(String name);
String getDnForUser(String name);
Person getDnForUser(String name);
}

View File

@ -4,23 +4,28 @@ 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;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.query.SearchScope;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.naming.directory.DirContext;
import javax.naming.ldap.LdapContext;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import static org.springframework.ldap.query.LdapQueryBuilder.query;
@ -35,58 +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 List<Person> findByName(String name) {
LdapTemplate ldapTemplate = getConnection();
LdapQuery query = query().where("cn").is(name);
return ldapTemplate.search(query, getContextMapper());
}
@Override
public String getDnForUser(String uid) {
public Person getDnForUser(String username) {
LdapTemplate ldapTemplate = getConnection();
List<String> result = ldapTemplate.search(
query().where("cn").is(uid),
new AbstractContextMapper() {
@Override
protected String doMapFromContext(DirContextOperations ctx) {
return ctx.getNameInNamespace();
}
});
String filter = getUserFilter();
String ou = getUserOu();
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) {
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 getUserFilter() {
String filter = service.getValue(ParamConstants.LDAP.FILTER.getValue());
if (StringUtils.isBlank(filter)) {
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();
}
@ -95,6 +105,8 @@ public class PersonRepoImpl implements PersonRepo {
@Override
public Person doMapFromContext(DirContextOperations context) {
Person person = new Person();
person.setDn(context.getNameInNamespace());
person.setUid(context.getStringAttribute("uid"));
person.setCommonName(context.getStringAttribute("cn"));
person.setSurName(context.getStringAttribute("sn"));
person.setUsername(context.getStringAttribute("sAMAccountName"));
@ -107,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();
@ -118,19 +129,29 @@ 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);
ldapTemplate.setIgnorePartialResultException(true);
Map<String, Object> baseEnv = new Hashtable<>();
baseEnv.put("com.sun.jndi.ldap.connect.timeout", "3000");
baseEnv.put("com.sun.jndi.ldap.read.timeout", "3000");
sourceLdapCtx.setBaseEnvironmentProperties(baseEnv);
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"));
@ -140,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"));
}

View File

@ -14,7 +14,7 @@ public class Person {
@Id
private Name id;
@DnAttribute(value="uid",index = 3)
@DnAttribute(value="uid",index = 0)
private String uid;
@Attribute(name = "cn")
private String commonName;
@ -24,5 +24,6 @@ public class Person {
private String username;
@Attribute(name = "mail")
private String email;
private String dn;
}

View File

@ -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,32 +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<Person> 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"));
}
} catch (CommunicationException e) {
MSException.throwException(Translator.get("ldap_connect_fail"));
person = personRepo.getDnForUser(username);
personRepo.authenticate(person.getDn(), credentials);
} catch (AuthenticationException e) {
MSException.throwException(Translator.get("authentication_failed"));
}
personRepo.authenticate(dn, credentials);
return personList.get(0);
return person;
}
public void testConnect(LdapInfo ldap) {
personRepo.authenticate(ldap.getDn(), ldap.getPassword());
public void testConnect() {
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_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
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=连接失败
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=登录失败,请检查用户过滤器

View File

@ -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=登錄失敗,請檢查用戶過濾器

View File

@ -82,6 +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_filter'), trigger: ['change', 'blur']}
},
loginFormRules: {
username: {required: true, message: this.$t('ldap.input_username'), trigger: 'blur'},
@ -136,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;
},

View File

@ -612,7 +612,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',
@ -620,6 +620,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: {

View File

@ -609,7 +609,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': '编辑',
@ -617,6 +617,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: {

View File

@ -609,7 +609,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': '編輯',
@ -617,6 +617,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: {