From 3207ef6b78d930d4eb1528b253cb62337f2377c1 Mon Sep 17 00:00:00 2001 From: prachi Date: Mon, 23 Apr 2012 17:41:45 -0700 Subject: [PATCH] CS-14611 : Not able to connect to cloudbridge db changes: - Added the util code that CloudStack uses to decrypt the password --- .../com/cloud/bridge/persist/dao/BaseDao.java | 75 +++++++++++ .../persist/{ => dao}/CloudStackDao.java | 29 +---- .../cloud/bridge/persist/dao/OfferingDao.java | 28 +--- .../persist/dao/UserCredentialsDao.java | 35 +---- .../cloud/bridge/service/EC2MainServlet.java | 2 +- .../bridge/util/CloudSessionFactory.java | 12 +- .../util/EncryptionSecretKeyCheckerUtil.java | 122 ++++++++++++++++++ build/build-aws-api.xml | 3 + 8 files changed, 222 insertions(+), 84 deletions(-) create mode 100644 awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java rename awsapi/src/com/cloud/bridge/persist/{ => dao}/CloudStackDao.java (64%) create mode 100644 awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java diff --git a/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java b/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java new file mode 100644 index 00000000000..7b0ed442092 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/persist/dao/BaseDao.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved. + * + * 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.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; + + + +public class BaseDao { + public static final Logger logger = Logger.getLogger(BaseDao.class); + + protected static String cloud_dbName = null; + protected static String dbHost = null; + protected static String dbUser = null; + protected static String dbPassword = null; + protected static String dbPort = null; + protected static String awsapi_dbName = null; + + 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(); + } + + 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); + } + dbHost = EC2Prop.getProperty( "db.cloud.host" ); + awsapi_dbName = EC2Prop.getProperty( "db.awsapi.name" ); + cloud_dbName = EC2Prop.getProperty( "db.cloud.name" ); + dbUser = EC2Prop.getProperty( "db.cloud.username" ); + dbPassword = EC2Prop.getProperty( "db.cloud.password" ); + dbPort = EC2Prop.getProperty( "db.cloud.port" ); + } + } + + public BaseDao() { + } + +} diff --git a/awsapi/src/com/cloud/bridge/persist/CloudStackDao.java b/awsapi/src/com/cloud/bridge/persist/dao/CloudStackDao.java similarity index 64% rename from awsapi/src/com/cloud/bridge/persist/CloudStackDao.java rename to awsapi/src/com/cloud/bridge/persist/dao/CloudStackDao.java index 56f59369501..81f4ceb4678 100644 --- a/awsapi/src/com/cloud/bridge/persist/CloudStackDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/CloudStackDao.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.cloud.bridge.persist; +package com.cloud.bridge.persist.dao; import java.io.File; import java.io.FileInputStream; @@ -31,35 +31,12 @@ import org.apache.log4j.Logger; import com.cloud.bridge.util.ConfigurationHelper; -public class CloudStackDao { +public class CloudStackDao extends BaseDao { public static final Logger logger = Logger.getLogger(CloudStackDao.class); private Connection conn = null; - private String dbName = null; - private String dbHost = null; - private String dbUser = null; - private String dbPassword = null; - private String dbPort = null; public CloudStackDao() { - File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties"); - Properties EC2Prop = null; - - if (null != propertiesFile) { - EC2Prop = new Properties(); - 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); - } - dbHost = EC2Prop.getProperty( "db.cloud.host" ); - dbName = EC2Prop.getProperty( "db.cloud.name" ); - dbUser = EC2Prop.getProperty( "db.cloud.username" ); - dbPassword = EC2Prop.getProperty( "db.cloud.password" ); - dbPort = EC2Prop.getProperty( "db.cloud.port" ); - } } @@ -91,7 +68,7 @@ public class CloudStackDao { throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException { if (null == conn) { Class.forName( "com.mysql.jdbc.Driver" ).newInstance(); - conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName, dbUser, dbPassword ); + conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + cloud_dbName, dbUser, dbPassword ); } } diff --git a/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java b/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java index 7a031950326..c8433cfd376 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/OfferingDao.java @@ -30,36 +30,14 @@ import org.apache.log4j.Logger; import com.cloud.bridge.util.ConfigurationHelper; -public class OfferingDao { + +public class OfferingDao extends BaseDao { public static final Logger logger = Logger.getLogger(OfferingDao.class); private Connection conn = null; - private String dbName = null; - private String dbHost = null; - private String dbUser = null; - private String dbPassword = null; - private String dbPort = null; public OfferingDao() { - File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties"); - Properties EC2Prop = null; - - if (null != propertiesFile) { - EC2Prop = new Properties(); - 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); - } - dbHost = EC2Prop.getProperty( "db.cloud.host" ); - dbName = EC2Prop.getProperty( "db.awsapi.name" ); - dbUser = EC2Prop.getProperty( "db.cloud.username" ); - dbPassword = EC2Prop.getProperty( "db.cloud.password" ); - dbPort = EC2Prop.getProperty( "db.cloud.port" ); - } } public int getOfferingCount() @@ -177,7 +155,7 @@ public class OfferingDao { { if (null == conn) { Class.forName( "com.mysql.jdbc.Driver" ).newInstance(); - conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName, dbUser, dbPassword ); + conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + awsapi_dbName, dbUser, dbPassword ); } } diff --git a/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java b/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java index 5662d961963..02c6607ac96 100644 --- a/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java +++ b/awsapi/src/com/cloud/bridge/persist/dao/UserCredentialsDao.java @@ -15,54 +15,27 @@ */ package com.cloud.bridge.persist.dao; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.Properties; import org.apache.log4j.Logger; import com.cloud.bridge.model.UserCredentials; import com.cloud.bridge.service.exception.NoSuchObjectException; -import com.cloud.bridge.util.ConfigurationHelper; -public class UserCredentialsDao { + + +public class UserCredentialsDao extends BaseDao{ public static final Logger logger = Logger.getLogger(UserCredentialsDao.class); private Connection conn = null; - private String dbName = null; - private String dbHost = null; - private String dbUser = null; - private String dbPassword = null; - private String dbPort = null; public UserCredentialsDao() { - File propertiesFile = ConfigurationHelper.findConfigurationFile("db.properties"); - Properties EC2Prop = null; - - if (null != propertiesFile) { - EC2Prop = new Properties(); - 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); - } - dbHost = EC2Prop.getProperty( "db.cloud.host" ); - dbName = EC2Prop.getProperty( "db.awsapi.name" ); - dbUser = EC2Prop.getProperty( "db.cloud.username" ); - dbPassword = EC2Prop.getProperty( "db.cloud.password" ); - dbPort = EC2Prop.getProperty( "db.cloud.port" ); - } } public void setUserKeys( String cloudAccessKey, String cloudSecretKey ) @@ -164,7 +137,7 @@ public class UserCredentialsDao { throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException { if (null == conn) { Class.forName( "com.mysql.jdbc.Driver" ).newInstance(); - conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName, dbUser, dbPassword ); + conn = DriverManager.getConnection( "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + awsapi_dbName, dbUser, dbPassword ); } } diff --git a/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java b/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java index c72054842d1..86489125d63 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2MainServlet.java @@ -9,7 +9,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import com.cloud.bridge.persist.CloudStackDao; +import com.cloud.bridge.persist.dao.CloudStackDao; import com.cloud.bridge.persist.dao.UserCredentialsDao; import com.cloud.bridge.util.ConfigurationHelper; diff --git a/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java b/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java index 51876b6b107..51bfa299ca1 100644 --- a/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java +++ b/awsapi/src/com/cloud/bridge/util/CloudSessionFactory.java @@ -24,8 +24,11 @@ import java.util.Properties; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; +import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; +import org.jasypt.properties.EncryptableProperties; import org.apache.log4j.Logger; + /** * @author Kelven Yang */ @@ -48,7 +51,14 @@ public class CloudSessionFactory { String dbPort = null; if (null != propertiesFile) { - dbProp = new Properties(); + + if(EncryptionSecretKeyCheckerUtil.useEncryption()){ + StandardPBEStringEncryptor encryptor = EncryptionSecretKeyCheckerUtil.getEncryptor(); + dbProp = new EncryptableProperties(encryptor); + } else { + dbProp = new Properties(); + } + try { dbProp.load( new FileInputStream( propertiesFile )); } catch (FileNotFoundException e) { diff --git a/awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java b/awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java new file mode 100644 index 00000000000..bd7b032b8de --- /dev/null +++ b/awsapi/src/com/cloud/bridge/util/EncryptionSecretKeyCheckerUtil.java @@ -0,0 +1,122 @@ +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 = "C://pscp//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/build/build-aws-api.xml b/build/build-aws-api.xml index 2d632223647..66953464d4e 100644 --- a/build/build-aws-api.xml +++ b/build/build-aws-api.xml @@ -208,6 +208,7 @@ + @@ -281,6 +282,7 @@ + @@ -353,6 +355,7 @@ +