/* * Copyright (C) 2012 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.setup; import com.intel.mtwilson.My; import com.intel.mtwilson.MyPersistenceManager; import com.intel.mtwilson.crypto.Aes128; import com.intel.dcsg.cpg.crypto.CryptographyException; import java.io.FileInputStream; import java.io.FileOutputStream; 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 javax.crypto.SecretKey; import org.apache.commons.codec.binary.Base64; import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author jbuhacoff */ public class SetupWizard { private Logger log = LoggerFactory.getLogger(getClass()); private Configuration conf; public SetupWizard(Configuration conf) { this.conf = conf; } public Connection getDatabaseConnection() throws SetupException, IOException { try { Properties p = MyPersistenceManager.getASDataJpaProperties(My.configuration()); Class.forName(p.getProperty("javax.persistence.jdbc.driver")); String url = p.getProperty("javax.persistence.jdbc.url"); String user = p.getProperty("javax.persistence.jdbc.user"); String pass = p.getProperty("javax.persistence.jdbc.password"); // System.out.println(String.format("SetupWizard.java db url: %s", url)); // System.out.println(String.format("SetupWizard.java db user: %s", user)); // System.out.println(String.format("SetupWizard.java db pass: %s", pass)); Connection conn = DriverManager.getConnection(url, user, pass); return conn; } catch (ClassNotFoundException e) { throw new SetupException("Cannot connect to database", e); } catch (SQLException e) { throw new SetupException("Cannot connect to database", e); } } public Connection getMSDatabaseConnection() throws SetupException, IOException { try { Class.forName(conf.getString("mountwilson.ms.db.driver", My.configuration().getDatabaseDriver())); /* * Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection( String.format("jdbc:mysql://%s:%d/%s", conf.getString("mountwilson.ms.db.host", conf.getString("mtwilson.db.host", "127.0.0.1")), conf.getInteger("mountwilson.ms.db.port", conf.getInteger("mtwilson.db.port", 3306)), conf.getString("mountwilson.ms.db.schema", conf.getString("mtwilson.db.schema"))), conf.getString("mountwilson.ms.db.user", conf.getString("mtwilson.db.user")), conf.getString("mountwilson.ms.db.password", conf.getString("mtwilson.db.password"))); */ String dbms = (conf.getString("mountwilson.ms.db.driver", conf.getString("mtwilson.db.driver", "com.mysql.jdbc.Driver")).contains("mysql")) ? "mysql" : "postgresql"; String url =conf.getString("mountwilson.ms.db.url", conf.getString("mtwilson.db.url", String.format("jdbc:"+dbms+"://%s:%s/%s?autoReconnect=true", conf.getString("mountwilson.ms.db.host", My.configuration().getDatabaseHost()), conf.getString("mountwilson.ms.db.port", My.configuration().getDatabasePort()), conf.getString("mountwilson.ms.db.schema", My.configuration().getDatabaseSchema())))); String user = conf.getString("mountwilson.ms.db.user", My.configuration().getDatabaseUsername()); String pass = conf.getString("mountwilson.ms.db.password", My.configuration().getDatabasePassword()); Connection conn = DriverManager.getConnection(url, user, pass); return conn; } catch (ClassNotFoundException e) { throw new SetupException("Cannot connect to database", e); } catch (SQLException e) { throw new SetupException("Cannot connect to database", e); } } /***** UNUSED public void closeConnection(Connection c) throws SetupException { try { if( c != null ) { c.close(); } } catch (SQLException e) { throw new SetupException("Error while closing database connection", e); } }*/ public void encryptVmwareConnectionStrings() throws SetupException, IOException { try { try (Connection c = getDatabaseConnection()) { /* if( !allNonEmptyFieldsInTableBeginWith(c, "tbl_hosts", "http") ) { throw new SetupException("Not all non-empty fields in tbl_hosts are valid connection strings"); } */ String dekBase64 = loadOrCreateSecretKeyAes128("mtwilson.as.dek"); encryptAllNonEmptyFieldsInTableWithKey(c, "mw_hosts", "AddOn_Connection_Info", dekBase64); } } catch (SQLException e) { throw new SetupException("Error while closing database connection", e); } } private String loadOrCreateSecretKeyAes128(String name) throws SetupException { String dekBase64 = conf.getString(name); if( dekBase64 == null || dekBase64.isEmpty() ) { try { System.out.println(String.format("Generating Data Encryption Key %s...", name)); SecretKey dek = Aes128.generateKey(); dekBase64 = Base64.encodeBase64String(dek.getEncoded()); //conf.setProperty(name, dekBase64); // this does not automatically save to the configuration file // save the new dek to configuration file. the Properties object inserts backslash-escapes before punctuation like : , = , etc. which affects the values... not sure if they'll be read in properly!!! Properties xxxTodoSubclassConf = new Properties(); try (FileInputStream in = new FileInputStream("/etc/intel/cloudsecurity/mtwilson.properties")) { xxxTodoSubclassConf.load(in); } xxxTodoSubclassConf.setProperty(name, dekBase64); try (FileOutputStream out = new FileOutputStream("/etc/intel/cloudsecurity/mtwilson.properties")) { xxxTodoSubclassConf.store(out, "auto-saved"); } My.reset(); } catch (CryptographyException e) { throw new SetupException(String.format("Cannot create Data Encryption Key %s", name), e); } catch (IOException e) { throw new SetupException(String.format("Cannot save Data Encryption Key %s", name), e); } } return dekBase64; } /** * @param c * @param tableName * @param beginWith * @return * @throws SetupException */ // commenting oput unused function (6/11 1.2) /* private boolean allNonEmptyFieldsInTableBeginWith(Connection c, String tableName, String beginWith) throws SetupException { try { boolean condition = true; Statement s = c.createStatement(); ResultSet rs = s.executeQuery(String.format("SELECT ID,Name,AddOn_Connection_Info FROM %s", tableName)); while(rs.next()) { String value = rs.getString("AddOn_Connection_Info"); if( value != null && !value.isEmpty() && !value.contains(beginWith)) { condition = false; log.error(String.format("Host %s [record %d] connection string %s", rs.getString("Name"), rs.getInt("ID"), value)); } } rs.close(); s.close(); return condition; } catch (SQLException e) { throw new SetupException(String.format("Cannot check contents of table %s", tableName), e); } } */ /** * @param c * @param tableName * @param fieldName * @param dekBase64 * @throws SetupException */ private void encryptAllNonEmptyFieldsInTableWithKey(Connection c, String tableName, String fieldName, String dekBase64) throws SetupException { try { Aes128 aes = new Aes128(Base64.decodeBase64(dekBase64)); try (PreparedStatement update = c.prepareStatement(String.format("UPDATE %s SET %s=? WHERE ID=?", tableName, fieldName));Statement query = c.createStatement();ResultSet rs = query.executeQuery(String.format("SELECT ID,%s FROM %s", fieldName, tableName))) { while (rs.next()) { String value = rs.getString(fieldName); if (value != null && !value.isEmpty() && value.startsWith("http")) { log.debug(String.format("Encrypting record %d field %s", rs.getInt("ID"), fieldName)); // do not log the value being encrypted because that leaks sensitive information to log String encrypted = aes.encryptString(value); update.setString(1, encrypted); update.setInt(2, rs.getInt("ID")); update.executeUpdate(); } } } } catch (CryptographyException e) { throw new SetupException(String.format("Cannot encrypt field %s in table %s", tableName), e); } catch (SQLException e) { throw new SetupException(String.format("Cannot check contents of table %s", tableName), e); } } }