diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/AuthenticationType.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/AuthenticationType.java index 5610a2285a..ecf1d4f8ea 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/AuthenticationType.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/AuthenticationType.java @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.dolphinscheduler.api.security; import com.baomidou.mybatisplus.annotation.EnumValue; @@ -24,6 +25,7 @@ import com.baomidou.mybatisplus.annotation.EnumValue; public enum AuthenticationType { PASSWORD(0, "verify via user name and password"), + LDAP(1, "verify via LDAP server"), ; AuthenticationType(int code, String desc) { diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/Authenticator.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/Authenticator.java index 8de1c7f407..99769b840b 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/Authenticator.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/Authenticator.java @@ -14,13 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.dolphinscheduler.api.security; import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.dao.entity.User; -import javax.servlet.http.HttpServletRequest; + import java.util.Map; +import javax.servlet.http.HttpServletRequest; + public interface Authenticator { /** * Verifying legality via username and password diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/SecurityConfig.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/SecurityConfig.java index 823c9bdfba..cb0d0646a1 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/SecurityConfig.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/SecurityConfig.java @@ -14,9 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.dolphinscheduler.api.security; -import org.apache.commons.lang.StringUtils; +import org.apache.dolphinscheduler.api.security.impl.ldap.LdapAuthenticator; +import org.apache.dolphinscheduler.api.security.impl.pwd.PasswordAuthenticator; +import org.apache.dolphinscheduler.common.utils.StringUtils; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -58,6 +62,9 @@ public class SecurityConfig { case PASSWORD: authenticator = new PasswordAuthenticator(); break; + case LDAP: + authenticator = new LdapAuthenticator(); + break; default: throw new IllegalStateException("Unexpected value: " + authenticationType); } diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/PasswordAuthenticator.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/AbstractAuthenticator.java similarity index 80% rename from dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/PasswordAuthenticator.java rename to dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/AbstractAuthenticator.java index 69930fc9d7..837e1f1f79 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/PasswordAuthenticator.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/AbstractAuthenticator.java @@ -14,9 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dolphinscheduler.api.security; + +package org.apache.dolphinscheduler.api.security.impl; import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.security.Authenticator; import org.apache.dolphinscheduler.api.service.SessionService; import org.apache.dolphinscheduler.api.service.UsersService; import org.apache.dolphinscheduler.api.utils.Result; @@ -24,26 +26,38 @@ import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.enums.Flag; import org.apache.dolphinscheduler.dao.entity.Session; import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.Collections; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import java.util.Collections; -import java.util.Map; -public class PasswordAuthenticator implements Authenticator { - private static final Logger logger = LoggerFactory.getLogger(PasswordAuthenticator.class); +public abstract class AbstractAuthenticator implements Authenticator { + private static final Logger logger = LoggerFactory.getLogger(AbstractAuthenticator.class); @Autowired private UsersService userService; @Autowired private SessionService sessionService; + /** + * user login and return user in db + * + * @param userId user identity field + * @param password user login password + * @param extra extra user login field + * @return user object in databse + */ + public abstract User login(String userId, String password, String extra); + @Override - public Result> authenticate(String username, String password, String extra) { + public Result> authenticate(String userId, String password, String extra) { Result> result = new Result<>(); - // verify username and password - User user = userService.queryUser(username, password); + User user = login(userId, password, extra); if (user == null) { result.setCode(Status.USER_NAME_PASSWD_ERROR.getCode()); result.setMsg(Status.USER_NAME_PASSWD_ERROR.getMsg()); @@ -64,7 +78,7 @@ public class PasswordAuthenticator implements Authenticator { result.setMsg(Status.LOGIN_SESSION_FAILED.getMsg()); return result; } - logger.info("sessionId : {}" , sessionId); + logger.info("sessionId : {}", sessionId); result.setData(Collections.singletonMap(Constants.SESSION_ID, sessionId)); result.setCode(Status.SUCCESS.getCode()); result.setMsg(Status.LOGIN_SUCCESS.getMsg()); @@ -81,4 +95,5 @@ public class PasswordAuthenticator implements Authenticator { //get user object from session return userService.queryUser(session.getUserId()); } + } diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticator.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticator.java new file mode 100644 index 0000000000..1604b79b6a --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticator.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.security.impl.ldap; + +import org.apache.dolphinscheduler.api.security.impl.AbstractAuthenticator; +import org.apache.dolphinscheduler.api.service.UsersService; +import org.apache.dolphinscheduler.dao.entity.User; + +import org.springframework.beans.factory.annotation.Autowired; + +public class LdapAuthenticator extends AbstractAuthenticator { + @Autowired + private UsersService usersService; + @Autowired + LdapService ldapService; + + @Override + public User login(String userId, String password, String extra) { + User user = null; + String ldapEmail = ldapService.ldapLogin(userId, password); + if (ldapEmail != null) { + //check if user exist + user = usersService.getUserByUserName(userId); + if (user == null) { + user = usersService.createUser(ldapService.getUserType(userId), userId, ldapEmail); + } + } + return user; + } +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapService.java new file mode 100644 index 0000000000..9f4fd1f0ae --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapService.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.security.impl.ldap; + +import org.apache.dolphinscheduler.common.enums.UserType; + +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.naming.ldap.InitialLdapContext; +import javax.naming.ldap.LdapContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Component +@Configuration +public class LdapService { + private static final Logger logger = LoggerFactory.getLogger(LdapService.class); + + @Value("${security.authentication.ldap.user.admin:null}") + private String adminUserId; + + @Value("${ldap.urls:null}") + private String ldapUrls; + + @Value("${ldap.base.dn:null}") + private String ldapBaseDn; + + @Value("${ldap.username:null}") + private String ldapSecurityPrincipal; + + @Value("${ldap.password:null}") + private String ldapPrincipalPassword; + + @Value("${ldap.user.identity.attribute:null}") + private String ldapUserIdentifyingAttribute; + + @Value("${ldap.user.email.attribute:null}") + private String ldapEmailAttribute; + + /*** + * get user type by configured admin userId + * @param userId login userId + * @return user type + */ + public UserType getUserType(String userId) { + return adminUserId.equalsIgnoreCase(userId) ? UserType.ADMIN_USER : UserType.GENERAL_USER; + } + + /** + * login by userId and return user email + * + * @param userId user identity id + * @param userPwd user login password + * @return user email + */ + public String ldapLogin(String userId, String userPwd) { + Properties searchEnv = getManagerLdapEnv(); + try { + //Connect to the LDAP server and Authenticate with a service user of whom we know the DN and credentials + LdapContext ctx = new InitialLdapContext(searchEnv, null); + SearchControls sc = new SearchControls(); + sc.setReturningAttributes(new String[]{ldapEmailAttribute}); + sc.setSearchScope(SearchControls.SUBTREE_SCOPE); + String searchFilter = String.format("(%s=%s)", ldapUserIdentifyingAttribute, userId); + //Search for the user you want to authenticate, search him with some attribute + NamingEnumeration results = ctx.search(ldapBaseDn, searchFilter, sc); + if (results.hasMore()) { + // get the users DN (distinguishedName) from the result + SearchResult result = results.next(); + NamingEnumeration attrs = result.getAttributes().getAll(); + while (attrs.hasMore()) { + //Open another connection to the LDAP server with the found DN and the password + searchEnv.put(Context.SECURITY_PRINCIPAL, result.getNameInNamespace()); + searchEnv.put(Context.SECURITY_CREDENTIALS, userPwd); + try { + new InitialDirContext(searchEnv); + } catch (Exception e) { + logger.warn("invalid ldap credentials or ldap search error", e); + return null; + } + Attribute attr = (Attribute) attrs.next(); + if (attr.getID().equals(ldapEmailAttribute)) { + return (String) attr.get(); + } + } + } + } catch (NamingException e) { + logger.error("ldap search error", e); + return null; + } + return null; + } + + /*** + * get ldap env fot ldap server search + * @return Properties + */ + Properties getManagerLdapEnv() { + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, ldapSecurityPrincipal); + env.put(Context.SECURITY_CREDENTIALS, ldapPrincipalPassword); + env.put(Context.PROVIDER_URL, ldapUrls); + return env; + } +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticator.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticator.java new file mode 100644 index 0000000000..a45bb84604 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticator.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.security.impl.pwd; + +import org.apache.dolphinscheduler.api.security.impl.AbstractAuthenticator; +import org.apache.dolphinscheduler.api.service.UsersService; +import org.apache.dolphinscheduler.dao.entity.User; + +import org.springframework.beans.factory.annotation.Autowired; + +public class PasswordAuthenticator extends AbstractAuthenticator { + @Autowired + private UsersService userService; + + @Override + public User login(String userId, String password, String extra) { + return userService.queryUser(userId, password); + } +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java index e47eb42cb5..3fb5f64346 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java @@ -14,10 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.dolphinscheduler.api.service; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.dolphinscheduler.api.dto.resources.ResourceComponent; import org.apache.dolphinscheduler.api.dto.resources.visitor.ResourceTreeVisitor; import org.apache.dolphinscheduler.api.enums.Status; @@ -29,20 +28,49 @@ import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.enums.Flag; import org.apache.dolphinscheduler.common.enums.ResourceType; import org.apache.dolphinscheduler.common.enums.UserType; -import org.apache.dolphinscheduler.common.utils.*; -import org.apache.dolphinscheduler.dao.entity.*; -import org.apache.dolphinscheduler.dao.mapper.*; +import org.apache.dolphinscheduler.common.utils.CollectionUtils; +import org.apache.dolphinscheduler.common.utils.EncryptionUtils; +import org.apache.dolphinscheduler.common.utils.HadoopUtils; +import org.apache.dolphinscheduler.common.utils.PropertyUtils; +import org.apache.dolphinscheduler.common.utils.StringUtils; +import org.apache.dolphinscheduler.dao.entity.AlertGroup; +import org.apache.dolphinscheduler.dao.entity.DatasourceUser; +import org.apache.dolphinscheduler.dao.entity.ProjectUser; +import org.apache.dolphinscheduler.dao.entity.Resource; +import org.apache.dolphinscheduler.dao.entity.ResourcesUser; +import org.apache.dolphinscheduler.dao.entity.Tenant; +import org.apache.dolphinscheduler.dao.entity.UDFUser; +import org.apache.dolphinscheduler.dao.entity.User; +import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper; +import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper; +import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper; +import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper; +import org.apache.dolphinscheduler.dao.mapper.ResourceMapper; +import org.apache.dolphinscheduler.dao.mapper.ResourceUserMapper; +import org.apache.dolphinscheduler.dao.mapper.TenantMapper; +import org.apache.dolphinscheduler.dao.mapper.UDFUserMapper; +import org.apache.dolphinscheduler.dao.mapper.UserMapper; import org.apache.dolphinscheduler.dao.utils.ResourceProcessDefinitionUtils; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.IOException; -import java.text.MessageFormat; -import java.util.*; -import java.util.stream.Collectors; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; /** * user service @@ -109,7 +137,7 @@ public class UsersService extends BaseService { String msg = this.checkUserParams(userName, userPassword, email, phone); if (!StringUtils.isEmpty(msg)) { - putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,msg); + putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, msg); return result; } if (!isAdmin(loginUser)) { @@ -126,12 +154,12 @@ public class UsersService extends BaseService { Tenant tenant = tenantMapper.queryById(tenantId); // resource upload startup - if (PropertyUtils.getResUploadStartupState()){ + if (PropertyUtils.getResUploadStartupState()) { // if tenant not exists - if (!HadoopUtils.getInstance().exists(HadoopUtils.getHdfsTenantDir(tenant.getTenantCode()))){ + if (!HadoopUtils.getInstance().exists(HadoopUtils.getHdfsTenantDir(tenant.getTenantCode()))) { createTenantDirIfNotExists(tenant.getTenantCode()); } - String userPath = HadoopUtils.getHdfsUserDir(tenant.getTenantCode(),user.getId()); + String userPath = HadoopUtils.getHdfsUserDir(tenant.getTenantCode(), user.getId()); HadoopUtils.getInstance().mkdir(userPath); } @@ -142,12 +170,12 @@ public class UsersService extends BaseService { @Transactional(rollbackFor = RuntimeException.class) public User createUser(String userName, - String userPassword, - String email, - int tenantId, - String phone, - String queue, - int state) { + String userPassword, + String email, + int tenantId, + String phone, + String queue, + int state) { User user = new User(); Date now = new Date(); @@ -161,7 +189,7 @@ public class UsersService extends BaseService { user.setUserType(UserType.GENERAL_USER); user.setCreateTime(now); user.setUpdateTime(now); - if (StringUtils.isEmpty(queue)){ + if (StringUtils.isEmpty(queue)) { queue = ""; } user.setQueue(queue); @@ -171,8 +199,40 @@ public class UsersService extends BaseService { return user; } + /*** + * create User for ldap login + */ + @Transactional(rollbackFor = Exception.class) + public User createUser(UserType userType, String userId, String email) { + User user = new User(); + Date now = new Date(); + + user.setUserName(userId); + user.setEmail(email); + // create general users, administrator users are currently built-in + user.setUserType(userType); + user.setCreateTime(now); + user.setUpdateTime(now); + user.setQueue(""); + + // save user + userMapper.insert(user); + return user; + } + + /** + * get user by user name + * + * @param userName user name + * @return exist user or null + */ + public User getUserByUserName(String userName) { + return userMapper.queryByUserNameAccurately(userName); + } + /** * query user by id + * * @param id id * @return user info */ @@ -182,6 +242,7 @@ public class UsersService extends BaseService { /** * query user + * * @param name name * @return user info */ @@ -203,6 +264,7 @@ public class UsersService extends BaseService { /** * get user id by user name + * * @param name user name * @return if name empty 0, user not exists -1, user exist user id */ @@ -242,7 +304,7 @@ public class UsersService extends BaseService { IPage scheduleList = userMapper.queryUserPaging(page, searchVal); PageInfo pageInfo = new PageInfo<>(pageNo, pageSize); - pageInfo.setTotalCount((int)scheduleList.getTotal()); + pageInfo.setTotalCount((int) scheduleList.getTotal()); pageInfo.setLists(scheduleList.getRecords()); result.put(Constants.DATA_LIST, pageInfo); putMsg(result, Status.SUCCESS); @@ -261,7 +323,7 @@ public class UsersService extends BaseService { * @param email email * @param tenantId tennat id * @param phone phone - * @param queue queue + * @param queue queue * @return update result code * @throws Exception exception */ @@ -286,8 +348,8 @@ public class UsersService extends BaseService { } if (StringUtils.isNotEmpty(userName)) { - if (!CheckUtils.checkUserName(userName)){ - putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,userName); + if (!CheckUtils.checkUserName(userName)) { + putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, userName); return result; } @@ -300,23 +362,23 @@ public class UsersService extends BaseService { } if (StringUtils.isNotEmpty(userPassword)) { - if (!CheckUtils.checkPassword(userPassword)){ - putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,userPassword); + if (!CheckUtils.checkPassword(userPassword)) { + putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, userPassword); return result; } user.setUserPassword(EncryptionUtils.getMd5(userPassword)); } if (StringUtils.isNotEmpty(email)) { - if (!CheckUtils.checkEmail(email)){ - putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,email); + if (!CheckUtils.checkEmail(email)) { + putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, email); return result; } user.setEmail(email); } if (StringUtils.isNotEmpty(phone) && !CheckUtils.checkPhone(phone)) { - putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,phone); + putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, phone); return result; } user.setPhone(phone); @@ -332,13 +394,13 @@ public class UsersService extends BaseService { Tenant newTenant = tenantMapper.queryById(tenantId); if (newTenant != null) { // if hdfs startup - if (PropertyUtils.getResUploadStartupState() && oldTenant != null){ + if (PropertyUtils.getResUploadStartupState() && oldTenant != null) { String newTenantCode = newTenant.getTenantCode(); String oldResourcePath = HadoopUtils.getHdfsResDir(oldTenant.getTenantCode()); String oldUdfsPath = HadoopUtils.getHdfsUdfDir(oldTenant.getTenantCode()); // if old tenant dir exists - if (HadoopUtils.getInstance().exists(oldResourcePath)){ + if (HadoopUtils.getInstance().exists(oldResourcePath)) { String newResourcePath = HadoopUtils.getHdfsResDir(newTenantCode); String newUdfsPath = HadoopUtils.getHdfsUdfDir(newTenantCode); @@ -361,18 +423,18 @@ public class UsersService extends BaseService { } //Delete the user from the old tenant directory - String oldUserPath = HadoopUtils.getHdfsUserDir(oldTenant.getTenantCode(),userId); + String oldUserPath = HadoopUtils.getHdfsUserDir(oldTenant.getTenantCode(), userId); HadoopUtils.getInstance().delete(oldUserPath, true); - }else { + } else { // if old tenant dir not exists , create createTenantDirIfNotExists(oldTenant.getTenantCode()); } - if (HadoopUtils.getInstance().exists(HadoopUtils.getHdfsTenantDir(newTenant.getTenantCode()))){ + if (HadoopUtils.getInstance().exists(HadoopUtils.getHdfsTenantDir(newTenant.getTenantCode()))) { //create user in the new tenant directory - String newUserPath = HadoopUtils.getHdfsUserDir(newTenant.getTenantCode(),user.getId()); + String newUserPath = HadoopUtils.getHdfsUserDir(newTenant.getTenantCode(), user.getId()); HadoopUtils.getInstance().mkdir(newUserPath); - }else { + } else { // if new tenant dir not exists , create createTenantDirIfNotExists(newTenant.getTenantCode()); } @@ -414,7 +476,7 @@ public class UsersService extends BaseService { if (user != null) { if (PropertyUtils.getResUploadStartupState()) { - String userPath = HadoopUtils.getHdfsUserDir(user.getTenantCode(),id); + String userPath = HadoopUtils.getHdfsUserDir(user.getTenantCode(), id); if (HadoopUtils.getInstance().exists(userPath)) { HadoopUtils.getInstance().delete(userPath, true); } @@ -493,7 +555,7 @@ public class UsersService extends BaseService { return result; } User user = userMapper.selectById(userId); - if(user == null){ + if (user == null) { putMsg(result, Status.USER_NOT_EXIST, userId); return result; } @@ -504,7 +566,7 @@ public class UsersService extends BaseService { // need authorize resource id set for (String resourceFullId : resourceFullIdArr) { String[] resourceIdArr = resourceFullId.split("-"); - for (int i=0;i<=resourceIdArr.length-1;i++) { + for (int i = 0; i <= resourceIdArr.length - 1; i++) { int resourceIdValue = Integer.parseInt(resourceIdArr[i]); needAuthorizeResIds.add(resourceIdValue); } @@ -531,7 +593,7 @@ public class UsersService extends BaseService { if (CollectionUtils.isNotEmpty(resourceIdSet)) { logger.error("can't be deleted,because it is used of process definition"); for (Integer resId : resourceIdSet) { - logger.error("resource id:{} is used of process definition {}",resId,resourceProcessMap.get(resId)); + logger.error("resource id:{} is used of process definition {}", resId, resourceProcessMap.get(resId)); } putMsg(result, Status.RESOURCE_IS_USED); return result; @@ -558,7 +620,7 @@ public class UsersService extends BaseService { resourcesUser.setResourcesId(resourceIdValue); if (resource.isDirectory()) { resourcesUser.setPerm(Constants.AUTHORIZE_READABLE_PERM); - }else{ + } else { resourcesUser.setPerm(Constants.AUTHORIZE_WRITABLE_PERM); } @@ -591,7 +653,7 @@ public class UsersService extends BaseService { return result; } User user = userMapper.selectById(userId); - if(user == null){ + if (user == null) { putMsg(result, Status.USER_NOT_EXIST, userId); return result; } @@ -626,7 +688,7 @@ public class UsersService extends BaseService { * * @param loginUser login user * @param userId user id - * @param datasourceIds data source id array + * @param datasourceIds data source id array * @return grant result code */ @Transactional(rollbackFor = RuntimeException.class) @@ -639,7 +701,7 @@ public class UsersService extends BaseService { return result; } User user = userMapper.selectById(userId); - if(user == null){ + if (user == null) { putMsg(result, Status.USER_NOT_EXIST, userId); return result; } @@ -738,7 +800,7 @@ public class UsersService extends BaseService { return result; } - List userList = userMapper.selectList(null ); + List userList = userMapper.selectList(null); result.put(Constants.DATA_LIST, userList); putMsg(result, Status.SUCCESS); @@ -782,7 +844,7 @@ public class UsersService extends BaseService { return result; } - List userList = userMapper.selectList(null ); + List userList = userMapper.selectList(null); List resultUsers = new ArrayList<>(); Set userSet = null; if (userList != null && userList.size() > 0) { @@ -833,11 +895,6 @@ public class UsersService extends BaseService { } /** - * - * @param userName - * @param password - * @param email - * @param phone * @return if check failed return the field, otherwise return null */ private String checkUserParams(String userName, String password, String email, String phone) { @@ -862,35 +919,36 @@ public class UsersService extends BaseService { /** * copy resource files + * * @param resourceComponent resource component - * @param srcBasePath src base path - * @param dstBasePath dst base path - * @throws IOException io exception + * @param srcBasePath src base path + * @param dstBasePath dst base path + * @throws IOException io exception */ private void copyResourceFiles(ResourceComponent resourceComponent, String srcBasePath, String dstBasePath) throws IOException { List components = resourceComponent.getChildren(); if (CollectionUtils.isNotEmpty(components)) { - for (ResourceComponent component:components) { + for (ResourceComponent component : components) { // verify whether exist - if (!HadoopUtils.getInstance().exists(String.format("%s/%s",srcBasePath,component.getFullName()))){ - logger.error("resource file: {} not exist,copy error",component.getFullName()); + if (!HadoopUtils.getInstance().exists(String.format("%s/%s", srcBasePath, component.getFullName()))) { + logger.error("resource file: {} not exist,copy error", component.getFullName()); throw new ServiceException(Status.RESOURCE_NOT_EXIST); } if (!component.isDirctory()) { // copy it to dst - HadoopUtils.getInstance().copy(String.format("%s/%s",srcBasePath,component.getFullName()),String.format("%s/%s",dstBasePath,component.getFullName()),false,true); + HadoopUtils.getInstance().copy(String.format("%s/%s", srcBasePath, component.getFullName()), String.format("%s/%s", dstBasePath, component.getFullName()), false, true); continue; } - if(CollectionUtils.isEmpty(component.getChildren())) { + if (CollectionUtils.isEmpty(component.getChildren())) { // if not exist,need create it - if (!HadoopUtils.getInstance().exists(String.format("%s/%s",dstBasePath,component.getFullName()))) { - HadoopUtils.getInstance().mkdir(String.format("%s/%s",dstBasePath,component.getFullName())); + if (!HadoopUtils.getInstance().exists(String.format("%s/%s", dstBasePath, component.getFullName()))) { + HadoopUtils.getInstance().mkdir(String.format("%s/%s", dstBasePath, component.getFullName())); } - }else{ - copyResourceFiles(component,srcBasePath,dstBasePath); + } else { + copyResourceFiles(component, srcBasePath, dstBasePath); } } } @@ -899,10 +957,10 @@ public class UsersService extends BaseService { /** * register user, default state is 0, default tenant_id is 1, no phone, no queue * - * @param userName user name - * @param userPassword user password + * @param userName user name + * @param userPassword user password * @param repeatPassword repeat password - * @param email email + * @param email email * @return register result code * @throws Exception exception */ @@ -914,7 +972,7 @@ public class UsersService extends BaseService { String msg = this.checkUserParams(userName, userPassword, email, ""); if (!StringUtils.isEmpty(msg)) { - putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR,msg); + putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, msg); return result; } @@ -932,7 +990,7 @@ public class UsersService extends BaseService { * activate user, only system admin have permission, change user state code 0 to 1 * * @param loginUser login user - * @param userName user name + * @param userName user name * @return create result code */ public Map activateUser(User loginUser, String userName) { @@ -944,7 +1002,7 @@ public class UsersService extends BaseService { return result; } - if (!CheckUtils.checkUserName(userName)){ + if (!CheckUtils.checkUserName(userName)) { putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, userName); return result; } diff --git a/dolphinscheduler-api/src/main/resources/application-api.properties b/dolphinscheduler-api/src/main/resources/application-api.properties index 92217a7fe4..e2cabfac67 100644 --- a/dolphinscheduler-api/src/main/resources/application-api.properties +++ b/dolphinscheduler-api/src/main/resources/application-api.properties @@ -45,6 +45,18 @@ spring.messages.basename=i18n/messages # Authentication types (supported types: PASSWORD) security.authentication.type=PASSWORD - +#============================================================================ +# LDAP Config +# mock ldap server from https://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/ +#============================================================================ +# admin userId +#security.authentication.ldap.user.admin=read-only-admin +# ldap server config +#ldap.urls=ldap://ldap.forumsys.com:389/ +#ldap.base.dn=dc=example,dc=com +#ldap.username=cn=read-only-admin,dc=example,dc=com +#ldap.password=password +#ldap.user.identity.attribute=uid +#ldap.user.email.attribute=mail diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigLDAPTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigLDAPTest.java new file mode 100644 index 0000000000..a96cec9158 --- /dev/null +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigLDAPTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.security; + +import org.apache.dolphinscheduler.api.ApiApplicationServer; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ApiApplicationServer.class) +@TestPropertySource(properties = { + "security.authentication.type=LDAP", +}) +public class SecurityConfigLDAPTest { + + @Autowired + private SecurityConfig securityConfig; + + @Test + public void testAuthenticator() { + Authenticator authenticator = securityConfig.authenticator(); + Assert.assertNotNull(authenticator); + } +} diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigPasswordTest.java similarity index 97% rename from dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigTest.java rename to dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigPasswordTest.java index 98e6829ac6..cf1023e786 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigPasswordTest.java @@ -14,9 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.dolphinscheduler.api.security; import org.apache.dolphinscheduler.api.ApiApplicationServer; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,7 +32,7 @@ import org.springframework.test.context.junit4.SpringRunner; @TestPropertySource(properties = { "security.authentication.type=PASSWORD", }) -public class SecurityConfigTest { +public class SecurityConfigPasswordTest { @Autowired private SecurityConfig securityConfig; diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticatorTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticatorTest.java new file mode 100644 index 0000000000..00612597b7 --- /dev/null +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticatorTest.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.security.impl.ldap; + +import static org.mockito.Mockito.when; + +import org.apache.dolphinscheduler.api.ApiApplicationServer; +import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.service.SessionService; +import org.apache.dolphinscheduler.api.service.UsersService; +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.common.enums.Flag; +import org.apache.dolphinscheduler.common.enums.UserType; +import org.apache.dolphinscheduler.dao.entity.Session; +import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.Date; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ApiApplicationServer.class) +@TestPropertySource( + properties = { + "security.authentication.type=LDAP", + "security.authentication.ldap.user.admin=read-only-admin", + "ldap.urls=ldap://ldap.forumsys.com:389/", + "ldap.base.dn=dc=example,dc=com", + "ldap.username=cn=read-only-admin,dc=example,dc=com", + "ldap.password=password", + "ldap.user.identity.attribute=uid", + "ldap.user.email.attribute=mail", + }) +public class LdapAuthenticatorTest { + private static Logger logger = LoggerFactory.getLogger(LdapAuthenticatorTest.class); + @Autowired + protected AutowireCapableBeanFactory beanFactory; + @MockBean + private LdapService ldapService; + @MockBean + private SessionService sessionService; + @MockBean + private UsersService usersService; + + private LdapAuthenticator ldapAuthenticator; + + //test param + private User mockUser; + private Session mockSession; + + private String ldapUid = "test"; + private String ldapUserPwd = "password"; + private String ldapEmail = "test@example.com"; + private String ip = "127.0.0.1"; + private UserType userType = UserType.GENERAL_USER; + + @Before + public void setUp() { + ldapAuthenticator = new LdapAuthenticator(); + beanFactory.autowireBean(ldapAuthenticator); + + mockUser = new User(); + mockUser.setId(1); + mockUser.setUserName(ldapUid); + mockUser.setEmail(ldapEmail); + mockUser.setUserType(userType); + mockUser.setState(Flag.YES.getCode()); + + mockSession = new Session(); + mockSession.setId(UUID.randomUUID().toString()); + mockSession.setIp(ip); + mockSession.setUserId(1); + mockSession.setLastLoginTime(new Date()); + + } + + @Test + public void testAuthenticate() { + when(usersService.createUser(userType, ldapUid, ldapEmail)).thenReturn(mockUser); + when(usersService.getUserByUserName(ldapUid)).thenReturn(mockUser); + when(sessionService.createSession(mockUser, ip)).thenReturn(mockSession.getId()); + + when(ldapService.ldapLogin(ldapUid, ldapUserPwd)).thenReturn(ldapEmail); + + Result result = ldapAuthenticator.authenticate(ldapUid, ldapUserPwd, ip); + Assert.assertEquals(Status.SUCCESS.getCode(), (int) result.getCode()); + logger.info(result.toString()); + + when(sessionService.createSession(mockUser, ip)).thenReturn(null); + result = ldapAuthenticator.authenticate(ldapUid, ldapUserPwd, ip); + Assert.assertEquals(Status.LOGIN_SESSION_FAILED.getCode(), (int) result.getCode()); + + when(sessionService.createSession(mockUser, ip)).thenReturn(mockSession.getId()); + when(usersService.getUserByUserName(ldapUid)).thenReturn(null); + result = ldapAuthenticator.authenticate(ldapUid, ldapUserPwd, ip); + Assert.assertEquals(Status.USER_NAME_PASSWD_ERROR.getCode(), (int) result.getCode()); + } + + @Test + public void testGetAuthUser() { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + when(usersService.queryUser(mockUser.getId())).thenReturn(mockUser); + when(sessionService.getSession(request)).thenReturn(mockSession); + + User user = ldapAuthenticator.getAuthUser(request); + Assert.assertNotNull(user); + + when(sessionService.getSession(request)).thenReturn(null); + user = ldapAuthenticator.getAuthUser(request); + Assert.assertNull(user); + } +} diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapServiceTest.java new file mode 100644 index 0000000000..8cd435f954 --- /dev/null +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapServiceTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.security.impl.ldap; + +import org.apache.dolphinscheduler.api.ApiApplicationServer; +import org.apache.dolphinscheduler.common.enums.UserType; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ApiApplicationServer.class) +@TestPropertySource( + properties = { + "security.authentication.type=LDAP", + "security.authentication.ldap.user.admin=read-only-admin", + "ldap.urls=ldap://ldap.forumsys.com:389/", + "ldap.base.dn=dc=example,dc=com", + "ldap.username=cn=read-only-admin,dc=example,dc=com", + "ldap.password=password", + "ldap.user.identity.attribute=uid", + "ldap.user.email.attribute=mail", + }) +public class LdapServiceTest { + @Autowired + protected AutowireCapableBeanFactory beanFactory; + + private LdapService ldapService; + + @Before + public void setUp() { + ldapService = new LdapService(); + beanFactory.autowireBean(ldapService); + } + + @Test + public void getUserType() { + UserType userType = ldapService.getUserType("read-only-admin"); + Assert.assertEquals(UserType.ADMIN_USER, userType); + } + + @Test + public void ldapLogin() { + String email = ldapService.ldapLogin("tesla", "password"); + Assert.assertEquals("tesla@ldap.forumsys.com", email); + + String email2 = ldapService.ldapLogin("tesla", "error password"); + Assert.assertNull(email2); + } + + @Test + public void ldapLoginError() { + String email = ldapService.ldapLogin("tesla", "password"); + Assert.assertEquals("tesla@ldap.forumsys.com", email); + + String email2 = ldapService.ldapLogin("tesla", "error password"); + Assert.assertNull(email2); + } +} \ No newline at end of file diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/PasswordAuthenticatorTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticatorTest.java similarity index 91% rename from dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/PasswordAuthenticatorTest.java rename to dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticatorTest.java index dca70f8ed3..f3c90ff743 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/PasswordAuthenticatorTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticatorTest.java @@ -14,7 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dolphinscheduler.api.security; + +package org.apache.dolphinscheduler.api.security.impl.pwd; + +import static org.mockito.Mockito.when; import org.apache.dolphinscheduler.api.ApiApplicationServer; import org.apache.dolphinscheduler.api.enums.Status; @@ -23,12 +26,17 @@ import org.apache.dolphinscheduler.api.service.UsersService; import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.dao.entity.Session; import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.Date; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; -import static org.mockito.Mockito.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -36,9 +44,6 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; -import javax.servlet.http.HttpServletRequest; -import java.util.Date; -import java.util.UUID; @RunWith(SpringRunner.class) @SpringBootTest(classes = ApiApplicationServer.class) @@ -58,7 +63,7 @@ public class PasswordAuthenticatorTest { private Session mockSession; @Before - public void setUp() throws Exception { + public void setUp() { authenticator = new PasswordAuthenticator(); beanFactory.autowireBean(authenticator); @@ -76,6 +81,13 @@ public class PasswordAuthenticatorTest { mockSession.setLastLoginTime(new Date()); } + @Test + public void testLogin() { + when(usersService.queryUser("test", "test")).thenReturn(mockUser); + User login = authenticator.login("test", "test", "127.0.0.1"); + Assert.assertNotNull(login); + } + @Test public void testAuthenticate() { when(usersService.queryUser("test", "test")).thenReturn(mockUser); diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java index d86c2cc93e..ca6c7216b9 100644 --- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java @@ -14,10 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.dolphinscheduler.api.service; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + import org.apache.dolphinscheduler.api.enums.Status; import org.apache.dolphinscheduler.api.utils.PageInfo; import org.apache.dolphinscheduler.api.utils.Result; @@ -29,7 +32,19 @@ import org.apache.dolphinscheduler.common.utils.EncryptionUtils; import org.apache.dolphinscheduler.dao.entity.Resource; import org.apache.dolphinscheduler.dao.entity.Tenant; import org.apache.dolphinscheduler.dao.entity.User; -import org.apache.dolphinscheduler.dao.mapper.*; +import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper; +import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper; +import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper; +import org.apache.dolphinscheduler.dao.mapper.ResourceMapper; +import org.apache.dolphinscheduler.dao.mapper.ResourceUserMapper; +import org.apache.dolphinscheduler.dao.mapper.TenantMapper; +import org.apache.dolphinscheduler.dao.mapper.UDFUserMapper; +import org.apache.dolphinscheduler.dao.mapper.UserMapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -42,13 +57,8 @@ import org.mockito.junit.MockitoJUnitRunner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @RunWith(MockitoJUnitRunner.class) public class UsersServiceTest { @@ -73,30 +83,34 @@ public class UsersServiceTest { @Mock private ResourceMapper resourceMapper; - private String queueName ="UsersServiceTestQueue"; - + private String queueName = "UsersServiceTestQueue"; @Before - public void before(){ - - + public void before() { } + @After - public void after(){ + public void after() { } - @Test - public void testCreateUser(){ + public void testCreateUserForLdap() { + String userName = "user1"; + String email = "user1@ldap.com"; + User user = usersService.createUser(UserType.ADMIN_USER, userName, email); + Assert.assertNotNull(user); + } + @Test + public void testCreateUser() { User user = new User(); user.setUserType(UserType.ADMIN_USER); String userName = "userTest0001~"; String userPassword = "userTest"; String email = "123@qq.com"; int tenantId = Integer.MAX_VALUE; - String phone= "13456432345"; + String phone = "13456432345"; int state = 1; try { //userName error @@ -119,7 +133,7 @@ public class UsersServiceTest { Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS)); email = "122222@qq.com"; - phone ="2233"; + phone = "2233"; //phone error result = usersService.createUser(user, userName, userPassword, email, tenantId, phone, queueName, state); logger.info(result.toString()); @@ -137,20 +151,19 @@ public class UsersServiceTest { Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); } catch (Exception e) { - logger.error(Status.CREATE_USER_ERROR.getMsg(),e); + logger.error(Status.CREATE_USER_ERROR.getMsg(), e); Assert.assertTrue(false); } } @Test - public void testQueryUser(){ - + public void testQueryUser() { String userName = "userTest0001"; String userPassword = "userTest0001"; - when(userMapper.queryUserByNamePassword(userName,EncryptionUtils.getMd5(userPassword))).thenReturn(getGeneralUser()); - User queryUser = usersService.queryUser(userName, userPassword); + when(userMapper.queryUserByNamePassword(userName, EncryptionUtils.getMd5(userPassword))).thenReturn(getGeneralUser()); + User queryUser = usersService.queryUser(userName, userPassword); logger.info(queryUser.toString()); - Assert.assertTrue(queryUser!=null); + Assert.assertTrue(queryUser != null); } @Test @@ -176,11 +189,8 @@ public class UsersServiceTest { } - @Test - public void testQueryUserList(){ - - + public void testQueryUserList() { User user = new User(); //no operate @@ -190,37 +200,34 @@ public class UsersServiceTest { //success user.setUserType(UserType.ADMIN_USER); - when(userMapper.selectList(null )).thenReturn(getUserList()); + when(userMapper.selectList(null)).thenReturn(getUserList()); result = usersService.queryUserList(user); List userList = (List) result.get(Constants.DATA_LIST); - Assert.assertTrue(userList.size()>0); + Assert.assertTrue(userList.size() > 0); } @Test - public void testQueryUserListPage(){ - - + public void testQueryUserListPage() { User user = new User(); - IPage page = new Page<>(1,10); + IPage page = new Page<>(1, 10); page.setRecords(getUserList()); when(userMapper.queryUserPaging(any(Page.class), eq("userTest"))).thenReturn(page); //no operate - Map result = usersService.queryUserList(user,"userTest",1,10); + Map result = usersService.queryUserList(user, "userTest", 1, 10); logger.info(result.toString()); Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS)); //success user.setUserType(UserType.ADMIN_USER); - result = usersService.queryUserList(user,"userTest",1,10); + result = usersService.queryUserList(user, "userTest", 1, 10); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); - PageInfo pageInfo = (PageInfo) result.get(Constants.DATA_LIST); - Assert.assertTrue(pageInfo.getLists().size()>0); + PageInfo pageInfo = (PageInfo) result.get(Constants.DATA_LIST); + Assert.assertTrue(pageInfo.getLists().size() > 0); } @Test - public void testUpdateUser(){ - + public void testUpdateUser() { String userName = "userTest0001"; String userPassword = "userTest0001"; try { @@ -235,48 +242,46 @@ public class UsersServiceTest { logger.info(result.toString()); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); } catch (Exception e) { - logger.error("update user error",e); + logger.error("update user error", e); Assert.assertTrue(false); } } @Test - public void testDeleteUserById(){ - + public void testDeleteUserById() { User loginUser = new User(); try { when(userMapper.queryTenantCodeByUserId(1)).thenReturn(getUser()); when(userMapper.selectById(1)).thenReturn(getUser()); //no operate - Map result = usersService.deleteUserById(loginUser,3); + Map result = usersService.deleteUserById(loginUser, 3); logger.info(result.toString()); Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS)); // user not exist loginUser.setUserType(UserType.ADMIN_USER); - result = usersService.deleteUserById(loginUser,3); + result = usersService.deleteUserById(loginUser, 3); logger.info(result.toString()); Assert.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS)); //success - result = usersService.deleteUserById(loginUser,1); + result = usersService.deleteUserById(loginUser, 1); logger.info(result.toString()); Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); } catch (Exception e) { - logger.error("delete user error",e); - Assert.assertTrue(false); + logger.error("delete user error", e); + Assert.assertTrue(false); } } @Test - public void testGrantProject(){ - + public void testGrantProject() { when(userMapper.selectById(1)).thenReturn(getUser()); User loginUser = new User(); - String projectIds= "100000,120000"; + String projectIds = "100000,120000"; Map result = usersService.grantProject(loginUser, 1, projectIds); logger.info(result.toString()); Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS)); @@ -292,8 +297,7 @@ public class UsersServiceTest { } @Test - public void testGrantResources(){ - + public void testGrantResources() { String resourceIds = "100000,120000"; when(userMapper.selectById(1)).thenReturn(getUser()); User loginUser = new User(); @@ -317,8 +321,7 @@ public class UsersServiceTest { @Test - public void testGrantUDFFunction(){ - + public void testGrantUDFFunction() { String udfIds = "100000,120000"; when(userMapper.selectById(1)).thenReturn(getUser()); User loginUser = new User(); @@ -337,8 +340,7 @@ public class UsersServiceTest { } @Test - public void testGrantDataSource(){ - + public void testGrantDataSource() { String datasourceIds = "100000,120000"; when(userMapper.selectById(1)).thenReturn(getUser()); User loginUser = new User(); @@ -365,8 +367,7 @@ public class UsersServiceTest { } @Test - public void getUserInfo(){ - + public void getUserInfo() { User loginUser = new User(); loginUser.setUserName("admin"); loginUser.setUserType(UserType.ADMIN_USER); @@ -376,7 +377,7 @@ public class UsersServiceTest { Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); User tempUser = (User) result.get(Constants.DATA_LIST); //check userName - Assert.assertEquals("admin",tempUser.getUserName()); + Assert.assertEquals("admin", tempUser.getUserName()); //get general user loginUser.setUserType(null); @@ -387,13 +388,12 @@ public class UsersServiceTest { Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS)); tempUser = (User) result.get(Constants.DATA_LIST); //check userName - Assert.assertEquals("userTest0001",tempUser.getUserName()); + Assert.assertEquals("userTest0001", tempUser.getUserName()); } @Test - public void testQueryAllGeneralUsers(){ - + public void testQueryAllGeneralUsers() { User loginUser = new User(); //no operate Map result = usersService.queryAllGeneralUsers(loginUser); @@ -410,8 +410,7 @@ public class UsersServiceTest { } @Test - public void testVerifyUserName(){ - + public void testVerifyUserName() { //not exist user Result result = usersService.verifyUserName("admin89899"); logger.info(result.toString()); @@ -424,11 +423,10 @@ public class UsersServiceTest { } @Test - public void testUnauthorizedUser(){ - + public void testUnauthorizedUser() { User loginUser = new User(); - when(userMapper.selectList(null )).thenReturn(getUserList()); - when( userMapper.queryUserListByAlertGroupId(2)).thenReturn(getUserList()); + when(userMapper.selectList(null)).thenReturn(getUserList()); + when(userMapper.queryUserListByAlertGroupId(2)).thenReturn(getUserList()); //no operate Map result = usersService.unauthorizedUser(loginUser, 2); logger.info(result.toString()); @@ -442,8 +440,7 @@ public class UsersServiceTest { @Test - public void testAuthorizedUser(){ - + public void testAuthorizedUser() { User loginUser = new User(); when(userMapper.queryUserListByAlertGroupId(2)).thenReturn(getUserList()); //no operate @@ -571,10 +568,8 @@ public class UsersServiceTest { /** * get disabled user - * @return */ private User getDisabledUser() { - User user = new User(); user.setUserType(UserType.GENERAL_USER); user.setUserName("userTest0001"); @@ -586,10 +581,8 @@ public class UsersServiceTest { /** * get user - * @return */ - private User getGeneralUser(){ - + private User getGeneralUser() { User user = new User(); user.setUserType(UserType.GENERAL_USER); user.setUserName("userTest0001"); @@ -597,8 +590,7 @@ public class UsersServiceTest { return user; } - - private List getUserList(){ + private List getUserList() { List userList = new ArrayList<>(); userList.add(getGeneralUser()); return userList; @@ -607,8 +599,7 @@ public class UsersServiceTest { /** * get user */ - private User getUser(){ - + private User getUser() { User user = new User(); user.setUserType(UserType.ADMIN_USER); user.setUserName("userTest0001"); @@ -619,9 +610,10 @@ public class UsersServiceTest { /** * get tenant + * * @return tenant */ - private Tenant getTenant(){ + private Tenant getTenant() { Tenant tenant = new Tenant(); tenant.setId(1); return tenant; @@ -629,10 +621,10 @@ public class UsersServiceTest { /** * get resource + * * @return resource */ - private Resource getResource(){ - + private Resource getResource() { Resource resource = new Resource(); resource.setPid(-1); resource.setUserId(1); diff --git a/pom.xml b/pom.xml index 201f1155c5..58cca7c4eb 100644 --- a/pom.xml +++ b/pom.xml @@ -725,8 +725,10 @@ **/api/exceptions/ApiExceptionHandlerTest.java **/api/exceptions/ServiceExceptionTest.java **/api/interceptor/LoginHandlerInterceptorTest.java - **/api/security/PasswordAuthenticatorTest.java - **/api/security/SecurityConfigTest.java + **/api/security/impl/pwd/PasswordAuthenticatorTest.java + **/api/security/impl/ldap/LdapAuthenticatorTest.java + **/api/security/SecurityConfigLDAPTest.java + **/api/security/SecurityConfigPasswordTest.java **/api/service/AccessTokenServiceTest.java **/api/service/AlertGroupServiceTest.java **/api/service/BaseDAGServiceTest.java