From 50237afe08c0f876f8b60e1dabdbc94c27341e82 Mon Sep 17 00:00:00 2001 From: geosmart Date: Wed, 23 Dec 2020 17:38:05 +0800 Subject: [PATCH 1/5] [FEATURE-736] integrate ldap authentication (#3743) * [FEATURE-736] integrate ldap authentication * add ldap authentication type * refactor authentication with ldap and password * add createUser for ldap in user service * remove duplicate password authenticator --- .../api/security/AuthenticationType.java | 2 + .../api/security/Authenticator.java | 5 +- .../api/security/SecurityConfig.java | 9 +- .../AbstractAuthenticator.java} | 35 +++- .../security/impl/ldap/LdapAuthenticator.java | 45 ++++ .../api/security/impl/ldap/LdapService.java | 133 ++++++++++++ .../impl/pwd/PasswordAuthenticator.java | 34 +++ .../api/service/UsersService.java | 196 ++++++++++++------ .../main/resources/application-api.properties | 14 +- .../api/security/SecurityConfigLDAPTest.java | 45 ++++ ...t.java => SecurityConfigPasswordTest.java} | 4 +- .../impl/ldap/LdapAuthenticatorTest.java | 142 +++++++++++++ .../security/impl/ldap/LdapServiceTest.java | 81 ++++++++ .../pwd}/PasswordAuthenticatorTest.java | 24 ++- .../api/service/UsersServiceTest.java | 162 +++++++-------- pom.xml | 6 +- 16 files changed, 761 insertions(+), 176 deletions(-) rename dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/{PasswordAuthenticator.java => impl/AbstractAuthenticator.java} (80%) create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticator.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapService.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/pwd/PasswordAuthenticator.java create mode 100644 dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/SecurityConfigLDAPTest.java rename dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/{SecurityConfigTest.java => SecurityConfigPasswordTest.java} (97%) create mode 100644 dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapAuthenticatorTest.java create mode 100644 dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapServiceTest.java rename dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/security/{ => impl/pwd}/PasswordAuthenticatorTest.java (91%) 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 From f0ada2aa2dba2ecdbfdd28c7f88a68fe06730d86 Mon Sep 17 00:00:00 2001 From: Shiwen Cheng Date: Wed, 23 Dec 2020 21:19:08 +0800 Subject: [PATCH 2/5] [Fix-4289][*] Flink name with disappeared and unescaped problem (#4290) * fix flink name not display in process definition editor * fix flink name not escape problem * simplify escape method --- .../server/utils/ArgsUtils.java | 30 +++++++++++++++++++ .../server/utils/FlinkArgsUtils.java | 5 ++-- .../server/utils/LogUtils.java | 6 ++-- .../dag/_source/formModel/tasks/flink.vue | 13 +++----- .../src/js/module/i18n/locale/en_US.js | 2 +- .../src/js/module/i18n/locale/zh_CN.js | 2 +- 6 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ArgsUtils.java diff --git a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ArgsUtils.java b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ArgsUtils.java new file mode 100644 index 0000000000..d71eb54f3c --- /dev/null +++ b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ArgsUtils.java @@ -0,0 +1,30 @@ +/* + * 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.server.utils; + +public class ArgsUtils { + + private ArgsUtils() throws IllegalStateException { + throw new IllegalStateException("Utility class"); + } + + public static String escape(String arg) { + return arg.replace(" ", "\\ ").replace("\"", "\\\"").replace("'", "\\'"); + } + +} diff --git a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/FlinkArgsUtils.java b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/FlinkArgsUtils.java index 5d3b57bb0a..2431eedd16 100644 --- a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/FlinkArgsUtils.java +++ b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/FlinkArgsUtils.java @@ -14,8 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dolphinscheduler.server.utils; +package org.apache.dolphinscheduler.server.utils; import org.apache.commons.lang.StringUtils; import org.apache.dolphinscheduler.common.Constants; @@ -26,7 +26,6 @@ import org.apache.dolphinscheduler.common.task.flink.FlinkParameters; import java.util.ArrayList; import java.util.List; - /** * flink args utils */ @@ -62,7 +61,7 @@ public class FlinkArgsUtils { String appName = param.getAppName(); if (StringUtils.isNotEmpty(appName)) { //-ynm args.add(Constants.FLINK_APP_NAME); - args.add(appName); + args.add(ArgsUtils.escape(appName)); } // judge flink version,from flink1.10,the parameter -yn removed diff --git a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/LogUtils.java b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/LogUtils.java index bb8ddc85de..1dc4287f82 100644 --- a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/LogUtils.java +++ b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/LogUtils.java @@ -25,8 +25,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; -import javax.transaction.NotSupportedException; - import org.slf4j.LoggerFactory; import ch.qos.logback.classic.sift.SiftingAppender; @@ -35,8 +33,8 @@ import ch.qos.logback.core.spi.AppenderAttachable; public class LogUtils { - private LogUtils() throws NotSupportedException { - throw new NotSupportedException(); + private LogUtils() throws IllegalStateException { + throw new IllegalStateException("Utility class"); } /** diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue index 24b3bbd481..0f422e59a4 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue @@ -89,7 +89,7 @@ type="input" size="small" v-model="appName" - :placeholder="$t('Please enter the job name of Flink')" + :placeholder="$t('Please enter the job name of Flink(optional)')" style="width: 200px;"> @@ -303,11 +303,6 @@ return false } - if (!this.appName) { - this.$message.warning(`${i18n.$t('Please enter the job name of Flink')}`) - return false - } - if (!this.jobManagerMemory) { this.$message.warning(`${i18n.$t('Please enter jobManager memory')}`) return false @@ -353,9 +348,9 @@ flinkVersion: this.flinkVersion, slot: this.slot, taskManager: this.taskManager, - appName: this.appName, jobManagerMemory: this.jobManagerMemory, taskManagerMemory: this.taskManagerMemory, + appName: this.appName, mainArgs: this.mainArgs, others: this.others, programType: this.programType @@ -489,9 +484,9 @@ localParams: this.localParams, slot: this.slot, taskManager: this.taskManager, - appName: this.appName, jobManagerMemory: this.jobManagerMemory, taskManagerMemory: this.taskManagerMemory, + appName: this.appName, mainArgs: this.mainArgs, others: this.others, programType: this.programType @@ -522,7 +517,7 @@ this.taskManager = o.params.taskManager || '2' this.jobManagerMemory = o.params.jobManagerMemory || '1G' this.taskManagerMemory = o.params.taskManagerMemory || '2G' - + this.appName = o.params.appName || '' this.mainArgs = o.params.mainArgs || '' this.others = o.params.others this.programType = o.params.programType || 'SCALA' diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js index 2ab56cb5ed..13dbc7e068 100755 --- a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js +++ b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js @@ -108,7 +108,7 @@ export default { 'Driver memory use': 'Driver memory use', 'Please enter driver memory use': 'Please enter driver memory use', 'Number of Executors': 'Number of Executors', - 'Please enter the job name of Flink': 'Please enter the job name of Flink', + 'Please enter the job name of Flink(optional)': 'Please enter the job name of Flink(optional)', 'Please enter the number of Executor': 'Please enter the number of Executor', 'Executor memory': 'Executor memory', 'Please enter the Executor memory': 'Please enter the Executor memory', diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js index 9198c988d7..c45afda8a5 100755 --- a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js +++ b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js @@ -106,7 +106,7 @@ export default { 'Driver memory use': 'Driver内存数', 'Please enter driver memory use': '请输入Driver内存数', 'Number of Executors': 'Executor数量', - 'Please enter the job name of Flink': '请输入Flink任务名称', + 'Please enter the job name of Flink(optional)': '请输入Flink任务名称(选填)', 'Please enter the number of Executor': '请输入Executor数量', 'Executor memory': 'Executor内存数', 'Please enter the Executor memory': '请输入Executor内存数', From 3f9dcd5d4489197b22027d752e2c0bd0d453c30c Mon Sep 17 00:00:00 2001 From: zhuangchong <37063904+zhuangchong@users.noreply.github.com> Date: Thu, 24 Dec 2020 09:20:58 +0800 Subject: [PATCH 3/5] fix database is the mysql DB keyword. (#4295) --- .../dao/mapper/UdfFuncMapper.xml | 99 +++++++++++-------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml index ae8e0df273..445810dce1 100644 --- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml +++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml @@ -18,82 +18,97 @@ + + + ${alias}.id, ${alias}.user_id, ${alias}.func_name, ${alias}.class_name, ${alias}.type, ${alias}.arg_types, + ${alias}.database, ${alias}.description, ${alias}.resource_id, ${alias}.resource_name, ${alias}.create_time, ${alias}.update_time + + - select t.id, t.user_id, t.token, t.expire_time, t.create_time, t.update_time + select t.id, t.user_id, t.token, t.expire_time, t.create_time, t.update_time, u.user_name from t_ds_access_token t left join t_ds_user u on t.user_id = u.id where 1 = 1 From ede78950836b77cceda0caafb0503a47b10fbbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=B8=9B=E9=98=B3?= Date: Thu, 24 Dec 2020 17:26:51 +0800 Subject: [PATCH 5/5] Dev imp server process utils (#4263) * Adds the comment on the WINDOWSATTERN Co-authored-by: Kirs Co-authored-by: 0002939 --- .../server/utils/ProcessUtils.java | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ProcessUtils.java b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ProcessUtils.java index 6e80c44995..6c54c790fb 100644 --- a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ProcessUtils.java +++ b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/utils/ProcessUtils.java @@ -30,9 +30,6 @@ import org.apache.dolphinscheduler.remote.utils.Host; import org.apache.dolphinscheduler.server.entity.TaskExecutionContext; import org.apache.dolphinscheduler.service.log.LogClientService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -40,21 +37,28 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * mainly used to get the start command line of a process. */ public class ProcessUtils { + /** - * logger. + * logger */ - private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class); + private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class); /** * Initialization regularization, solve the problem of pre-compilation performance, - * avoid the thread safety problem of multi-thread operation. + * avoid the thread safety problem of multi-thread operation */ private static final Pattern MACPATTERN = Pattern.compile("-[+|-]-\\s(\\d+)"); + /** + * Expression of PID recognition in Windows scene + */ private static final Pattern WINDOWSATTERN = Pattern.compile("(\\d+)"); private static final String LOCAL_PROCESS_EXEC = "jdk.lang.Process.allowAmbiguousCommands"; @@ -79,7 +83,7 @@ public class ProcessUtils { } cmdstr = createCommandLine( - VERIFICATION_LEGACY, executablePath, cmd); + VERIFICATION_LEGACY, executablePath, cmd); } else { String executablePath; try { @@ -102,7 +106,7 @@ public class ProcessUtils { cmdstr = createCommandLine( - isShellFile(executablePath) ? VERIFICATION_CMD_BAT : VERIFICATION_WIN32, quoteString(executablePath), cmd); + isShellFile(executablePath) ? VERIFICATION_CMD_BAT : VERIFICATION_WIN32, quoteString(executablePath), cmd); } return cmdstr; } @@ -211,8 +215,8 @@ public class ProcessUtils { * create command line. * * @param verificationType verification type - * @param executablePath executable path - * @param cmd cmd + * @param executablePath executable path + * @param cmd cmd * @return command line */ private static String createCommandLine(int verificationType, final String executablePath, final String[] cmd) { @@ -241,8 +245,8 @@ public class ProcessUtils { * whether is quoted. * * @param noQuotesInside no quotes inside - * @param arg arg - * @param errorMessage error message + * @param arg arg + * @param errorMessage error message * @return boolean */ private static boolean isQuoted(boolean noQuotesInside, String arg, String errorMessage) { @@ -266,7 +270,7 @@ public class ProcessUtils { * whether needs escaping. * * @param verificationType verification type - * @param arg arg + * @param arg arg * @return boolean */ private static boolean needsEscaping(int verificationType, String arg) { @@ -287,9 +291,9 @@ public class ProcessUtils { /** * kill yarn application. * - * @param appIds app id list - * @param logger logger - * @param tenantCode tenant code + * @param appIds app id list + * @param logger logger + * @param tenantCode tenant code * @param executePath execute path */ public static void cancelApplication(List appIds, Logger logger, String tenantCode, String executePath) { @@ -301,7 +305,7 @@ public class ProcessUtils { if (!applicationStatus.typeIsFinished()) { String commandFile = String - .format("%s/%s.kill", executePath, appId); + .format("%s/%s.kill", executePath, appId); String cmd = "yarn application -kill " + appId; execYarnKillCommand(logger, tenantCode, appId, commandFile, cmd); } @@ -315,11 +319,11 @@ public class ProcessUtils { /** * build kill command for yarn application * - * @param logger logger - * @param tenantCode tenant code - * @param appId app id + * @param logger logger + * @param tenantCode tenant code + * @param appId app id * @param commandFile command file - * @param cmd cmd + * @param cmd cmd */ private static void execYarnKillCommand(Logger logger, String tenantCode, String appId, String commandFile, String cmd) { try { @@ -361,7 +365,7 @@ public class ProcessUtils { int processId = taskExecutionContext.getProcessId(); if (processId == 0) { logger.error("process kill failed, process id :{}, task id:{}", - processId, taskExecutionContext.getTaskInstanceId()); + processId, taskExecutionContext.getTaskInstanceId()); return; } @@ -422,8 +426,8 @@ public class ProcessUtils { try { logClient = new LogClientService(); log = logClient.viewLog(Host.of(taskExecutionContext.getHost()).getIp(), - Constants.RPC_PORT, - taskExecutionContext.getLogPath()); + Constants.RPC_PORT, + taskExecutionContext.getLogPath()); } finally { if (logClient != null) { logClient.close();