diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/config/properties/EncryptProperties.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/config/properties/EncryptProperties.java new file mode 100644 index 00000000..0f2813d8 --- /dev/null +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/config/properties/EncryptProperties.java @@ -0,0 +1,59 @@ +package com.autohome.frostmourne.monitor.config.properties; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +/** + * 加密配置类 + * + * @author limbo + * @since 2022/9/14 13:48 + */ +@Configuration +public class EncryptProperties implements InitializingBean { + + private static EncryptProperties prop = null; + + public static EncryptProperties getInstance () { + return prop; + } + + @Override + public void afterPropertiesSet() throws Exception { + prop = this; + } + + /** + * 密钥 + */ + @Value("${encrypt.key:EX31$@*^ac1}") + private String key; + + /** + * 敏感字段列表 + * + * 默认会对 data_source表 properties字段值进行加密 + * 对于username, password等配置等敏感字段也要进行加解密操作,避免在前端泄漏 + */ + @Value("#{'${encrypt.sensitives:username,password}'.split(',')}") + private List sensitiveFields; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public List getSensitiveFields() { + return sensitiveFields; + } + + public void setSensitiveFields(List sensitiveFields) { + this.sensitiveFields = sensitiveFields; + } +} diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/controller/AdminController.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/controller/AdminController.java index b2d8b05b..e622fd56 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/controller/AdminController.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/controller/AdminController.java @@ -4,6 +4,7 @@ import com.autohome.frostmourne.monitor.dao.mybatis.frostmourne.domain.generate.Alarm; import com.autohome.frostmourne.monitor.model.enums.AlarmStatus; +import com.autohome.frostmourne.monitor.tool.AESUtils; import org.springframework.web.bind.annotation.*; import com.autohome.frostmourne.common.contract.PagerContract; @@ -12,6 +13,9 @@ import com.autohome.frostmourne.monitor.service.admin.IAlarmAdminService; import com.autohome.frostmourne.monitor.tool.AuthTool; +import java.util.Map; +import java.util.Objects; + @RestController @RequestMapping(value = {"/admin", "/api/monitor-api/admin"}) public class AdminController { @@ -58,6 +62,13 @@ public Protocol findById(@RequestParam(value = "alarmId") Long al if (alarmContract == null) { return new Protocol<>(404, "监控不存在"); } + + // 敏感信息加密 + Map settings = alarmContract.getMetricContract().getDataSourceContract().getSettings(); + if (Objects.nonNull(settings)) { + AESUtils.encryptMappingSensitive(settings); + alarmContract.getMetricContract().getDataSourceContract().setSettings(settings); + } return new Protocol<>(alarmContract); } @@ -66,4 +77,5 @@ public Protocol> list(int pageIndex, int pageSize, Long ala PagerContract pagerContract = this.alarmAdminService.find(pageIndex, pageSize, alarmId, name, teamName, status, serviceId); return new Protocol<>(pagerContract); } + } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/DataSourceJdbcType.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/DataSourceJdbcType.java index 7caf8012..f60b2c5f 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/DataSourceJdbcType.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/DataSourceJdbcType.java @@ -1,5 +1,7 @@ package com.autohome.frostmourne.monitor.dao.jdbc; +import com.autohome.frostmourne.monitor.model.enums.DataSourceType; + public enum DataSourceJdbcType { /** @@ -32,4 +34,8 @@ public String getDriverClassName() { return driverClassName; } + public static DataSourceJdbcType fromDataSourceType(DataSourceType dataSourceType) { + return DataSourceJdbcType.valueOf(dataSourceType.name().toUpperCase()); + } + } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/impl/DataSourceJdbcManager.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/impl/DataSourceJdbcManager.java index 0e44fa32..b71132be 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/impl/DataSourceJdbcManager.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/jdbc/impl/DataSourceJdbcManager.java @@ -6,7 +6,6 @@ import javax.sql.DataSource; -import com.autohome.frostmourne.monitor.model.enums.DataSourceType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,13 +96,7 @@ private void closeDataSource(DruidDataSource dataSource) { private DruidDataSource createDataSource(DataSourceContract dataSourceContract) throws SQLException { DruidDataSource dataSource = new DruidDataSource(); - if (DataSourceType.clickhouse.equals(dataSourceContract.getDatasourceType())) { - dataSource.setDriverClassName(DataSourceJdbcType.CLICKHOUSE.getDriverClassName()); - } else if (DataSourceType.mysql.equals(dataSourceContract.getDatasourceType())) { - dataSource.setDriverClassName(DataSourceJdbcType.MYSQL.getDriverClassName()); - } else if (DataSourceType.sqlserver.equals(dataSourceContract.getDatasourceType())) { - dataSource.setDriverClassName(DataSourceJdbcType.SQLSERVER.getDriverClassName()); - } + dataSource.setDriverClassName(DataSourceJdbcType.fromDataSourceType(dataSourceContract.getDatasourceType()).getDriverClassName()); dataSource.setUrl(dataSourceContract.getServiceAddress()); dataSource.setUsername(dataSourceContract.getSettings().get("username")); dataSource.setPassword(dataSourceContract.getSettings().get("password")); diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/domain/generate/DataSource.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/domain/generate/DataSource.java index b09caeea..c2281915 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/domain/generate/DataSource.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/domain/generate/DataSource.java @@ -167,4 +167,19 @@ public int hashCode() { result = prime * result + ((getProperties() == null) ? 0 : getProperties().hashCode()); return result; } + + @Override + public String toString() { + return "DataSource{" + + "id=" + id + + ", datasourceName='" + datasourceName + '\'' + + ", datasourceType=" + datasourceType + + ", serviceAddress='" + serviceAddress + '\'' + + ", creator='" + creator + '\'' + + ", createAt=" + createAt + + ", modifier='" + modifier + '\'' + + ", modifyAt=" + modifyAt + + ", properties='" + properties + '\'' + + '}'; + } } \ No newline at end of file diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicMapper.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicMapper.java index 1865b37a..57b49858 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicMapper.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicMapper.java @@ -6,6 +6,8 @@ import com.autohome.frostmourne.monitor.dao.mybatis.frostmourne.domain.generate.DataSource; import java.util.List; import java.util.Optional; + +import com.autohome.frostmourne.monitor.handler.CryptoTypeHandler; import org.apache.ibatis.annotations.DeleteProvider; import org.apache.ibatis.annotations.InsertProvider; import org.apache.ibatis.annotations.Mapper; @@ -58,7 +60,7 @@ public interface DataSourceDynamicMapper { @Result(column="create_at", property="createAt", jdbcType=JdbcType.TIMESTAMP), @Result(column="modifier", property="modifier", jdbcType=JdbcType.VARCHAR), @Result(column="modify_at", property="modifyAt", jdbcType=JdbcType.TIMESTAMP), - @Result(column="properties", property="properties", jdbcType=JdbcType.LONGVARCHAR) + @Result(column="properties", property="properties", jdbcType=JdbcType.LONGVARCHAR, typeHandler = CryptoTypeHandler.class) }) List selectMany(SelectStatementProvider selectStatement); diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicSqlSupport.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicSqlSupport.java index 77d8ed6e..e5c19f25 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicSqlSupport.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/dao/mybatis/frostmourne/mapper/dynamic/DataSourceDynamicSqlSupport.java @@ -71,7 +71,7 @@ public static final class DataSource extends SqlTable { public final SqlColumn modifyAt = column("modify_at", JDBCType.TIMESTAMP); - public final SqlColumn properties = column("properties", JDBCType.LONGVARCHAR); + public final SqlColumn properties = column("properties", JDBCType.LONGVARCHAR, "com.autohome.frostmourne.monitor.handler.CryptoTypeHandler"); public DataSource() { super("data_source"); diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/handler/CryptoTypeHandler.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/handler/CryptoTypeHandler.java new file mode 100644 index 00000000..1a7dd26c --- /dev/null +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/handler/CryptoTypeHandler.java @@ -0,0 +1,58 @@ +package com.autohome.frostmourne.monitor.handler; + +import com.autohome.frostmourne.monitor.tool.AESUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.*; +import java.util.Objects; + +/** + * 加解密mybatis TypeHandler + * + * @author limbo + * @since 2022/9/9 15:08 + */ +@MappedTypes({String.class}) +public class CryptoTypeHandler implements TypeHandler { + + /** + * 设置加密 + */ + @Override + public void setParameter(PreparedStatement preparedStatement, int i, String parameter, JdbcType jdbcType) throws SQLException { + if (StringUtils.isNotBlank(parameter)) { + preparedStatement.setString(i, AESUtils.encrypt(parameter)); + } else { + preparedStatement.setNull(i, Types.VARCHAR); + } + } + + /** + * 设置解密 + */ + @Override + public String getResult(ResultSet resultSet, String columnName) throws SQLException { + return decrypt(resultSet.getString(columnName)); + } + + @Override + public String getResult(ResultSet resultSet, int columnIndex) throws SQLException { + return decrypt(resultSet.getString(columnIndex)); + } + + @Override + public String getResult(CallableStatement callableStatement, int columnIndex) throws SQLException { + return decrypt(callableStatement.getString(columnIndex)); + } + + private String decrypt(String result) { + if (StringUtils.isNotBlank(result)) { + String decrypt = AESUtils.decrypt(result); + return Objects.nonNull(decrypt) ? decrypt : result; + } + return result; + } +} diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataOption.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataOption.java index 9692e765..24d339cb 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataOption.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataOption.java @@ -1,26 +1,13 @@ package com.autohome.frostmourne.monitor.model.contract; +import lombok.Data; + import java.util.List; +@Data public class DataOption { private String datasourceType; private List dataSourceOptionList; - - public String getDatasourceType() { - return datasourceType; - } - - public void setDatasourceType(String datasourceType) { - this.datasourceType = datasourceType; - } - - public List getDataSourceOptionList() { - return dataSourceOptionList; - } - - public void setDataSourceOptionList(List dataSourceOptionList) { - this.dataSourceOptionList = dataSourceOptionList; - } } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceContract.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceContract.java index 6b1c0ce2..a78b8e8f 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceContract.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceContract.java @@ -96,4 +96,19 @@ public Date getModifyAt() { public void setModifyAt(Date modifyAt) { this.modifyAt = modifyAt; } + + @Override + public String toString() { + return "DataSourceContract{" + + "id=" + id + + ", datasourceName='" + datasourceName + '\'' + + ", datasourceType=" + datasourceType + + ", serviceAddress='" + serviceAddress + '\'' + + ", settings=" + settings + + ", creator='" + creator + '\'' + + ", createAt=" + createAt + + ", modifier='" + modifier + '\'' + + ", modifyAt=" + modifyAt + + '}'; + } } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceOption.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceOption.java index a2df165b..764a5f86 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceOption.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/contract/DataSourceOption.java @@ -3,26 +3,14 @@ import java.util.List; import com.autohome.frostmourne.monitor.dao.mybatis.frostmourne.domain.generate.DataSource; +import com.autohome.frostmourne.monitor.model.vo.DataSourceVO; +import lombok.Data; +@Data public class DataSourceOption { - private DataSource dataSource; + private DataSourceVO dataSourceVO; private List dataNameContractList; - public DataSource getDataSource() { - return dataSource; - } - - public void setDataSource(DataSource dataSource) { - this.dataSource = dataSource; - } - - public List getDataNameContractList() { - return dataNameContractList; - } - - public void setDataNameContractList(List dataNameContractList) { - this.dataNameContractList = dataNameContractList; - } } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/vo/DataSourceVO.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/vo/DataSourceVO.java new file mode 100644 index 00000000..5747f271 --- /dev/null +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/model/vo/DataSourceVO.java @@ -0,0 +1,32 @@ +package com.autohome.frostmourne.monitor.model.vo; + +import com.autohome.frostmourne.monitor.model.enums.DataSourceType; +import lombok.Builder; +import lombok.Data; + +/** + * description + * + * @author limbo + * @since 2022/9/14 18:55 + */ +@Data +@Builder +public class DataSourceVO { + + /** + * 主键 + */ + private Long id; + + /** + * 数据源名称 + */ + private String datasourceName; + + /** + * 数据源类型。(Elasticsearch, Influxdb) + */ + private DataSourceType datasourceType; + +} diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/AlarmAdminService.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/AlarmAdminService.java index a45026f8..bd457a7f 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/AlarmAdminService.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/AlarmAdminService.java @@ -146,10 +146,7 @@ public boolean close(Long alarmId) { public AlarmContract findById(Long alarmId) { AlarmContract alarmContract = new AlarmContract(); Optional optionalAlarm = alarmRepository.selectByPrimaryKey(alarmId); - if (!optionalAlarm.isPresent()) { - return null; - } - Alarm alarm = optionalAlarm.get(); + Alarm alarm = optionalAlarm.orElseThrow(() -> new ProtocolException(404, String.format("The alarm[id=%s] not exists", alarmId))); alarmContract.setId(alarmId); alarmContract.setStatus(alarm.getStatus()); alarmContract.setOwnerKey(alarm.getOwnerKey()); @@ -467,25 +464,19 @@ private void saveMetric(MetricContract metricContract, Long alarmId, Long ruleId @Override public void padAlarm(AlarmContract alarmContract) { - alarmContract.setAlarmType(alarmContract.getMetricContract().getDataName()); + String dataNameStr = alarmContract.getMetricContract().getDataName(); + alarmContract.setAlarmType(dataNameStr); String ruleType = metricRuleMap.get(alarmContract.getMetricContract().getMetricType()); alarmContract.getRuleContract().setRuleType(ruleType); - if (alarmContract.getMetricContract().getDataName().equalsIgnoreCase("http")) { - return; - } - if (alarmContract.getMetricContract().getDataName().equalsIgnoreCase("ping")) { - return; - } - if (alarmContract.getMetricContract().getDataName().equalsIgnoreCase("telnet")) { + if (dataNameStr.equalsIgnoreCase("http") + || dataNameStr.equalsIgnoreCase("ping") + || dataNameStr.equalsIgnoreCase("telnet")) { return; } - Optional optionalDataName = dataNameRepository.findByName(alarmContract.getMetricContract().getDataName()); - if (!optionalDataName.isPresent()) { - throw new ProtocolException(1290, "dataName not exist. " + alarmContract.getMetricContract().getDataName()); - } - DataName dataName = optionalDataName.get(); + Optional optionalDataName = dataNameRepository.findByName(dataNameStr); + DataName dataName = optionalDataName.orElseThrow(() -> new ProtocolException(1290, "dataName not exist. " + dataNameStr)); alarmContract.getMetricContract().setDataNameId(dataName.getId()); alarmContract.getMetricContract().setDataNameContract(DataAdminService.toDataNameContract(dataName)); alarmContract.getMetricContract().setDataSourceId(dataName.getDataSourceId()); @@ -494,6 +485,5 @@ public void padAlarm(AlarmContract alarmContract) { DataSourceContract dataSourceContract = optionalDataSource.map(DataSourceTransformer::model2Contract) .orElseThrow(() -> new ProtocolException(1900, "dataSource not exist. id: " + dataName.getDataSourceId())); alarmContract.getMetricContract().setDataSourceContract(dataSourceContract); - } } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/DataAdminService.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/DataAdminService.java index 530945dd..8d1264e0 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/DataAdminService.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/service/admin/impl/DataAdminService.java @@ -11,7 +11,10 @@ import javax.annotation.Resource; +import com.autohome.frostmourne.monitor.config.properties.EncryptProperties; import com.autohome.frostmourne.monitor.model.enums.DataSourceType; +import com.autohome.frostmourne.monitor.model.vo.DataSourceVO; +import com.autohome.frostmourne.monitor.tool.AESUtils; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -69,9 +72,15 @@ public boolean saveDataSource(String account, DataSourceContract dataSourceContr dataSource.setModifier(account); dataSource.setServiceAddress(dataSourceContract.getServiceAddress()); dataSource.setModifyAt(new Date()); + if (dataSourceContract.getSettings() != null && dataSourceContract.getSettings().size() > 0) { + // 解密操作 + Map settings = handleEncryptSetting(dataSourceContract); + // 更新settings + dataSourceContract.setSettings(settings); dataSource.setProperties(JacksonUtil.serialize(dataSourceContract.getSettings())); } + if (dataSourceContract.getId() != null && dataSourceContract.getId() > 0) { dataSource.setId(dataSourceContract.getId()); if (DataSourceType.elasticsearch.equals(dataSource.getDatasourceType())) { @@ -90,7 +99,6 @@ public boolean saveDataSource(String account, DataSourceContract dataSourceContr dataSource.setCreator(account); dataSource.setCreateAt(new Date()); return dataSourceRepository.insert(dataSource) > 0; - } @Override @@ -106,8 +114,11 @@ public boolean removeDataSource(Long id) { public PagerContract findDatasource(int pageIndex, int pageSize, DataSourceType datasourceType) { Page page = PageHelper.startPage(pageIndex, pageSize); List list = this.dataSourceRepository.find(datasourceType); - return new PagerContract<>(list.stream().map(DataSourceTransformer::model2Contract).collect(Collectors.toList()), page.getPageSize(), page.getPageNum(), - (int)page.getTotal()); + return new PagerContract<>( + list.stream() + .map(i -> DataSourceTransformer.model2Contract(i, true)) + .collect(Collectors.toList()), + page.getPageSize(), page.getPageNum(), (int)page.getTotal()); } @Override @@ -134,7 +145,12 @@ public List dataOptions() { Map> dataOptionMap = new HashMap<>(); for (DataSource dataSource : dataSourceList) { DataSourceOption dataSourceOption = new DataSourceOption(); - dataSourceOption.setDataSource(dataSource); + DataSourceVO dataSourceVO = DataSourceVO.builder() + .id(dataSource.getId()) + .datasourceName(dataSource.getDatasourceName()) + .datasourceType(dataSource.getDatasourceType()) + .build(); + dataSourceOption.setDataSourceVO(dataSourceVO); dataSourceOption.setDataNameContractList(dataNameList.stream().filter(dataName -> dataName.getDataSourceId().equals(dataSource.getId())) .map(DataAdminService::toDataNameContract).collect(Collectors.toList())); if (dataOptionMap.containsKey(dataSource.getDatasourceType().name())) { @@ -184,7 +200,7 @@ private List parseTreeDataOptionByDataSourceOptions(List { - TreeDataOption option = new TreeDataOption(String.valueOf(item.getDataSource().getId()), item.getDataSource().getDatasourceName()); + TreeDataOption option = new TreeDataOption(String.valueOf(item.getDataSourceVO().getId()), item.getDataSourceVO().getDatasourceName()); option.setChildren(this.parseTreeDataOptionByDataNameContracts(item.getDataNameContractList())); return option; }).collect(Collectors.toList()); @@ -276,4 +292,22 @@ static DataNameContract toDataNameContract(DataName dataName) { return dataNameContract; } + + private Map handleEncryptSetting(DataSourceContract dataSourceContract) { + Map settings = dataSourceContract.getSettings(); + List sensitiveFields = EncryptProperties.getInstance().getSensitiveFields(); + if (!CollectionUtils.isEmpty(sensitiveFields)) { + sensitiveFields.forEach(field -> { + if (settings.containsKey(field)) { + // 判断是否是加密数据, 并更新原键值 + String decrypt = AESUtils.decrypt(settings.get(field)); + if (decrypt != null) { + settings.put(field, decrypt); + } + } + }); + } + return settings; + + } } diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/tool/AESUtils.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/tool/AESUtils.java new file mode 100644 index 00000000..2ec8ad4f --- /dev/null +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/tool/AESUtils.java @@ -0,0 +1,94 @@ +package com.autohome.frostmourne.monitor.tool; + +import com.autohome.frostmourne.monitor.config.properties.EncryptProperties; +import org.apache.commons.codec.binary.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.List; +import java.util.Map; + +/** + * AES utils + * + * @author limobo + * @since 2022/9/9 14:48 + */ +public final class AESUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(AESUtils.class); + + private static final String DEFAULT_CIPHER_ALGORITHM = "SHA1PRNG"; + private static final String KEY_ALGORITHM = "AES"; + + public static String encrypt(String data) { + try { + return doAES(data, Cipher.ENCRYPT_MODE); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { + LOGGER.error("encrypt error with data: {}", data, e); + } catch (Exception e) { + LOGGER.error("encrypt exception with data: {}", data, e); + } + return null; + } + + public static String decrypt(String data) { + try { + return doAES(data, Cipher.DECRYPT_MODE); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { + LOGGER.error("decrypt error with data: {}", data, e); + } catch (Exception e) { + LOGGER.error("decrypt exception with data: {}", data, e); + } + return null; + } + + private static String doAES(String data, int mode) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + + boolean encrypt = mode == Cipher.ENCRYPT_MODE; + byte[] content; + if (encrypt) { + content = data.getBytes(StandardCharsets.UTF_8); + } else { + content = Base64.decodeBase64(data.getBytes(StandardCharsets.UTF_8)); + } + + String key = EncryptProperties.getInstance().getKey(); + + KeyGenerator generator = KeyGenerator.getInstance(KEY_ALGORITHM); + SecureRandom secureRandom = SecureRandom.getInstance(DEFAULT_CIPHER_ALGORITHM); + secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8)); + generator.init(128, secureRandom); + SecretKeySpec keySpec = new SecretKeySpec(generator.generateKey().getEncoded(), KEY_ALGORITHM); + + Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); + cipher.init(mode, keySpec); + byte[] result = cipher.doFinal(content); + + if (encrypt) { + return Base64.encodeBase64String(result); + } else { + return new String(result, StandardCharsets.UTF_8); + } + } + + public static void encryptMappingSensitive(Map settings) { + try { + List sensitiveFields = EncryptProperties.getInstance().getSensitiveFields(); + if (!CollectionUtils.isEmpty(sensitiveFields)) { + sensitiveFields.forEach(field -> settings.computeIfPresent(field, (k, v) -> encrypt(v))); + } + } catch (Exception e) { + LOGGER.error("encryptMappingSensitive error", e); + } + } + +} diff --git a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/transform/DataSourceTransformer.java b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/transform/DataSourceTransformer.java index 27ca306f..8ef7be1d 100644 --- a/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/transform/DataSourceTransformer.java +++ b/frostmourne-monitor/src/main/java/com/autohome/frostmourne/monitor/transform/DataSourceTransformer.java @@ -1,25 +1,56 @@ package com.autohome.frostmourne.monitor.transform; import java.util.HashMap; +import java.util.List; import java.util.Map; +import com.autohome.frostmourne.monitor.config.properties.EncryptProperties; import com.autohome.frostmourne.monitor.dao.mybatis.frostmourne.domain.generate.DataSource; +import com.autohome.frostmourne.monitor.tool.AESUtils; import org.elasticsearch.common.Strings; import com.autohome.frostmourne.common.jackson.JacksonUtil; import com.autohome.frostmourne.monitor.model.contract.DataSourceContract; import com.fasterxml.jackson.core.type.TypeReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; public class DataSourceTransformer { + private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceTransformer.class); + public static DataSourceContract model2Contract(DataSource dataSource) { + return model2Contract(dataSource, false); + } + + /** + * Encrypt DataSource sensitive fields, like username, password. + * + * @param dataSource dataSource entity + * @param encrypt whether to encrypt + * @return {@link DataSourceContract} + */ + public static DataSourceContract model2Contract(DataSource dataSource, boolean encrypt) { DataSourceContract dataSourceContract = new DataSourceContract(); dataSourceContract.setDatasourceName(dataSource.getDatasourceName()); dataSourceContract.setDatasourceType(dataSource.getDatasourceType()); dataSourceContract.setId(dataSource.getId()); dataSourceContract.setServiceAddress(dataSource.getServiceAddress()); if (!Strings.isNullOrEmpty(dataSource.getProperties())) { - dataSourceContract.setSettings(JacksonUtil.deSerialize(dataSource.getProperties(), new TypeReference>() {})); + Map settings = new HashMap<>(); + try { + settings = JacksonUtil.deSerialize(dataSource.getProperties(), new TypeReference>() {}); + } catch (Exception e) { + // 当加密的key(配置 encrypt.key)发生变更后会出现原来已加密的字符串无法解密,原样输出则json解析失败 + // 此时设置一个空的 settings,能够在"数据源"页面重新设置账号密码等信息,新的key会重新加密 + LOGGER.error("dataSource properties json parse error, datasource: {}", dataSource, e); + } + // 加密敏感字段 + if (encrypt) { + AESUtils.encryptMappingSensitive(settings); + } + dataSourceContract.setSettings(settings); } else { dataSourceContract.setSettings(new HashMap<>()); } @@ -29,4 +60,5 @@ public static DataSourceContract model2Contract(DataSource dataSource) { dataSourceContract.setModifyAt(dataSource.getModifyAt()); return dataSourceContract; } + } diff --git a/frostmourne-monitor/src/main/resources/application-local.properties b/frostmourne-monitor/src/main/resources/application-local.properties index 77d21529..55c979ec 100644 --- a/frostmourne-monitor/src/main/resources/application-local.properties +++ b/frostmourne-monitor/src/main/resources/application-local.properties @@ -1,3 +1,7 @@ +### debug +logging.level.com.autohome.frostmourne.monitor: debug +logging.level.com.autohome.frostmourne.monitor.schedule: info + ### initial login password initial_password=123456 @@ -35,3 +39,7 @@ your.wechat.agentid= your.wechat.secret= schedule_enabled=true + +### encryption +encrypt_key:EX31$@*^ac1 +encrypt_sensitives:username,password diff --git a/frostmourne-monitor/src/main/resources/application.properties b/frostmourne-monitor/src/main/resources/application.properties index 80d76cf3..b2cde399 100644 --- a/frostmourne-monitor/src/main/resources/application.properties +++ b/frostmourne-monitor/src/main/resources/application.properties @@ -1,6 +1,7 @@ server.port=10054 logging.config=classpath:log4j2/log4j2.xml + initial.password=${initial_password:} spring.freemarker.checkTemplateLocation=false @@ -54,3 +55,9 @@ wechat.secret=${your.wechat.secret:} schedule.enabled=${schedule_enabled:true} schedule.trigger.pool.fast.max=200 schedule.trigger.pool.slow.max=200 + +### 加解密相关配置 +# 密钥,一旦设置不要轻易修改 +encrypt.key=${encrypt_key:EX31$@*^ac1} +# 敏感字段 +encrypt.sensitives=${encrypt_sensitives:username,password} diff --git a/frostmourne-vue/src/views/alarm/edit.vue b/frostmourne-vue/src/views/alarm/edit.vue index 23f1867b..145d3e1a 100644 --- a/frostmourne-vue/src/views/alarm/edit.vue +++ b/frostmourne-vue/src/views/alarm/edit.vue @@ -977,8 +977,8 @@ export default { } for (var j = 0; j < remoteOptions[i].dataSourceOptionList.length; j++) { var dataSource = { - label: remoteOptions[i].dataSourceOptionList[j].dataSource.datasourceName, - value: remoteOptions[i].dataSourceOptionList[j].dataSource.id, + label: remoteOptions[i].dataSourceOptionList[j].dataSourceVO.datasourceName, + value: remoteOptions[i].dataSourceOptionList[j].dataSourceVO.id, children: [] } diff --git a/pom.xml b/pom.xml index a190e6df..c25d9a56 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,14 @@ + + + + org.projectlombok + lombok + provided + +