From 291d778ee2a96bf2d36e15f08ebe50650ed719f7 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Tue, 17 Mar 2020 16:16:04 -0400 Subject: [PATCH] 6151: Do not add account_id column to non-account correlation attribute instance tables --- .../CentralRepoDbUpgrader13To14.java | 25 ++++++------ .../datamodel/CentralRepoDbUtil.java | 13 +++++++ .../datamodel/RdbmsCentralRepo.java | 31 ++++++++++----- .../datamodel/RdbmsCentralRepoFactory.java | 38 +++++++++++++++++-- 4 files changed, 82 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUpgrader13To14.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUpgrader13To14.java index 9d6473055e..dbd1e77da4 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUpgrader13To14.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUpgrader13To14.java @@ -51,7 +51,7 @@ public class CentralRepoDbUpgrader13To14 implements CentralRepoDbUpgrader { if (type.getId() >= CorrelationAttributeInstance.ADDITIONAL_TYPES_BASE_ID) { // these are new Correlation types - new tables need to be created - statement.execute(String.format(RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform), instance_type_dbname, instance_type_dbname)); + statement.execute(String.format(RdbmsCentralRepoFactory.getCreateAccountInstancesTableTemplate(selectedPlatform), instance_type_dbname, instance_type_dbname)); statement.execute(String.format(RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate(), instance_type_dbname, instance_type_dbname)); statement.execute(String.format(RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate(), instance_type_dbname, instance_type_dbname)); statement.execute(String.format(RdbmsCentralRepoFactory.getAddValueIndexTemplate(), instance_type_dbname, instance_type_dbname)); @@ -61,18 +61,19 @@ public class CentralRepoDbUpgrader13To14 implements CentralRepoDbUpgrader { // add new correlation type CentralRepoDbUtil.insertCorrelationType(connection, type); - } else { - - // Alter the existing X_Instance tables to add account_id column - String sqlStr = String.format(getAlterArtifactInstancesAddAccountIdTemplate(selectedPlatform), instance_type_dbname); - statement.execute(sqlStr); - - // SQLite does NOT allow adding a constraint with Alter Table statement. - // The alternative would be to create new tables, copy all data over, and delete old tables - potentially a time consuming process. - // We decided to not add this constraint for SQLite, since there likely aren't many users using SQLite based Central Repo. - if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) { - sqlStr = String.format(getAlterArtifactInstancesAddAccountIdConstraintTemplate(), instance_type_dbname); + } else { // existing attributes + // Alter the existing _instance tables for Phone and Email attributes to add account_id column + if (type.getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID || type.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID) { + String sqlStr = String.format(getAlterArtifactInstancesAddAccountIdTemplate(selectedPlatform), instance_type_dbname); statement.execute(sqlStr); + + // SQLite does NOT allow adding a constraint with Alter Table statement. + // The alternative would be to create new tables, copy all data over, and delete old tables - potentially a time consuming process. + // We decided to not add this constraint for SQLite, since there likely aren't many users using SQLite based Central Repo. + if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) { + sqlStr = String.format(getAlterArtifactInstancesAddAccountIdConstraintTemplate(), instance_type_dbname); + statement.execute(sqlStr); + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java index 826c315c02..69ea8d4e05 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java @@ -325,4 +325,17 @@ public class CentralRepoDbUtil { closeStatement(preparedStatement); } + /** + * Checks if the given correlation attribute type has an account behind it. + * + * @param type Correlation type to check. + * + * @return True If the specified correlation type has an account. + */ + static boolean correlationAttribHasAnAccount(CorrelationAttributeInstance.Type type) { + return (type.getId() >= CorrelationAttributeInstance.ADDITIONAL_TYPES_BASE_ID) + || type.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID + || type.getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID; + } + } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index 63f8e2f13a..148513f40c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -1002,18 +1002,26 @@ abstract class RdbmsCentralRepo implements CentralRepository { public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) throws CentralRepoException { checkAddArtifactInstanceNulls(eamArtifact); - - - - // @@@ We should cache the case and data source IDs in memory String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()); - String sql - = "INSERT INTO " + boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType()); + + String sql; + // _instance table for accounts have an additional account_id column + if (artifactHasAnAccount) { + sql = "INSERT INTO " + tableName + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?) " + getConflictClause(); + } + else { + sql = "INSERT INTO " + + tableName + + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) " + + "VALUES (?, ?, ?, ?, ?, ?, ?) " + + getConflictClause(); + } try (Connection conn = connect(); PreparedStatement preparedStatement = conn.prepareStatement(sql);) { @@ -1032,10 +1040,13 @@ abstract class RdbmsCentralRepo implements CentralRepository { } preparedStatement.setLong(7, eamArtifact.getFileObjectId()); - if (eamArtifact.getAccountId() >= 0) { - preparedStatement.setLong(8, eamArtifact.getAccountId()); - } else { - preparedStatement.setNull(8, Types.INTEGER); + // set in the accountId only for artifacts that represent accounts + if (artifactHasAnAccount) { + if (eamArtifact.getAccountId() >= 0) { + preparedStatement.setLong(8, eamArtifact.getAccountId()); + } else { + preparedStatement.setNull(8, Types.INTEGER); + } } preparedStatement.executeUpdate(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java index 1232d708a6..d50d344a5e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java @@ -83,6 +83,7 @@ public class RdbmsCentralRepoFactory { public boolean initializeDatabaseSchema() { String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(selectedPlatform); + String createAccountInstancesTableTemplate = getCreateAccountInstancesTableTemplate(selectedPlatform); String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate(); @@ -147,7 +148,13 @@ public class RdbmsCentralRepoFactory { reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); - stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); + // use the correct create table template, based on whether the attribute type represents an account or not. + String createTableTemplate = (CentralRepoDbUtil.correlationAttribHasAnAccount(type)) + ? createAccountInstancesTableTemplate + : createArtifactInstancesTableTemplate; + + stmt.execute(String.format(createTableTemplate, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); @@ -357,7 +364,7 @@ public class RdbmsCentralRepoFactory { + ")"; } /** - * Get the template String for creating a new _instances table in a Sqlite + * Get the template String for creating a new _instances table for non account artifacts in * central repository. %s will exist in the template where the name of the * new table will be added. * @@ -365,6 +372,31 @@ public class RdbmsCentralRepoFactory { */ static String getCreateArtifactInstancesTableTemplate(CentralRepoPlatforms selectedPlatform) { // Each "%s" will be replaced with the relevant TYPE_instances table name. + + return "CREATE TABLE IF NOT EXISTS %s (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "case_id integer NOT NULL," + + "data_source_id integer NOT NULL," + + "value text NOT NULL," + + "file_path text NOT NULL," + + "known_status integer NOT NULL," + + "comment text," + + "file_obj_id " + getBigIntType(selectedPlatform) + " ," + + "CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path)" + getOnConflictIgnoreClause(selectedPlatform) + "," + + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"; + } + + /** + * Get the template String for creating a new _instances table for Accounts in + * central repository. %s will exist in the template where the name of the + * new table will be added. + * + * @return a String which is a template for creating a _instances table + */ + static String getCreateAccountInstancesTableTemplate(CentralRepoPlatforms selectedPlatform) { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE TABLE IF NOT EXISTS %s (" + getNumericPrimaryKeyClause("id", selectedPlatform) + "case_id integer NOT NULL," @@ -380,7 +412,7 @@ public class RdbmsCentralRepoFactory { + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"; } - + /** * Get the statement String for creating a new data_sources table in a * Sqlite central repository.