All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.druid.filter.config.ConfigFilter Maven / Gradle / Ivy

There is a newer version: 1.2.23
Show newest version
/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed 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 com.alibaba.druid.filter.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.security.PublicKey;
import java.sql.SQLException;
import java.util.Properties;

import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.util.StringUtils;

/**
 * 
 * 这个类主要是负责两个事情, 解密, 和下载远程的配置文件
 * [解密]
 * 
 * DruidDataSource dataSource = new DruidDataSource();
 * //dataSource.setXXX 其他设置
 * //下面两步很重要
 * //启用config filter
 * dataSource.setFilters("config");
 * //使用RSA解密(使用默认密钥)
 * dataSource.setConnectionPropertise("config.decrypt=true");
 * dataSource.setPassword("加密的密文");
 * 
 * [远程配置文件]
 * DruidDataSource dataSource = new DruidDataSource();
 * //下面两步很重要
 * //启用config filter
 * dataSource.setFilters("config");
 * //使用RSA解密(使用默认密钥)
 * dataSource.setConnectionPropertise("config.file=http://localhost:8080/remote.propreties;");
 * 
 * [Spring的配置解密]
 * 
 * <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
 *     <property name="password" value="加密的密文" />
 *     <!-- 其他的属性设置 -->
 *     <property name="filters" value="config" />
 *     <property name="connectionProperties" value="config.decrypt=true" />
 * </bean>
 * 
 * [Spring的配置远程配置文件]
 * 
 * <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
 *     <property name="filters" value="config" />
 *     <property name="connectionProperties" value="config.file=http://localhost:8080/remote.propreties; />
 * </bean>
 * 
 * [使用系统属性配置远程文件]
 * java -Ddruid.config.file=file:///home/test/my.properties ...
 * 
 * 远程配置文件格式:
 * 1. 其他的属性KEY请查看 @see com.alibaba.druid.pool.DruidDataSourceFactory
 * 2. config filter 相关设置:
 * #远程文件路径
 * config.file=http://xxxxx(http://开头或者file:开头)
 * 
 * #RSA解密, Key不指定, 使用默认的
 * config.decrypt=true
 * config.decrypt.key=密钥字符串
 * config.decrypt.keyFile=密钥文件路径
 * config.decrypt.x509File=证书路径
 * 
 * 
* * @author Jonas Yang */ public class ConfigFilter extends FilterAdapter { private static Log LOG = LogFactory.getLog(ConfigFilter.class); public static final String CONFIG_FILE = "config.file"; public static final String CONFIG_DECRYPT = "config.decrypt"; public static final String CONFIG_KEY = "config.decrypt.key"; public static final String SYS_PROP_CONFIG_FILE = "druid.config.file"; public static final String SYS_PROP_CONFIG_DECRYPT = "druid.config.decrypt"; public static final String SYS_PROP_CONFIG_KEY = "druid.config.decrypt.key"; public ConfigFilter(){ } public void init(DataSourceProxy dataSourceProxy) { if (!(dataSourceProxy instanceof DruidDataSource)) { LOG.error("ConfigLoader only support DruidDataSource"); } DruidDataSource dataSource = (DruidDataSource) dataSourceProxy; Properties connectinProperties = dataSource.getConnectProperties(); Properties configFileProperties = loadPropertyFromConfigFile(connectinProperties); // 判断是否需要解密,如果需要就进行解密行动 boolean decrypt = isDecrypt(connectinProperties, configFileProperties); if (configFileProperties == null) { if (decrypt) { decrypt(dataSource, null); } return; } if (decrypt) { decrypt(dataSource, configFileProperties); } try { DruidDataSourceFactory.config(dataSource, configFileProperties); } catch (SQLException e) { throw new IllegalArgumentException("Config DataSource error.", e); } } public boolean isDecrypt(Properties connectinProperties, Properties configFileProperties) { String decrypterId = connectinProperties.getProperty(CONFIG_DECRYPT); if (decrypterId == null || decrypterId.length() == 0) { if (configFileProperties != null) { decrypterId = configFileProperties.getProperty(CONFIG_DECRYPT); } } if (decrypterId == null || decrypterId.length() == 0) { decrypterId = System.getProperty(SYS_PROP_CONFIG_DECRYPT); } return Boolean.valueOf(decrypterId); } Properties loadPropertyFromConfigFile(Properties connectinProperties) { String configFile = connectinProperties.getProperty(CONFIG_FILE); if (configFile == null) { configFile = System.getProperty(SYS_PROP_CONFIG_FILE); } if (configFile != null && configFile.length() > 0) { if (LOG.isInfoEnabled()) { LOG.info("DruidDataSource Config File load from : " + configFile); } Properties info = loadConfig(configFile); if (info == null) { throw new IllegalArgumentException("Cannot load remote config file from the [config.file=" + configFile + "]."); } return info; } return null; } public void decrypt(DruidDataSource dataSource, Properties info) { try { String encryptedPassword = null; if (info != null) { encryptedPassword = info.getProperty(DruidDataSourceFactory.PROP_PASSWORD); } if (encryptedPassword == null || encryptedPassword.length() == 0) { encryptedPassword = dataSource.getConnectProperties().getProperty(DruidDataSourceFactory.PROP_PASSWORD); } if (encryptedPassword == null || encryptedPassword.length() == 0) { encryptedPassword = dataSource.getPassword(); } PublicKey publicKey = getPublicKey(dataSource.getConnectProperties(), info); String passwordPlainText = ConfigTools.decrypt(publicKey, encryptedPassword); if (info != null) { info.setProperty(DruidDataSourceFactory.PROP_PASSWORD, passwordPlainText); } else { dataSource.setPassword(passwordPlainText); } } catch (Exception e) { throw new IllegalArgumentException("Failed to decrypt.", e); } } public PublicKey getPublicKey(Properties connectinProperties, Properties configFileProperties) { String key = null; if (configFileProperties != null) { key = configFileProperties.getProperty(CONFIG_KEY); } if (StringUtils.isEmpty(key) && connectinProperties != null) { key = connectinProperties.getProperty(CONFIG_KEY); } if (StringUtils.isEmpty(key)) { key = System.getProperty(SYS_PROP_CONFIG_KEY); } return ConfigTools.getPublicKey(key); } public Properties loadConfig(String filePath) { Properties properties = new Properties(); InputStream inStream = null; try { boolean xml = false; if (filePath.startsWith("file://")) { filePath = filePath.substring("file://".length()); inStream = getFileAsStream(filePath); xml = filePath.endsWith(".xml"); } else if (filePath.startsWith("http://") || filePath.startsWith("https://")) { URL url = new URL(filePath); inStream = url.openStream(); xml = url.getPath().endsWith(".xml"); } else if (filePath.startsWith("classpath:")) { String resourcePath = filePath.substring("classpath:".length()); inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourcePath); // 在classpath下应该也可以配置xml文件吧? xml = resourcePath.endsWith(".xml"); } else { inStream = getFileAsStream(filePath); xml = filePath.endsWith(".xml"); } if (inStream == null) { LOG.error("load config file error, file : " + filePath); return null; } if (xml) { properties.loadFromXML(inStream); } else { properties.load(inStream); } return properties; } catch (Exception ex) { LOG.error("load config file error, file : " + filePath, ex); return null; } finally { JdbcUtils.close(inStream); } } private InputStream getFileAsStream(String filePath) throws FileNotFoundException { InputStream inStream = null; File file = new File(filePath); if (file.exists()) { inStream = new FileInputStream(file); } else { inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath); } return inStream; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy