(improvement)(headless) Encrypt database password (#1553)

* (improvement)(headless) Encrypt database password


---------

Co-authored-by: lxwcodemonkey
This commit is contained in:
LXW
2024-08-12 00:37:32 +08:00
committed by GitHub
parent 8b01dac8d4
commit 1ff4a71a41
8 changed files with 65 additions and 102 deletions

View File

@@ -73,7 +73,6 @@ public class AESEncryptionUtil {
return new String(decryptedBytes, ENCODE); return new String(decryptedBytes, ENCODE);
} catch (Exception e) { } catch (Exception e) {
log.warn("encryptStr decrypt failed:{}", encryptStr);
return encryptStr; return encryptStr;
} }
} }

View File

@@ -1,14 +1,13 @@
package com.tencent.supersonic.headless.api.pojo.request; package com.tencent.supersonic.headless.api.pojo.request;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.tencent.supersonic.headless.api.pojo.enums.DataType; import com.tencent.supersonic.common.pojo.RecordInfo;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.util.List; import java.util.List;
@Data @Data
public class DatabaseReq { public class DatabaseReq extends RecordInfo {
private Long id; private Long id;
@@ -37,20 +36,4 @@ public class DatabaseReq {
private List<String> viewers = Lists.newArrayList(); private List<String> viewers = Lists.newArrayList();
public String getConnectUrl() {
if (StringUtils.isNotBlank(url)) {
return url;
}
String databaseUrl = database;
if (StringUtils.isBlank(databaseUrl)) {
databaseUrl = "";
} else {
databaseUrl = "/" + database;
}
if (type.equalsIgnoreCase(DataType.MYSQL.getFeature())) {
return String.format("jdbc:%s://%s:%s%s?sessionVariables=sql_mode='IGNORE_SPACE'&allowMultiQueries=true",
type, host, port, databaseUrl);
}
return String.format("jdbc:%s://%s:%s%s", type, host, port, databaseUrl);
}
} }

View File

@@ -3,6 +3,7 @@ package com.tencent.supersonic.headless.core.pojo;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.tencent.supersonic.common.pojo.RecordInfo; import com.tencent.supersonic.common.pojo.RecordInfo;
import com.tencent.supersonic.common.util.AESEncryptionUtil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@@ -40,10 +41,12 @@ public class Database extends RecordInfo {
*/ */
private String type; private String type;
private ConnectInfo connectInfo;
private List<String> admins = Lists.newArrayList(); private List<String> admins = Lists.newArrayList();
private List<String> viewers = Lists.newArrayList(); private List<String> viewers = Lists.newArrayList();
public String passwordDecrypt() {
return AESEncryptionUtil.aesDecryptCBC(password);
}
} }

View File

@@ -1,20 +1,11 @@
package com.tencent.supersonic.headless.core.pojo; package com.tencent.supersonic.headless.core.pojo;
import static com.tencent.supersonic.common.pojo.Constants.STATISTIC;
import com.alibaba.druid.filter.Filter; import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter; import com.alibaba.druid.wall.WallFilter;
import com.tencent.supersonic.headless.api.pojo.enums.DataType; import com.tencent.supersonic.headless.api.pojo.enums.DataType;
import com.tencent.supersonic.headless.core.utils.JdbcDataSourceUtils; import com.tencent.supersonic.headless.core.utils.JdbcDataSourceUtils;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +13,14 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static com.tencent.supersonic.common.pojo.Constants.STATISTIC;
@Slf4j @Slf4j
@Component @Component
@@ -181,7 +180,7 @@ public class JdbcDataSource {
String type = database.getType(); String type = database.getType();
String jdbcUrl = database.getUrl(); String jdbcUrl = database.getUrl();
String username = database.getUsername(); String username = database.getUsername();
String password = database.getPassword(); String password = database.passwordDecrypt();
String key = getDataSourceKey(database); String key = getDataSourceKey(database);
@@ -309,6 +308,6 @@ public class JdbcDataSource {
return JdbcDataSourceUtils.getKey(database.getName(), return JdbcDataSourceUtils.getKey(database.getName(),
database.getUrl(), database.getUrl(),
database.getUsername(), database.getUsername(),
database.getPassword(), "", false); database.passwordDecrypt(), "", false);
} }
} }

View File

@@ -1,5 +1,20 @@
package com.tencent.supersonic.headless.core.utils; package com.tencent.supersonic.headless.core.utils;
import com.alibaba.druid.util.StringUtils;
import com.tencent.supersonic.common.util.MD5Util;
import com.tencent.supersonic.headless.api.pojo.enums.DataType;
import com.tencent.supersonic.headless.core.pojo.Database;
import com.tencent.supersonic.headless.core.pojo.JdbcDataSource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import static com.tencent.supersonic.common.pojo.Constants.AT_SYMBOL; import static com.tencent.supersonic.common.pojo.Constants.AT_SYMBOL;
import static com.tencent.supersonic.common.pojo.Constants.COLON; import static com.tencent.supersonic.common.pojo.Constants.COLON;
import static com.tencent.supersonic.common.pojo.Constants.DOUBLE_SLASH; import static com.tencent.supersonic.common.pojo.Constants.DOUBLE_SLASH;
@@ -9,22 +24,6 @@ import static com.tencent.supersonic.common.pojo.Constants.NEW_LINE_CHAR;
import static com.tencent.supersonic.common.pojo.Constants.PATTERN_JDBC_TYPE; import static com.tencent.supersonic.common.pojo.Constants.PATTERN_JDBC_TYPE;
import static com.tencent.supersonic.common.pojo.Constants.SPACE; import static com.tencent.supersonic.common.pojo.Constants.SPACE;
import com.alibaba.druid.util.StringUtils;
import com.tencent.supersonic.common.util.MD5Util;
import com.tencent.supersonic.headless.api.pojo.enums.DataType;
import com.tencent.supersonic.headless.core.pojo.Database;
import com.tencent.supersonic.headless.core.pojo.JdbcDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import javax.sql.DataSource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/** /**
* tools functions about jdbc * tools functions about jdbc
*/ */
@@ -42,13 +41,13 @@ public class JdbcDataSourceUtils {
public static boolean testDatabase(Database database) { public static boolean testDatabase(Database database) {
try { try {
Class.forName(getDriverClassName(database.getConnectInfo().getUrl())); Class.forName(getDriverClassName(database.getUrl()));
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
log.error(e.toString(), e); log.error(e.toString(), e);
return false; return false;
} }
try (Connection con = DriverManager.getConnection(database.getConnectInfo().getUrl(), try (Connection con = DriverManager.getConnection(database.getUrl(),
database.getConnectInfo().getUserName(), database.getConnectInfo().getPassword());) { database.getUsername(), database.passwordDecrypt())) {
return con != null; return con != null;
} catch (SQLException e) { } catch (SQLException e) {
log.error(e.toString(), e); log.error(e.toString(), e);

View File

@@ -72,7 +72,7 @@ public class SqlUtils {
.withType(database.getType()) .withType(database.getType())
.withJdbcUrl(database.getUrl()) .withJdbcUrl(database.getUrl())
.withUsername(database.getUsername()) .withUsername(database.getUsername())
.withPassword(database.getPassword()) .withPassword(database.passwordDecrypt())
.withJdbcDataSource(this.jdbcDataSource) .withJdbcDataSource(this.jdbcDataSource)
.withResultLimit(this.resultLimit) .withResultLimit(this.resultLimit)
.withIsQueryLogEnable(this.isQueryLogEnable) .withIsQueryLogEnable(this.isQueryLogEnable)

View File

@@ -3,9 +3,6 @@ package com.tencent.supersonic.headless.server.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.tencent.supersonic.auth.api.authentication.pojo.User; import com.tencent.supersonic.auth.api.authentication.pojo.User;
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.common.pojo.Pair;
import com.tencent.supersonic.common.pojo.QueryColumn; import com.tencent.supersonic.common.pojo.QueryColumn;
import com.tencent.supersonic.headless.api.pojo.DBColumn; import com.tencent.supersonic.headless.api.pojo.DBColumn;
import com.tencent.supersonic.headless.api.pojo.request.DatabaseReq; import com.tencent.supersonic.headless.api.pojo.request.DatabaseReq;
@@ -31,7 +28,6 @@ import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.util.TablesNamesFinder; import net.sf.jsqlparser.util.TablesNamesFinder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -64,16 +60,15 @@ public class DatabaseServiceImpl extends ServiceImpl<DatabaseDOMapper, DatabaseD
@Override @Override
public DatabaseResp createOrUpdateDatabase(DatabaseReq databaseReq, User user) { public DatabaseResp createOrUpdateDatabase(DatabaseReq databaseReq, User user) {
Database database = DatabaseConverter.convert(databaseReq);
DatabaseDO databaseDO = getDatabaseDO(databaseReq.getId()); DatabaseDO databaseDO = getDatabaseDO(databaseReq.getId());
if (databaseDO != null) { if (databaseDO != null) {
database.updatedBy(user.getName()); databaseReq.updatedBy(user.getName());
DatabaseConverter.convert(database, databaseDO); DatabaseConverter.convert(databaseReq, databaseDO);
updateById(databaseDO); updateById(databaseDO);
return DatabaseConverter.convertWithPassword(databaseDO); return DatabaseConverter.convertWithPassword(databaseDO);
} }
database.createdBy(user.getName()); databaseReq.createdBy(user.getName());
databaseDO = DatabaseConverter.convert(database); databaseDO = DatabaseConverter.convertDO(databaseReq);
save(databaseDO); save(databaseDO);
return DatabaseConverter.convertWithPassword(databaseDO); return DatabaseConverter.convertWithPassword(databaseDO);
} }
@@ -146,19 +141,6 @@ public class DatabaseServiceImpl extends ServiceImpl<DatabaseDOMapper, DatabaseD
return queryWithColumns(sql, DatabaseConverter.convert(databaseResp)); return queryWithColumns(sql, DatabaseConverter.convert(databaseResp));
} }
private Pair<String, String> getDbTableName(String sql, DatabaseResp databaseResp) {
String dbTableName = SqlSelectHelper.getDbTableName(sql);
if (StringUtils.isBlank(dbTableName)) {
return Pair.pair("", "");
}
if (dbTableName.contains(Constants.DOT)) {
String db = dbTableName.split("\\.")[0];
String table = dbTableName.split("\\.")[1];
return Pair.pair(db, table);
}
return Pair.pair(databaseResp.getDatabase(), dbTableName);
}
@Override @Override
public Map<String, List<DatabaseParameter>> getDatabaseParameters() { public Map<String, List<DatabaseParameter>> getDatabaseParameters() {
return DbParameterFactory.getMap().entrySet().stream().collect(LinkedHashMap::new, return DbParameterFactory.getMap().entrySet().stream().collect(LinkedHashMap::new,

View File

@@ -15,42 +15,21 @@ public class DatabaseConverter {
public static Database convert(DatabaseResp databaseResp) { public static Database convert(DatabaseResp databaseResp) {
Database database = new Database(); Database database = new Database();
BeanUtils.copyProperties(databaseResp, database); BeanUtils.copyProperties(databaseResp, database);
ConnectInfo connectInfo = getConnectInfo(databaseResp);
database.setConnectInfo(connectInfo);
database.setVersion(databaseResp.getVersion());
return database; return database;
} }
public static Database convert(DatabaseReq databaseReq) { public static Database convert(DatabaseReq databaseReq) {
Database database = new Database(); Database database = new Database();
BeanUtils.copyProperties(databaseReq, database); BeanUtils.copyProperties(databaseReq, database);
ConnectInfo connectInfo = new ConnectInfo();
connectInfo.setUserName(databaseReq.getUsername());
connectInfo.setPassword(databaseReq.getPassword());
connectInfo.setUrl(databaseReq.getConnectUrl());
connectInfo.setDatabase(databaseReq.getDatabase());
database.setConnectInfo(connectInfo);
database.setVersion(databaseReq.getVersion());
return database; return database;
} }
public static DatabaseDO convert(Database database, DatabaseDO databaseDO) { public static DatabaseDO convert(DatabaseReq databaseReq, DatabaseDO databaseDO) {
database.setId(databaseDO.getId()); BeanUtils.copyProperties(databaseReq, databaseDO);
database.setCreatedBy(databaseDO.getCreatedBy()); ConnectInfo connectInfo = getConnectInfo(databaseReq);
database.setCreatedAt(databaseDO.getCreatedAt()); databaseDO.setConfig(JSONObject.toJSONString(connectInfo));
BeanUtils.copyProperties(database, databaseDO); databaseDO.setAdmin(String.join(",", databaseReq.getAdmins()));
databaseDO.setConfig(JSONObject.toJSONString(database.getConnectInfo())); databaseDO.setViewer(String.join(",", databaseReq.getViewers()));
databaseDO.setAdmin(String.join(",", database.getAdmins()));
databaseDO.setViewer(String.join(",", database.getViewers()));
return databaseDO;
}
public static DatabaseDO convert(Database database) {
DatabaseDO databaseDO = new DatabaseDO();
BeanUtils.copyProperties(database, databaseDO);
databaseDO.setConfig(JSONObject.toJSONString(database.getConnectInfo()));
databaseDO.setAdmin(String.join(",", database.getAdmins()));
databaseDO.setViewer(String.join(",", database.getViewers()));
return databaseDO; return databaseDO;
} }
@@ -70,6 +49,16 @@ public class DatabaseConverter {
return databaseResp; return databaseResp;
} }
public static DatabaseDO convertDO(DatabaseReq databaseReq) {
DatabaseDO databaseDO = new DatabaseDO();
BeanUtils.copyProperties(databaseReq, databaseDO);
ConnectInfo connectInfo = getConnectInfo(databaseReq);
databaseDO.setConfig(JSONObject.toJSONString(connectInfo));
databaseDO.setAdmin(String.join(",", databaseReq.getAdmins()));
databaseDO.setViewer(String.join(",", databaseReq.getViewers()));
return databaseDO;
}
public static DatabaseResp convertWithPassword(DatabaseDO databaseDO) { public static DatabaseResp convertWithPassword(DatabaseDO databaseDO) {
DatabaseResp databaseResp = convert(databaseDO); DatabaseResp databaseResp = convert(databaseDO);
ConnectInfo connectInfo = JSONObject.parseObject(databaseDO.getConfig(), ConnectInfo.class); ConnectInfo connectInfo = JSONObject.parseObject(databaseDO.getConfig(), ConnectInfo.class);
@@ -86,4 +75,13 @@ public class DatabaseConverter {
return connectInfo; return connectInfo;
} }
public static ConnectInfo getConnectInfo(DatabaseReq databaseReq) {
ConnectInfo connectInfo = new ConnectInfo();
connectInfo.setUserName(databaseReq.getUsername());
connectInfo.setPassword(databaseReq.getPassword());
connectInfo.setUrl(databaseReq.getUrl());
connectInfo.setDatabase(databaseReq.getDatabase());
return connectInfo;
}
} }