working through refactoring postgres settings in central repo

This commit is contained in:
Greg DiCristofaro 2020-02-27 12:17:52 -05:00
parent 127cc0c9e1
commit 7dba95ed2f
6 changed files with 362 additions and 184 deletions

View File

@ -21,10 +21,8 @@ package org.sleuthkit.autopsy.centralrepository.datamodel;
/**
* common interface for settings pertaining to the database in central repository
*/
public interface CentralRepoDbSettings {
public interface CentralRepoDbConnectivityManager {
void saveSettings();
boolean createDatabase();
boolean deleteDatabase();

View File

@ -249,7 +249,7 @@ public class CentralRepoDbManager {
return configurationChanged;
}
private CentralRepoDbSettings getSelectedSettings() throws CentralRepoException {
private CentralRepoDbConnectivityManager getSelectedSettings() throws CentralRepoException {
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
return dbSettingsPostgres;
if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
@ -275,7 +275,7 @@ public class CentralRepoDbManager {
boolean result = false;
boolean dbCreated = true;
CentralRepoDbSettings selectedDbSettings = getSelectedSettings();
CentralRepoDbConnectivityManager selectedDbSettings = getSelectedSettings();
if (!selectedDbSettings.verifyDatabaseExists()) {
dbCreated = selectedDbSettings.createDatabase();
@ -336,7 +336,7 @@ public class CentralRepoDbManager {
// start with the new settings.
saveDbChoice(selectedDbChoice);
CentralRepoDbSettings selectedDbSettings = getSelectedSettings();
CentralRepoDbConnectivityManager selectedDbSettings = getSelectedSettings();
// save the new settings
selectedDbSettings.saveSettings();

View File

@ -0,0 +1,153 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.core.UserPreferencesException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.TextConverter;
import org.sleuthkit.autopsy.coreutils.TextConverterException;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
/**
*
* @author gregd
*/
public class CentralRepoPostgresSettingsManager {
private final static Logger LOGGER = Logger.getLogger(CentralRepoPostgresSettingsManager.class.getName());
private final static String DEFAULT_HOST = ""; // NON-NLS
private final static int DEFAULT_PORT = 5432;
private final static String DEFAULT_DBNAME = "central_repository"; // NON-NLS
private final static String DEFAULT_USERNAME = "";
private final static String DEFAULT_PASSWORD = "";
private static final String PASSWORD_KEY = "db.postgresql.password";
private static final String BULK_THRESHOLD_KEY = "db.postgresql.bulkThreshold";
private static final String PORT_KEY = "db.postgresql.port";
private static final String USER_KEY = "db.postgresql.user";
private static final String DBNAME_KEY = "db.postgresql.dbName";
private static final String HOST_KEY = "db.postgresql.host";
private static final String MODULE_KEY = "CentralRepository";
private static String valOrDefault(String val, String defaultVal) {
if (val == null || val.isEmpty())
return defaultVal;
return val;
}
private static int valOrDefault(String val, int defaultVal, Integer min, Integer max) {
try {
if (val == null || val.isEmpty()) {
return defaultVal;
} else {
int retVal = Integer.parseInt(val);
if ((min != null && retVal < min) || (max != null && retVal > max)) {
return defaultVal;
}
else {
return retVal;
}
}
} catch (NumberFormatException ex) {
return defaultVal;
}
}
private static void handleTry(TryHandler handler) {
try {
handler.op();
}
catch (CentralRepoException e) {}
}
private interface TryHandler {
public void op() throws CentralRepoException;
}
public static PostgresConnectionSettings loadMultiUserSettings() {
PostgresConnectionSettings settings = new PostgresConnectionSettings();
CaseDbConnectionInfo muConn;
try {
muConn = UserPreferences.getDatabaseConnectionInfo();
} catch (UserPreferencesException ex) {
LOGGER.log(Level.SEVERE, "Failed to import settings from multi-user settings.", ex);
return settings;
}
handleTry(() -> settings.setHost(valOrDefault(muConn.getHost(), DEFAULT_HOST)));
handleTry(() -> settings.setDbName(DEFAULT_DBNAME));
handleTry(() -> settings.setUserName(valOrDefault(muConn.getUserName(), DEFAULT_USERNAME)));
handleTry(() -> settings.setPort(valOrDefault(muConn.getPort(), DEFAULT_PORT, 1, 65535)));
handleTry(() -> settings.setBulkThreshold(RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD));
handleTry(() -> settings.setPassword(valOrDefault(muConn.getPassword(), DEFAULT_PASSWORD)));
return settings;
}
public static PostgresConnectionSettings loadSettings() {
PostgresConnectionSettings settings = new PostgresConnectionSettings();
Map<String, String> keyVals = ModuleSettings.getConfigSettings(MODULE_KEY);
handleTry(() -> settings.setHost(valOrDefault(keyVals.get(HOST_KEY), DEFAULT_HOST)));
handleTry(() -> settings.setDbName(valOrDefault(keyVals.get(DBNAME_KEY), DEFAULT_DBNAME)));
handleTry(() -> settings.setUserName(valOrDefault(keyVals.get(USER_KEY), DEFAULT_USERNAME)));
handleTry(() -> settings.setPort(valOrDefault(keyVals.get(PORT_KEY), DEFAULT_PORT, 1, 65535)));
handleTry(() -> settings.setBulkThreshold(valOrDefault(keyVals.get(BULK_THRESHOLD_KEY), RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD, 1, null)));
String passwordHex = keyVals.get(PASSWORD_KEY);
String password;
try {
password = TextConverter.convertHexTextToText(passwordHex);
} catch (TextConverterException ex) {
LOGGER.log(Level.WARNING, "Failed to convert password from hex text to text.", ex);
password = DEFAULT_PASSWORD;
}
final String finalPassword = password;
handleTry(() -> settings.setPassword(finalPassword));
return settings;
}
public static void saveSettings(PostgresConnectionSettings settings) {
Map<String, String> map = new HashMap<String, String>();
map.put(HOST_KEY, settings.getHost());
map.put(PORT_KEY, Integer.toString(settings.getPort()));
map.put(DBNAME_KEY, settings.getDbName());
map.put(BULK_THRESHOLD_KEY, Integer.toString(settings.getBulkThreshold()));
map.put(USER_KEY, settings.getUserName());
try {
map.put(PASSWORD_KEY, TextConverter.convertTextToHexText(settings.getPassword())); // NON-NLS
} catch (TextConverterException ex) {
LOGGER.log(Level.SEVERE, "Failed to convert password from text to hex text.", ex);
}
ModuleSettings.setConfigSettings(MODULE_KEY, map);
}
public static boolean isChanged(PostgresConnectionSettings settings) {
PostgresConnectionSettings saved = loadSettings();
return saved.equals(settings);
}
}

View File

@ -24,7 +24,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.regex.Pattern;
@ -32,7 +31,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.TextConverter;
import org.sleuthkit.autopsy.coreutils.TextConverterException;
import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo.SOFTWARE_CR_DB_SCHEMA_VERSION;
/**
* Settings for the Postgres implementation of the Central Repository database
@ -40,28 +38,18 @@ import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo
* NOTE: This is public scope because the options panel calls it directly to
* set/get
*/
public final class PostgresCentralRepoSettings implements CentralRepoDbSettings {
public final class PostgresCentralRepoSettings implements CentralRepoDbConnectivityManager {
private final static Logger LOGGER = Logger.getLogger(PostgresCentralRepoSettings.class.getName());
private final static String DEFAULT_HOST = ""; // NON-NLS
private final static int DEFAULT_PORT = 5432;
private final static String DEFAULT_DBNAME = "central_repository"; // NON-NLS
private final static String DEFAULT_USERNAME = "";
private final static String DEFAULT_PASSWORD = "";
private final static String VALIDATION_QUERY = "SELECT version()"; // NON-NLS
private final static String JDBC_BASE_URI = "jdbc:postgresql://"; // NON-NLS
private final static String JDBC_DRIVER = "org.postgresql.Driver"; // NON-NLS
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*"; // only lower case
private final static String DB_USER_NAMES_REGEX = "[a-zA-Z]\\w*";
private String host;
private int port;
private String dbName;
private int bulkThreshold;
private String userName;
private String password;
public PostgresCentralRepoSettings() {
loadSettings();
private final PostgresConnectionSettings connSettings;
public PostgresCentralRepoSettings(PostgresConnectionSettings connSettings) {
this.connSettings = connSettings;
}
@Override
@ -70,76 +58,29 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbSettings
getHost(), getPort(), getDbName(), getUserName());
}
public void loadSettings() {
host = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
if (host == null || host.isEmpty()) {
host = DEFAULT_HOST;
}
try {
String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS
if (portString == null || portString.isEmpty()) {
port = DEFAULT_PORT;
} else {
port = Integer.parseInt(portString);
if (port < 0 || port > 65535) {
port = DEFAULT_PORT;
}
}
} catch (NumberFormatException ex) {
port = DEFAULT_PORT;
}
dbName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
if (dbName == null || dbName.isEmpty()) {
dbName = DEFAULT_DBNAME;
}
try {
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
} else {
this.bulkThreshold = Integer.parseInt(bulkThresholdString);
if (getBulkThreshold() <= 0) {
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
}
}
} catch (NumberFormatException ex) {
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
}
userName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS
if (userName == null || userName.isEmpty()) {
userName = DEFAULT_USERNAME;
}
password = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.password"); // NON-NLS
if (password == null || password.isEmpty()) {
password = DEFAULT_PASSWORD;
} else {
try {
password = TextConverter.convertHexTextToText(password);
} catch (TextConverterException ex) {
LOGGER.log(Level.WARNING, "Failed to convert password from hex text to text.", ex);
password = DEFAULT_PASSWORD;
}
}
/**
* @return the VALIDATION_QUERY
*/
String getValidationQuery() {
return VALIDATION_QUERY;
}
public void saveSettings() {
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.host", getHost()); // NON-NLS
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.port", Integer.toString(port)); // NON-NLS
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.dbName", getDbName()); // NON-NLS
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.bulkThreshold", Integer.toString(getBulkThreshold())); // NON-NLS
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.user", getUserName()); // NON-NLS
try {
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.password", TextConverter.convertTextToHexText(getPassword())); // NON-NLS
} catch (TextConverterException ex) {
LOGGER.log(Level.SEVERE, "Failed to convert password from text to hex text.", ex);
}
/**
* @return the POSTGRES_DRIVER
*/
String getDriver() {
return JDBC_DRIVER;
}
/**
* @return the JDBC_BASE_URI
*/
String getJDBCBaseURI() {
return JDBC_BASE_URI;
}
/**
* Get the full connection URL as a String
*
@ -301,73 +242,33 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbSettings
}
boolean isChanged() {
String hostString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS
String userNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS
String userPasswordString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.password"); // NON-NLS
return !host.equals(hostString) || !Integer.toString(port).equals(portString)
|| !dbName.equals(dbNameString) || !Integer.toString(bulkThreshold).equals(bulkThresholdString)
|| !userName.equals(userNameString) || !password.equals(userPasswordString);
}
/**
* @return the host
*/
public String getHost() {
return host;
return connSettings.getHost();
}
/**
* @param host the host to set
*/
public void setHost(String host) throws CentralRepoException {
if (null != host && !host.isEmpty()) {
this.host = host;
} else {
throw new CentralRepoException("Invalid host name. Cannot be empty."); // NON-NLS
}
connSettings.setHost(host);
}
/**
* @return the port
*/
public int getPort() {
return port;
return connSettings.getPort();
}
/**
* @param port the port to set
*/
public void setPort(int port) throws CentralRepoException {
if (port > 0 && port < 65535) {
this.port = port;
} else {
throw new CentralRepoException("Invalid port. Must be a number greater than 0."); // NON-NLS
}
connSettings.setPort(port);
}
/**
@ -377,95 +278,55 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbSettings
* @return the dbName
*/
public String getDbName() {
return dbName.toLowerCase();
return connSettings.getDbName() == null ? null : connSettings.getDbName().toLowerCase();
}
/**
* @param dbName the dbName to set
*/
public void setDbName(String dbName) throws CentralRepoException {
if (dbName == null || dbName.isEmpty()) {
throw new CentralRepoException("Invalid database name. Cannot be empty."); // NON-NLS
} else if (!Pattern.matches(DB_NAMES_REGEX, dbName)) {
throw new CentralRepoException("Invalid database name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'."); // NON-NLS
}
this.dbName = dbName.toLowerCase();
connSettings.setDbName(dbName);
}
/**
* @return the bulkThreshold
*/
int getBulkThreshold() {
return bulkThreshold;
return connSettings.getBulkThreshold();
}
/**
* @param bulkThreshold the bulkThreshold to set
*/
public void setBulkThreshold(int bulkThreshold) throws CentralRepoException {
if (bulkThreshold > 0) {
this.bulkThreshold = bulkThreshold;
} else {
throw new CentralRepoException("Invalid bulk threshold."); // NON-NLS
}
connSettings.setBulkThreshold(bulkThreshold);
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
return connSettings.getUserName();
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) throws CentralRepoException {
if (userName == null || userName.isEmpty()) {
throw new CentralRepoException("Invalid user name. Cannot be empty."); // NON-NLS
} else if (!Pattern.matches(DB_USER_NAMES_REGEX, userName)) {
throw new CentralRepoException("Invalid user name. Name must start with a letter and can only contain letters, numbers, and '_'."); // NON-NLS
}
this.userName = userName;
connSettings.setUserName(userName);
}
/**
* @return the password
*/
public String getPassword() {
return password;
return connSettings.getPassword();
}
/**
* @param password the password to set
*/
public void setPassword(String password) throws CentralRepoException {
if (password == null || password.isEmpty()) {
throw new CentralRepoException("Invalid user password. Cannot be empty."); // NON-NLS
}
this.password = password;
connSettings.setPassword(password);
}
/**
* @return the VALIDATION_QUERY
*/
String getValidationQuery() {
return VALIDATION_QUERY;
}
/**
* @return the POSTGRES_DRIVER
*/
String getDriver() {
return JDBC_DRIVER;
}
/**
* @return the JDBC_BASE_URI
*/
String getJDBCBaseURI() {
return JDBC_BASE_URI;
}
}

View File

@ -0,0 +1,166 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.util.Objects;
import java.util.regex.Pattern;
/**
*
* @author gregd
*/
public class PostgresConnectionSettings {
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*"; // only lower case
private final static String DB_USER_NAMES_REGEX = "[a-zA-Z]\\w*";
private String host;
private int port;
private String dbName;
private int bulkThreshold;
private String userName;
private String password;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getDbName() {
return dbName;
}
public int getBulkThreshold() {
return bulkThreshold;
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
private static void validateStr(String s, String errMessage) throws CentralRepoException {
if (null == s || s.isEmpty())
throw new CentralRepoException(errMessage);
}
private static void validateRegex(String s, String pattern, String errMessage) throws CentralRepoException {
if (!Pattern.matches(pattern, s))
throw new CentralRepoException(errMessage);
}
private static void validateNum(int num, Integer min, Integer max, String errMessage) throws CentralRepoException {
if ((min != null && num < min) || (max != null && num > max))
throw new CentralRepoException(errMessage);
}
/**
* @param host the host to set
*/
public void setHost(String host) throws CentralRepoException {
validateStr(host, "Invalid host name. Cannot be empty.");
this.host = host;
}
/**
* @param port the port to set
*/
public void setPort(int port) throws CentralRepoException {
validateNum(port, 1, 65535, "Invalid port. Must be a number greater than 0.");
this.port = port;
}
/**
* @param dbName the dbName to set
*/
public void setDbName(String dbName) throws CentralRepoException {
validateStr(dbName, "Invalid database name. Cannot be empty."); // NON-NLS
validateRegex(dbName, DB_NAMES_REGEX,
"Invalid database name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'."); // NON-NLS
this.dbName = dbName.toLowerCase();
}
/**
* @param bulkThreshold the bulkThreshold to set
*/
public void setBulkThreshold(int bulkThreshold) throws CentralRepoException {
validateNum(bulkThreshold, 1, null, "Invalid bulk threshold.");
this.bulkThreshold = bulkThreshold;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) throws CentralRepoException {
validateStr(userName, "Invalid user name. Cannot be empty."); // NON-NLS
validateRegex(userName, DB_USER_NAMES_REGEX,
"Invalid user name. Name must start with a letter and can only contain letters, numbers, and '_'.");
this.userName = userName;
}
/**
* @param password the password to set
*/
public void setPassword(String password) throws CentralRepoException {
validateStr(password, "Invalid user password. Cannot be empty.");
this.password = password;
}
@Override
public int hashCode() {
int hash = 3;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PostgresConnectionSettings other = (PostgresConnectionSettings) obj;
if (this.port != other.port) {
return false;
}
if (this.bulkThreshold != other.bulkThreshold) {
return false;
}
if (!Objects.equals(this.host, other.host)) {
return false;
}
if (!Objects.equals(this.dbName, other.dbName)) {
return false;
}
if (!Objects.equals(this.userName, other.userName)) {
return false;
}
if (!Objects.equals(this.password, other.password)) {
return false;
}
return true;
}
}

View File

@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
* NOTE: This is public scope because the options panel calls it directly to
* set/get
*/
public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
public final class SqliteCentralRepoSettings implements CentralRepoDbConnectivityManager {
public final static String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
private final static Logger LOGGER = Logger.getLogger(SqliteCentralRepoSettings.class.getName());