mirror of
https://github.com/dataease/dataease.git
synced 2026-05-14 12:22:10 +08:00
fix: 【漏洞】修复unauthorized command execution vulnerability
This commit is contained in:
@@ -10,7 +10,6 @@ import io.dataease.auth.vo.TokenVO;
|
|||||||
import io.dataease.exception.DEException;
|
import io.dataease.exception.DEException;
|
||||||
import io.dataease.i18n.Translator;
|
import io.dataease.i18n.Translator;
|
||||||
import io.dataease.utils.LogUtil;
|
import io.dataease.utils.LogUtil;
|
||||||
import io.dataease.utils.Md5Utils;
|
|
||||||
import io.dataease.utils.RsaUtils;
|
import io.dataease.utils.RsaUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
@@ -43,8 +42,7 @@ public class SubstituleLoginServer {
|
|||||||
TokenUserBO tokenUserBO = new TokenUserBO();
|
TokenUserBO tokenUserBO = new TokenUserBO();
|
||||||
tokenUserBO.setUserId(1L);
|
tokenUserBO.setUserId(1L);
|
||||||
tokenUserBO.setDefaultOid(1L);
|
tokenUserBO.setDefaultOid(1L);
|
||||||
String md5Pwd = Md5Utils.md5(pwd);
|
return generate(tokenUserBO, SubstituleLoginConfig.getTokenSecret());
|
||||||
return generate(tokenUserBO, md5Pwd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import io.dataease.utils.CommonBeanFactory;
|
import io.dataease.utils.CommonBeanFactory;
|
||||||
import io.dataease.utils.LogUtil;
|
import io.dataease.utils.LogUtil;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -16,16 +17,21 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@ConditionalOnMissingBean(name = "loginServer")
|
@ConditionalOnMissingBean(name = "loginServer")
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SubstituleLoginConfig {
|
public class SubstituleLoginConfig {
|
||||||
|
private static final String PWD_KEY = "pwd";
|
||||||
|
private static final String TOKEN_SECRET_KEY = "tokenSecret";
|
||||||
|
|
||||||
@Value("${dataease.path.substitule:classpath:substitule.json}")
|
@Value("${dataease.path.substitule:classpath:substitule.json}")
|
||||||
private String jsonFilePath;
|
private String jsonFilePath;
|
||||||
|
|
||||||
private static String pwd;
|
private static String pwd;
|
||||||
|
|
||||||
|
private static String tokenSecret;
|
||||||
|
|
||||||
private static boolean ready = false;
|
private static boolean ready = false;
|
||||||
|
|
||||||
|
|
||||||
@@ -34,39 +40,91 @@ public class SubstituleLoginConfig {
|
|||||||
public Map<String, Object> substituleLoginData(ResourceLoader resourceLoader) throws IOException {
|
public Map<String, Object> substituleLoginData(ResourceLoader resourceLoader) throws IOException {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
File jsonFile = new File(jsonFilePath);
|
File jsonFile = new File(jsonFilePath);
|
||||||
if (!jsonFile.exists()) {
|
Map<String, Object> result = jsonFile.exists() ? objectMapper.readValue(jsonFile, Map.class) : new HashMap<>();
|
||||||
pwd = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.default-pwd", "DataEase@123456");
|
boolean updated = false;
|
||||||
modifyPwd(pwd);
|
Environment environment = CommonBeanFactory.getBean(Environment.class);
|
||||||
|
String configuredPwd = environment == null ? null : environment.getProperty("dataease.default-pwd");
|
||||||
|
pwd = readString(result, PWD_KEY);
|
||||||
|
if (StringUtils.isBlank(pwd)) {
|
||||||
|
pwd = StringUtils.isNotBlank(configuredPwd) ? configuredPwd : generatePwd();
|
||||||
|
result.put(PWD_KEY, pwd);
|
||||||
|
updated = true;
|
||||||
|
if (StringUtils.isBlank(configuredPwd)) {
|
||||||
|
LogUtil.info("Generated substitute admin password in " + jsonFilePath + ". Please keep the file secure.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return objectMapper.readValue(jsonFile, Map.class);
|
tokenSecret = readString(result, TOKEN_SECRET_KEY);
|
||||||
|
if (StringUtils.isBlank(tokenSecret)) {
|
||||||
|
tokenSecret = generateSecret();
|
||||||
|
result.put(TOKEN_SECRET_KEY, tokenSecret);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
if (updated) {
|
||||||
|
writeConfig(jsonFile, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getPwd() {
|
public static String getPwd() {
|
||||||
if (!ready) {
|
loadSubstituleLoginData();
|
||||||
ready = true;
|
return pwd;
|
||||||
Object substituleLoginDataObject = CommonBeanFactory.getBean("substituleLoginData");
|
}
|
||||||
if (substituleLoginDataObject != null) {
|
|
||||||
Map<String, Object> substituleLoginData = (Map<String, Object>) substituleLoginDataObject;
|
public static String getTokenSecret() {
|
||||||
if (ObjectUtils.isNotEmpty(substituleLoginData.get("pwd"))) {
|
loadSubstituleLoginData();
|
||||||
pwd = substituleLoginData.get("pwd").toString();
|
return tokenSecret;
|
||||||
return substituleLoginData.get("pwd").toString();
|
}
|
||||||
}
|
|
||||||
|
private static synchronized void loadSubstituleLoginData() {
|
||||||
|
if (ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ready = true;
|
||||||
|
Object substituleLoginDataObject = CommonBeanFactory.getBean("substituleLoginData");
|
||||||
|
if (substituleLoginDataObject != null) {
|
||||||
|
Map<String, Object> substituleLoginData = (Map<String, Object>) substituleLoginDataObject;
|
||||||
|
String configuredPwd = readString(substituleLoginData, PWD_KEY);
|
||||||
|
if (StringUtils.isNotBlank(configuredPwd)) {
|
||||||
|
pwd = configuredPwd;
|
||||||
|
}
|
||||||
|
String configuredTokenSecret = readString(substituleLoginData, TOKEN_SECRET_KEY);
|
||||||
|
if (StringUtils.isNotBlank(configuredTokenSecret)) {
|
||||||
|
tokenSecret = configuredTokenSecret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pwd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void modifyPwd(String pwd) {
|
public void modifyPwd(String pwd) {
|
||||||
File file = new File(jsonFilePath);
|
File file = new File(jsonFilePath);
|
||||||
Map<String, String> myObject = new HashMap<>();
|
Map<String, String> myObject = new HashMap<>();
|
||||||
myObject.put("pwd", pwd);
|
myObject.put(PWD_KEY, pwd);
|
||||||
|
myObject.put(TOKEN_SECRET_KEY, ObjectUtils.isNotEmpty(tokenSecret) ? tokenSecret : generateSecret());
|
||||||
SubstituleLoginConfig.pwd = pwd;
|
SubstituleLoginConfig.pwd = pwd;
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
SubstituleLoginConfig.tokenSecret = myObject.get(TOKEN_SECRET_KEY);
|
||||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
try {
|
||||||
// 将对象写入文件
|
writeConfig(file, myObject);
|
||||||
mapper.writeValue(fos, myObject);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LogUtil.error(e.getCause(), new Throwable(e));
|
LogUtil.error(e.getCause(), new Throwable(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void writeConfig(File file, Map<?, ?> config) throws IOException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
mapper.writeValue(fos, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readString(Map<String, Object> config, String key) {
|
||||||
|
Object value = config.get(key);
|
||||||
|
return ObjectUtils.isEmpty(value) ? null : value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generatePwd() {
|
||||||
|
return "DE-" + UUID.randomUUID().toString().replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateSecret() {
|
||||||
|
return UUID.randomUUID().toString().replace("-", "") + UUID.randomUUID().toString().replace("-", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ public class CommunityTokenFilter implements Filter {
|
|||||||
if (StringUtils.isNotBlank(token) && ObjectUtils.isNotEmpty(userBO = AuthUtils.getUser()) && ObjectUtils.isNotEmpty(userId = userBO.getUserId()) && !LicenseUtil.licenseValid()) {
|
if (StringUtils.isNotBlank(token) && ObjectUtils.isNotEmpty(userBO = AuthUtils.getUser()) && ObjectUtils.isNotEmpty(userId = userBO.getUserId()) && !LicenseUtil.licenseValid()) {
|
||||||
String secret = null;
|
String secret = null;
|
||||||
if (ObjectUtils.isEmpty(CommonBeanFactory.getBean("loginServer"))) {
|
if (ObjectUtils.isEmpty(CommonBeanFactory.getBean("loginServer"))) {
|
||||||
String pwd = SubstituleLoginConfig.getPwd();
|
secret = SubstituleLoginConfig.getTokenSecret();
|
||||||
secret = Md5Utils.md5(pwd);
|
|
||||||
} else {
|
} else {
|
||||||
Object apisixCacheManage = CommonBeanFactory.getBean("apisixCacheManage");
|
Object apisixCacheManage = CommonBeanFactory.getBean("apisixCacheManage");
|
||||||
Method method = DeReflectUtil.findMethod(apisixCacheManage.getClass(), "userCacheBO");
|
Method method = DeReflectUtil.findMethod(apisixCacheManage.getClass(), "userCacheBO");
|
||||||
|
|||||||
Reference in New Issue
Block a user