From 1460196496d73e0db25c7beb2392cfaf9d591ed7 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Wed, 30 Oct 2013 17:03:13 -0700 Subject: [PATCH] Centralize loading of db.properties to one place There is now a method DbProperites.getDbProperties() that will load the db.properties in one place and do the proper decryption of values if needed --- .../com/cloud/bridge/persist/dao/BaseDao.java | 28 +-- .../util/EncryptionSecretKeyCheckerUtil.java | 138 ------------- .../bootstrap/spring-bootstrap-context.xml | 3 +- .../com/cloud/upgrade/DatabaseCreator.java | 12 +- .../cloud/upgrade/dao/Upgrade307to410.java | 25 +-- .../com/cloud/upgrade/dao/Upgrade40to41.java | 20 +- .../com/cloud/cluster/ClusterManagerImpl.java | 11 +- .../cluster/ClusterServiceServletAdapter.java | 18 +- .../com/cloud/utils/db/TransactionLegacy.java | 39 ++-- .../jobs/impl/AsyncJobManagerImpl.java | 14 +- .../cloudstack/region/RegionManagerImpl.java | 21 +- utils/src/com/cloud/utils/PropertiesUtil.java | 8 +- .../cloud/utils/crypt/DBEncryptionUtil.java | 26 +-- .../crypt/EncryptionSecretKeyChecker.java | 190 ++++++++---------- .../src/com/cloud/utils/db/DbProperties.java | 105 ++++++++++ 15 files changed, 241 insertions(+), 417 deletions(-) delete mode 100644 awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java create mode 100644 utils/src/com/cloud/utils/db/DbProperties.java diff --git a/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java b/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java index 83679fa002d..3b04b5070e1 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java @@ -16,18 +16,11 @@ // under the License. package com.cloud.bridge.persist.dao; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.Properties; import org.apache.log4j.Logger; -import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; -import org.jasypt.properties.EncryptableProperties; -import com.cloud.bridge.util.ConfigurationHelper; -import com.cloud.bridge.util.EncryptionSecretKeyCheckerUtil; +import com.cloud.utils.db.DbProperties; @@ -43,24 +36,9 @@ public class BaseDao { static{ logger.info("Initializing DB props"); - File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties"); - Properties EC2Prop = null; - - if (null != propertiesFile) { - if(EncryptionSecretKeyCheckerUtil.useEncryption()){ - StandardPBEStringEncryptor encryptor = EncryptionSecretKeyCheckerUtil.getEncryptor(); - EC2Prop = new EncryptableProperties(encryptor); - } else { - EC2Prop = new Properties(); - } + Properties EC2Prop = DbProperties.getDbProperties(); - try { - EC2Prop.load( new FileInputStream( propertiesFile )); - } catch (FileNotFoundException e) { - logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e); - } catch (IOException e) { - logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e); - } + if (EC2Prop.size() > 0) { dbHost = EC2Prop.getProperty( "db.cloud.host" ); awsapi_dbName = EC2Prop.getProperty( "db.awsapi.name" ); cloud_dbName = EC2Prop.getProperty( "db.cloud.name" ); diff --git a/awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java b/awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java deleted file mode 100644 index 6f0049f24c4..00000000000 --- a/awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java +++ /dev/null @@ -1,138 +0,0 @@ -// 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 com.cloud.bridge.util; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Properties; - -import org.apache.log4j.Logger; -import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; -import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; - - -public class EncryptionSecretKeyCheckerUtil { - private static final Logger s_logger = Logger.getLogger(EncryptionSecretKeyCheckerUtil.class); - - private static final String s_keyFile = "/etc/cloudstack/management/key"; - private static final String s_envKey = "CLOUD_SECRET_KEY"; - private static StandardPBEStringEncryptor s_encryptor = new StandardPBEStringEncryptor(); - private static boolean s_useEncryption = false; - - static{ - //Get encryption type from db.properties - final File dbPropsFile = ConfigurationHelper.findConfigurationFile("db.properties"); - final Properties dbProps = new Properties(); - try { - dbProps.load(new FileInputStream(dbPropsFile)); - - final String encryptionType = dbProps.getProperty("db.cloud.encryption.type"); - - s_logger.debug("Encryption Type: "+ encryptionType); - - if(encryptionType != null && !encryptionType.equals("none")){ - - s_encryptor.setAlgorithm("PBEWithMD5AndDES"); - String secretKey = null; - - SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig(); - - if(encryptionType.equals("file")){ - try { - BufferedReader in = new BufferedReader(new FileReader(s_keyFile)); - secretKey = in.readLine(); - //Check for null or empty secret key - } catch (FileNotFoundException e) { - throw new RuntimeException("File containing secret key not found: "+s_keyFile, e); - } catch (IOException e) { - throw new RuntimeException("Error while reading secret key from: "+s_keyFile, e); - } - - if(secretKey == null || secretKey.isEmpty()){ - throw new RuntimeException("Secret key is null or empty in file "+s_keyFile); - } - - } else if(encryptionType.equals("env")){ - secretKey = System.getenv(s_envKey); - if(secretKey == null || secretKey.isEmpty()){ - throw new RuntimeException("Environment variable "+s_envKey+" is not set or empty"); - } - } else if(encryptionType.equals("web")){ - ServerSocket serverSocket = null; - int port = 8097; - try { - serverSocket = new ServerSocket(port); - } catch (IOException ioex) { - throw new RuntimeException("Error initializing secret key reciever", ioex); - } - s_logger.info("Waiting for admin to send secret key on port "+port); - Socket clientSocket = null; - try { - clientSocket = serverSocket.accept(); - } catch (IOException e) { - throw new RuntimeException("Accept failed on "+port); - } - PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); - BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); - String inputLine, outputLine; - if ((inputLine = in.readLine()) != null) { - secretKey = inputLine; - } - out.close(); - in.close(); - clientSocket.close(); - serverSocket.close(); - } else { - throw new RuntimeException("Invalid encryption type: "+encryptionType); - } - - stringConfig.setPassword(secretKey); - s_encryptor.setConfig(stringConfig); - s_useEncryption = true; - } - } catch (FileNotFoundException e) { - throw new RuntimeException("File db.properties not found", e); - } catch (IOException e) { - throw new RuntimeException("Error while reading db.properties", e); - } - } - - public static StandardPBEStringEncryptor getEncryptor() { - return s_encryptor; - } - - public static boolean useEncryption(){ - return s_useEncryption; - } - - //Initialize encryptor for migration during secret key change - public static void initEncryptorForMigration(String secretKey){ - s_encryptor.setAlgorithm("PBEWithMD5AndDES"); - SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig(); - stringConfig.setPassword(secretKey); - s_encryptor.setConfig(stringConfig); - s_useEncryption = true; - } -} diff --git a/core/resources/META-INF/cloudstack/bootstrap/spring-bootstrap-context.xml b/core/resources/META-INF/cloudstack/bootstrap/spring-bootstrap-context.xml index 40fcc71c14e..5ddb66f3a9c 100644 --- a/core/resources/META-INF/cloudstack/bootstrap/spring-bootstrap-context.xml +++ b/core/resources/META-INF/cloudstack/bootstrap/spring-bootstrap-context.xml @@ -25,8 +25,9 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" - > + > + diff --git a/engine/schema/src/com/cloud/upgrade/DatabaseCreator.java b/engine/schema/src/com/cloud/upgrade/DatabaseCreator.java index 8260aa125e5..4ed389eecdd 100755 --- a/engine/schema/src/com/cloud/upgrade/DatabaseCreator.java +++ b/engine/schema/src/com/cloud/upgrade/DatabaseCreator.java @@ -18,7 +18,12 @@ */ package com.cloud.upgrade; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; @@ -33,7 +38,6 @@ import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.SystemIntegrityChecker; import com.cloud.utils.db.ScriptRunner; -import com.cloud.utils.db.Transaction; import com.cloud.utils.db.TransactionLegacy; // Creates the CloudStack Database by using the 4.0 schema and apply @@ -171,10 +175,6 @@ public class DatabaseCreator { System.exit(1); } - try { - TransactionLegacy.initDataSource(dbPropsFile); - } catch (NullPointerException e) { - } initDB(dbPropsFile, rootPassword, databases, dryRun); // Process sql files diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade307to410.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade307to410.java index aeeb6d5863f..3edc890d603 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade307to410.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade307to410.java @@ -18,21 +18,16 @@ package com.cloud.upgrade.dao; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Properties; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.crypt.EncryptionSecretKeyChecker; import org.apache.log4j.Logger; +import com.cloud.utils.db.DbProperties; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; -import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; -import org.jasypt.properties.EncryptableProperties; public class Upgrade307to410 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade307to410.class); @@ -68,23 +63,7 @@ public class Upgrade307to410 implements DbUpgrade { } private void updateRegionEntries(Connection conn) { - File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - final Properties dbProps; - if (EncryptionSecretKeyChecker.useEncryption()) { - StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); - dbProps = new EncryptableProperties(encryptor); - } else { - dbProps = new Properties(); - } - try { - dbProps.load(new FileInputStream(dbPropsFile)); - } catch (IOException e) { - s_logger.fatal("Unable to load db properties file, pl. check the classpath and file path configuration", e); - return; - } catch (NullPointerException e) { - s_logger.fatal("Unable to locate db properties file within classpath or absolute path: db.properties"); - return; - } + final Properties dbProps = DbProperties.getDbProperties(); int region_id = 1; String regionId = dbProps.getProperty("region.id"); if(regionId != null){ diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade40to41.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade40to41.java index 79ca5e1fdb1..86fe589bb18 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade40to41.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade40to41.java @@ -19,9 +19,11 @@ package com.cloud.upgrade.dao; import com.cloud.utils.PropertiesUtil; import com.cloud.utils.crypt.EncryptionSecretKeyChecker; +import com.cloud.utils.db.DbProperties; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; + import org.apache.log4j.Logger; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.properties.EncryptableProperties; @@ -81,23 +83,7 @@ public class Upgrade40to41 implements DbUpgrade { } private void updateRegionEntries(Connection conn) { - File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - final Properties dbProps; - if (EncryptionSecretKeyChecker.useEncryption()) { - StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); - dbProps = new EncryptableProperties(encryptor); - } else { - dbProps = new Properties(); - } - try { - dbProps.load(new FileInputStream(dbPropsFile)); - } catch (IOException e) { - s_logger.fatal("Unable to load db properties file, pl. check the classpath and file path configuration", e); - return; - } catch (NullPointerException e) { - s_logger.fatal("Unable to locate db properties file within classpath or absolute path: db.properties"); - return; - } + final Properties dbProps = DbProperties.getDbProperties(); int region_id = 1; String regionId = dbProps.getProperty("region.id"); if(regionId != null){ diff --git a/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java b/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java index 71bea4f2e4f..1c10a95c328 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java @@ -59,6 +59,7 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.ConnectionConcierge; import com.cloud.utils.db.DB; +import com.cloud.utils.db.DbProperties; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.TransactionCallback; import com.cloud.utils.db.TransactionLegacy; @@ -1029,15 +1030,7 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C s_logger.info("Start configuring cluster manager : " + name); } - File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - Properties dbProps = new Properties(); - try { - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); - } catch (FileNotFoundException e) { - throw new ConfigurationException("Unable to find db.properties"); - } catch (IOException e) { - throw new ConfigurationException("Unable to load db.properties content"); - } + Properties dbProps = DbProperties.getDbProperties(); _clusterNodeIP = dbProps.getProperty("cluster.node.IP"); if (_clusterNodeIP == null) { _clusterNodeIP = "127.0.0.1"; diff --git a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletAdapter.java b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletAdapter.java index f80e21f1d34..ebbbe984c5b 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletAdapter.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletAdapter.java @@ -16,9 +16,6 @@ // under the License. package com.cloud.cluster; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import java.rmi.RemoteException; import java.util.Map; import java.util.Properties; @@ -26,14 +23,13 @@ import java.util.Properties; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; - import org.apache.cloudstack.framework.config.ConfigDepot; +import org.apache.log4j.Logger; import com.cloud.cluster.dao.ManagementServerHostDao; import com.cloud.utils.NumbersUtil; -import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.DbProperties; public class ClusterServiceServletAdapter extends AdapterBase implements ClusterServiceAdapter { @@ -122,15 +118,7 @@ public class ClusterServiceServletAdapter extends AdapterBase implements Cluster if (_mshostDao != null) return; - File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - Properties dbProps = new Properties(); - try { - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); - } catch (FileNotFoundException e) { - throw new ConfigurationException("Unable to find db.properties"); - } catch (IOException e) { - throw new ConfigurationException("Unable to load db.properties content"); - } + Properties dbProps = DbProperties.getDbProperties(); _clusterServicePort = NumbersUtil.parseInt(dbProps.getProperty("cluster.servlet.port"), DEFAULT_SERVICE_PORT); if (s_logger.isInfoEnabled()) diff --git a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java index a318d83f92b..7cb4a985448 100755 --- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java +++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java @@ -93,12 +93,6 @@ public class TransactionLegacy { } catch (Exception e) { s_logger.error("Unable to register mbean for transaction", e); } - - /* FIXME: We need a better solution for this - * Initialize encryption if we need it for db.properties - */ - EncryptionSecretKeyChecker enc = new EncryptionSecretKeyChecker(); - enc.check(); } private final LinkedList _stack; @@ -1025,30 +1019,21 @@ public class TransactionLegacy { static { // Initialize with assumed db.properties file - initDataSource("db.properties"); + initDataSource(DbProperties.getDbProperties()); } - public static void initDataSource(String propsFileName) { - try { - File dbPropsFile = PropertiesUtil.findConfigFile(propsFileName); - final Properties dbProps; - if (EncryptionSecretKeyChecker.useEncryption()) { - StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); - dbProps = new EncryptableProperties(encryptor); - } else { - dbProps = new Properties(); - } - try { - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); - dbProps.load(new FileInputStream(dbPropsFile)); - } catch (IOException e) { - s_logger.fatal("Unable to load db properties file, pl. check the classpath and file path configuration", e); - return; - } catch (NullPointerException e) { - s_logger.fatal("Unable to locate db properties file within classpath or absolute path: " + propsFileName); - return; - } + public static void initDataSource(String propsFileName) throws IOException { + Properties dbProps = new Properties(); + File dbPropsFile = PropertiesUtil.findConfigFile(propsFileName); + PropertiesUtil.loadFromFile(dbProps, dbPropsFile); + initDataSource(dbProps); + } + public static void initDataSource(Properties dbProps) { + try { + if (dbProps.size() == 0) + return; + // FIXME: If params are missing...default them???? final int cloudMaxActive = Integer.parseInt(dbProps.getProperty("db.cloud.maxActive")); final int cloudMaxIdle = Integer.parseInt(dbProps.getProperty("db.cloud.maxIdle")); diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java index 29a299ff423..d79575273cd 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java @@ -17,7 +17,6 @@ package org.apache.cloudstack.framework.jobs.impl; -import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -34,7 +33,6 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; @@ -54,25 +52,26 @@ import org.apache.cloudstack.jobs.JobInfo; import org.apache.cloudstack.jobs.JobInfo.Status; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHost; import com.cloud.utils.DateUtil; import com.cloud.utils.Predicate; -import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; +import com.cloud.utils.db.DbProperties; import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.TransactionCallback; -import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionUtil; @@ -865,10 +864,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, @Override public boolean configure(String name, Map params) throws ConfigurationException { try { - final File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - final Properties dbProps = new Properties(); - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); - + final Properties dbProps = DbProperties.getDbProperties(); final int cloudMaxActive = Integer.parseInt(dbProps.getProperty("db.cloud.maxActive")); int poolSize = (cloudMaxActive * 2) / 3; diff --git a/server/src/org/apache/cloudstack/region/RegionManagerImpl.java b/server/src/org/apache/cloudstack/region/RegionManagerImpl.java index 40ac46c176c..74fa8feb4ba 100755 --- a/server/src/org/apache/cloudstack/region/RegionManagerImpl.java +++ b/server/src/org/apache/cloudstack/region/RegionManagerImpl.java @@ -30,6 +30,8 @@ import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.crypt.EncryptionSecretKeyChecker; +import com.cloud.utils.db.DbProperties; + import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; @@ -43,6 +45,7 @@ import org.springframework.stereotype.Component; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -71,23 +74,7 @@ public class RegionManagerImpl extends ManagerBase implements RegionManager, Man @Override public boolean configure(final String name, final Map params) throws ConfigurationException { _name = name; - File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - final Properties dbProps; - if (EncryptionSecretKeyChecker.useEncryption()) { - StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); - dbProps = new EncryptableProperties(encryptor); - } else { - dbProps = new Properties(); - } - try { - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); - } catch (IOException e) { - s_logger.fatal("Unable to load db properties file, pl. check the classpath and file path configuration", e); - return false; - } catch (NullPointerException e) { - s_logger.fatal("Unable to locate db properties file within classpath or absolute path: db.properties"); - return false; - } + final Properties dbProps = DbProperties.getDbProperties(); String regionId = dbProps.getProperty("region.id"); _id = 1; if(regionId != null){ diff --git a/utils/src/com/cloud/utils/PropertiesUtil.java b/utils/src/com/cloud/utils/PropertiesUtil.java index 6f3796a9f0b..78d4013ea3d 100755 --- a/utils/src/com/cloud/utils/PropertiesUtil.java +++ b/utils/src/com/cloud/utils/PropertiesUtil.java @@ -41,12 +41,12 @@ public class PropertiesUtil { public static File findConfigFile(String path) { ClassLoader cl = PropertiesUtil.class.getClassLoader(); URL url = cl.getResource(path); - if (url != null) { + if (url != null && "file".equals(url.getProtocol())) { return new File(url.getFile()); } url = ClassLoader.getSystemResource(path); - if (url != null) { + if (url != null && "file".equals(url.getProtocol())) { return new File(url.getFile()); } @@ -57,12 +57,12 @@ public class PropertiesUtil { String newPath = "conf" + (path.startsWith(File.separator) ? "" : "/") + path; url = ClassLoader.getSystemResource(newPath); - if (url != null) { + if (url != null && "file".equals(url.getProtocol())) { return new File(url.getFile()); } url = cl.getResource(newPath); - if (url != null) { + if (url != null && "file".equals(url.getProtocol())) { return new File(url.getFile()); } diff --git a/utils/src/com/cloud/utils/crypt/DBEncryptionUtil.java b/utils/src/com/cloud/utils/crypt/DBEncryptionUtil.java index 2f44c5a4fab..12e5bee05f2 100755 --- a/utils/src/com/cloud/utils/crypt/DBEncryptionUtil.java +++ b/utils/src/com/cloud/utils/crypt/DBEncryptionUtil.java @@ -16,18 +16,13 @@ // under the License.package com.cloud.utils.crypt; package com.cloud.utils.crypt; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.Properties; import org.apache.log4j.Logger; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.exceptions.EncryptionOperationNotPossibleException; -import org.jasypt.properties.EncryptableProperties; -import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.DbProperties; import com.cloud.utils.exception.CloudRuntimeException; public class DBEncryptionUtil { @@ -69,27 +64,16 @@ public class DBEncryptionUtil { } return plain; } - + private static void initialize(){ - final File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - final Properties dbProps; - + final Properties dbProps = DbProperties.getDbProperties(); + if(EncryptionSecretKeyChecker.useEncryption()){ - StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); - dbProps = new EncryptableProperties(encryptor); - try { - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); - } catch (FileNotFoundException e) { - throw new CloudRuntimeException("db.properties file not found while reading DB secret key", e); - } catch (IOException e) { - throw new CloudRuntimeException("Erroe while reading DB secret key from db.properties", e); - } - String dbSecretKey = dbProps.getProperty("db.cloud.encrypt.secret"); if(dbSecretKey == null || dbSecretKey.isEmpty()){ throw new CloudRuntimeException("Empty DB secret key in db.properties"); } - + s_encryptor = new StandardPBEStringEncryptor(); s_encryptor.setAlgorithm("PBEWithMD5AndDES"); s_encryptor.setPassword(dbSecretKey); diff --git a/utils/src/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java b/utils/src/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java index 56195de23c8..06391a5c275 100755 --- a/utils/src/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java +++ b/utils/src/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java @@ -27,20 +27,17 @@ import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; -import javax.ejb.Local; +import javax.annotation.PostConstruct; +import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.component.ComponentLifecycle; -import com.cloud.utils.component.SystemIntegrityChecker; +import com.cloud.utils.db.DbProperties; import com.cloud.utils.exception.CloudRuntimeException; -@Local(value = {SystemIntegrityChecker.class}) -public class EncryptionSecretKeyChecker extends AdapterBase implements SystemIntegrityChecker { +public class EncryptionSecretKeyChecker { private static final Logger s_logger = Logger.getLogger(EncryptionSecretKeyChecker.class); @@ -50,98 +47,92 @@ public class EncryptionSecretKeyChecker extends AdapterBase implements SystemInt private static final String s_envKey = "CLOUD_SECRET_KEY"; private static StandardPBEStringEncryptor s_encryptor = new StandardPBEStringEncryptor(); private static boolean s_useEncryption = false; - - public EncryptionSecretKeyChecker() { - setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP); + + @PostConstruct + public void init() { + /* This will call DbProperties, which will call this to initialize the encryption. Yep, + * round about and annoying */ + DbProperties.getDbProperties(); } - @Override - public void check() { - //Get encryption type from db.properties - final File dbPropsFile = PropertiesUtil.findConfigFile("db.properties"); - final Properties dbProps = new Properties(); - try { - PropertiesUtil.loadFromFile(dbProps, dbPropsFile); + public void check(Properties dbProps) throws IOException { + String encryptionType = dbProps.getProperty("db.cloud.encryption.type"); - final String encryptionType = dbProps.getProperty("db.cloud.encryption.type"); + s_logger.debug("Encryption Type: "+ encryptionType); - s_logger.debug("Encryption Type: "+ encryptionType); - - if(encryptionType == null || encryptionType.equals("none")){ - return; - } - - if (s_useEncryption) { - s_logger.warn("Encryption already enabled, is check() called twice?"); - return; - } - - s_encryptor.setAlgorithm("PBEWithMD5AndDES"); - String secretKey = null; - - SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig(); - - if(encryptionType.equals("file")){ - File keyFile = new File(s_keyFile); - if (!keyFile.exists()) { - keyFile = new File(s_altKeyFile); - } - try { - BufferedReader in = new BufferedReader(new FileReader(keyFile)); - secretKey = in.readLine(); - //Check for null or empty secret key - } catch (FileNotFoundException e) { - throw new CloudRuntimeException("File containing secret key not found: "+s_keyFile, e); - } catch (IOException e) { - throw new CloudRuntimeException("Error while reading secret key from: "+s_keyFile, e); - } - - if(secretKey == null || secretKey.isEmpty()){ - throw new CloudRuntimeException("Secret key is null or empty in file "+s_keyFile); - } - - } else if(encryptionType.equals("env")){ - secretKey = System.getenv(s_envKey); - if(secretKey == null || secretKey.isEmpty()){ - throw new CloudRuntimeException("Environment variable "+s_envKey+" is not set or empty"); - } - } else if(encryptionType.equals("web")){ - ServerSocket serverSocket = null; - int port = 8097; - try { - serverSocket = new ServerSocket(port); - } catch (IOException ioex) { - throw new CloudRuntimeException("Error initializing secret key reciever", ioex); - } - s_logger.info("Waiting for admin to send secret key on port "+port); - Socket clientSocket = null; - try { - clientSocket = serverSocket.accept(); - } catch (IOException e) { - throw new CloudRuntimeException("Accept failed on "+port); - } - PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); - BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); - String inputLine; - if ((inputLine = in.readLine()) != null) { - secretKey = inputLine; - } - out.close(); - in.close(); - clientSocket.close(); - serverSocket.close(); - } else { - throw new CloudRuntimeException("Invalid encryption type: "+encryptionType); - } - - stringConfig.setPassword(secretKey); - s_encryptor.setConfig(stringConfig); - s_useEncryption = true; - } catch (FileNotFoundException e) { - throw new CloudRuntimeException("File db.properties not found", e); - } catch (IOException e) { - throw new CloudRuntimeException("Error while reading db.properties", e); + if(encryptionType == null || encryptionType.equals("none")){ + return; } + + if (s_useEncryption) { + s_logger.warn("Encryption already enabled, is check() called twice?"); + return; + } + + s_encryptor.setAlgorithm("PBEWithMD5AndDES"); + String secretKey = null; + + SimpleStringPBEConfig stringConfig = new SimpleStringPBEConfig(); + + if(encryptionType.equals("file")){ + File keyFile = new File(s_keyFile); + if (!keyFile.exists()) { + keyFile = new File(s_altKeyFile); + } + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(keyFile)); + secretKey = in.readLine(); + //Check for null or empty secret key + } catch (FileNotFoundException e) { + throw new CloudRuntimeException("File containing secret key not found: "+s_keyFile, e); + } catch (IOException e) { + throw new CloudRuntimeException("Error while reading secret key from: "+s_keyFile, e); + } finally { + IOUtils.closeQuietly(in); + } + + if(secretKey == null || secretKey.isEmpty()){ + throw new CloudRuntimeException("Secret key is null or empty in file "+s_keyFile); + } + + } else if(encryptionType.equals("env")){ + secretKey = System.getenv(s_envKey); + if(secretKey == null || secretKey.isEmpty()){ + throw new CloudRuntimeException("Environment variable "+s_envKey+" is not set or empty"); + } + } else if(encryptionType.equals("web")){ + ServerSocket serverSocket = null; + int port = 8097; + try { + serverSocket = new ServerSocket(port); + } catch (IOException ioex) { + throw new CloudRuntimeException("Error initializing secret key reciever", ioex); + } + s_logger.info("Waiting for admin to send secret key on port "+port); + Socket clientSocket = null; + try { + clientSocket = serverSocket.accept(); + } catch (IOException e) { + throw new CloudRuntimeException("Accept failed on "+port); + } + PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); + BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + String inputLine; + if ((inputLine = in.readLine()) != null) { + secretKey = inputLine; + } + out.close(); + in.close(); + clientSocket.close(); + serverSocket.close(); + } else { + throw new CloudRuntimeException("Invalid encryption type: "+encryptionType); + } + + stringConfig.setPassword(secretKey); + s_encryptor.setConfig(stringConfig); + s_useEncryption = true; } public static StandardPBEStringEncryptor getEncryptor() { @@ -160,15 +151,4 @@ public class EncryptionSecretKeyChecker extends AdapterBase implements SystemInt s_encryptor.setConfig(stringConfig); s_useEncryption = true; } - - @Override - public boolean start() { - try { - check(); - } catch (Exception e) { - s_logger.error("System integrity check exception", e); - System.exit(1); - } - return true; - } } diff --git a/utils/src/com/cloud/utils/db/DbProperties.java b/utils/src/com/cloud/utils/db/DbProperties.java new file mode 100644 index 00000000000..a5ad383118d --- /dev/null +++ b/utils/src/com/cloud/utils/db/DbProperties.java @@ -0,0 +1,105 @@ +/* + * 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 com.cloud.utils.db; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; +import org.jasypt.properties.EncryptableProperties; + +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.crypt.EncryptionSecretKeyChecker; + +public class DbProperties { + + private static final Logger log = Logger.getLogger(DbProperties.class); + + private static Properties properties = new Properties(); + private static boolean loaded = false; + + protected static Properties wrapEncryption(Properties dbProps) throws IOException { + EncryptionSecretKeyChecker checker = new EncryptionSecretKeyChecker(); + checker.check(dbProps); + + if ( EncryptionSecretKeyChecker.useEncryption() ) { + return dbProps; + } else { + EncryptableProperties encrProps = new EncryptableProperties(EncryptionSecretKeyChecker.getEncryptor()); + encrProps.putAll(dbProps); + return encrProps; + } + } + + public synchronized static Properties getDbProperties() { + if ( ! loaded ) { + Properties dbProps = new Properties(); + InputStream is = null; + try { + File props = PropertiesUtil.findConfigFile("db.properties"); + if ( props != null && props.exists() ) { + is = new FileInputStream(props); + } + + if ( is == null ) { + is = PropertiesUtil.openStreamFromURL("db.properties"); + } + if ( is == null ) { + System.err.println("Failed to find db.properties"); + log.error("Failed to find db.properties"); + } + + dbProps.load(is); + + EncryptionSecretKeyChecker checker = new EncryptionSecretKeyChecker(); + checker.check(dbProps); + + if (EncryptionSecretKeyChecker.useEncryption()) { + StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); + EncryptableProperties encrDbProps = new EncryptableProperties(encryptor); + encrDbProps.putAll(dbProps); + dbProps = encrDbProps; + } + } catch ( IOException e ) { + throw new IllegalStateException("Failed to load db.properties", e); + } finally { + IOUtils.closeQuietly(is); + } + + properties = dbProps; + loaded = true; + } + + return properties; + } + + public synchronized static Properties setDbProperties(Properties props) throws IOException { + if ( loaded ) { + throw new IllegalStateException("DbProperties has already been loaded"); + } + properties = wrapEncryption(props); + loaded = true; + return properties; + } +}