diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java index 7a2d3a8b74..4747f990c2 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java @@ -123,16 +123,6 @@ public class DatabaseUtils { // Print basic database connection information printDBInfo(connection); - - // Print any database warnings/errors found (if any) - boolean issueFound = printDBIssues(connection); - - // If issues found, exit with an error status (even if connection succeeded). - if (issueFound) { - System.exit(1); - } else { - System.exit(0); - } } catch (SQLException sqle) { System.err.println("\nError running 'test': "); System.err.println(" - " + sqle); @@ -170,16 +160,6 @@ public class DatabaseUtils { "migrate'."); } } - - // Print any database warnings/errors found (if any) - boolean issueFound = printDBIssues(connection); - - // If issues found, exit with an error status - if (issueFound) { - System.exit(1); - } else { - System.exit(0); - } } catch (SQLException e) { System.err.println("Info exception:"); e.printStackTrace(System.err); @@ -335,31 +315,6 @@ public class DatabaseUtils { } try (Connection connection = dataSource.getConnection()) { - String dbType = getDbType(connection); - - // Not all Postgres user accounts will be able to run a 'clean', - // as only 'superuser' accounts can remove the 'pgcrypto' extension. - if (dbType.equals(DBMS_POSTGRES)) { - // Check if database user has permissions suitable to run a clean - if (!PostgresUtils.checkCleanPermissions(connection)) { - String username = connection.getMetaData().getUserName(); - // Exit immediately, providing a descriptive error message - System.out.println( - "\nERROR: The database user '" + username + "' does not have sufficient " + - "privileges to run a 'database clean' (via Flyway)."); - System.out.println( - "\nIn order to run a 'clean', the database user MUST have 'superuser' privileges"); - System.out.println( - "OR the '" + PostgresUtils.PGCRYPTO + "' extension must be installed in a " + - "separate schema (see documentation)."); - System.out.println( - "\nOptionally, you could also manually remove the '" + PostgresUtils.PGCRYPTO + - "' extension first (DROP EXTENSION " + PostgresUtils.PGCRYPTO + - " CASCADE;), then rerun the 'clean'"); - System.exit(1); - } - } - BufferedReader input = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); @@ -368,11 +323,6 @@ public class DatabaseUtils { .println("\nWARNING: ALL DATA AND TABLES IN YOUR DATABASE WILL BE PERMANENTLY DELETED.\n"); System.out.println("There is NO turning back from this action. Backup your DB before " + "continuing."); - if (dbType.equals(DBMS_POSTGRES)) { - System.out.println( - "\nPOSTGRES WARNING: the '" + PostgresUtils.PGCRYPTO + "' extension will be dropped " + - "if it is in the same schema as the DSpace database.\n"); - } System.out.print("Do you want to PERMANENTLY DELETE everything from your database? [y/n]: "); String choiceString = input.readLine(); input.close(); @@ -476,108 +426,10 @@ public class DatabaseUtils { "Database Software: " + meta.getDatabaseProductName() + " version " + meta.getDatabaseProductVersion()); System.out.println("Database Driver: " + meta.getDriverName() + " version " + meta.getDriverVersion()); - // For Postgres, report whether pgcrypto is installed - // (If it isn't, we'll also write out warnings...see below) - if (dbType.equals(DBMS_POSTGRES)) { - boolean pgcryptoUpToDate = PostgresUtils.isPgcryptoUpToDate(); - Double pgcryptoVersion = PostgresUtils.getPgcryptoInstalledVersion(connection); - System.out.println( - "PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension installed/up-to-date? " + pgcryptoUpToDate + "" + - " " + ((pgcryptoVersion != null) ? "(version=" + pgcryptoVersion + ")" : "(not installed)")); - } // Finally, print out our version of Flyway System.out.println("FlywayDB Version: " + VersionPrinter.getVersion()); } - /** - * Print any warnings about current database setup to System.err (if any). - * This is utilized by both the 'test' and 'info' commandline options. - * - * @param connection current database connection - * @return boolean true if database issues found, false otherwise - * @throws SQLException if database error occurs - */ - private static boolean printDBIssues(Connection connection) throws SQLException { - boolean issueFound = false; - - // Get the DB Type - String dbType = getDbType(connection); - - // For PostgreSQL databases, we need to check for the 'pgcrypto' extension. - // If it is NOT properly installed, we'll need to warn the user, as DSpace will be unable to proceed. - if (dbType.equals(DBMS_POSTGRES)) { - // Get version of pgcrypto available in this postgres instance - Double pgcryptoAvailable = PostgresUtils.getPgcryptoAvailableVersion(connection); - - // Generic requirements message - String requirementsMsg = "\n** DSpace REQUIRES PostgreSQL >= " + PostgresUtils.POSTGRES_VERSION + " AND " - + PostgresUtils.PGCRYPTO + " extension >= " + PostgresUtils.PGCRYPTO_VERSION + " **\n"; - - // Check if installed in PostgreSQL & a supported version - if (pgcryptoAvailable != null && pgcryptoAvailable.compareTo(PostgresUtils.PGCRYPTO_VERSION) >= 0) { - // We now know it's available in this Postgres. Let's see if it is installed in this database. - Double pgcryptoInstalled = PostgresUtils.getPgcryptoInstalledVersion(connection); - - // Check if installed in database, but outdated version - if (pgcryptoInstalled != null && pgcryptoInstalled.compareTo(PostgresUtils.PGCRYPTO_VERSION) < 0) { - System.out.println( - "\nWARNING: Required PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is OUTDATED " + - "(installed version=" + pgcryptoInstalled + ", available version = " + pgcryptoAvailable - + ")."); - System.out.println(requirementsMsg); - System.out.println( - "To update it, please connect to your DSpace database as a 'superuser' and manually run the " + - "following command: "); - System.out.println( - "\n ALTER EXTENSION " + PostgresUtils.PGCRYPTO + " UPDATE TO '" + pgcryptoAvailable + "';\n"); - issueFound = true; - } else if (pgcryptoInstalled == null) { - // If it's not installed in database - - System.out.println( - "\nWARNING: Required PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is NOT INSTALLED " + - "on this database."); - System.out.println(requirementsMsg); - System.out.println( - "To install it, please connect to your DSpace database as a 'superuser' and manually run the " + - "following command: "); - System.out.println("\n CREATE EXTENSION " + PostgresUtils.PGCRYPTO + ";\n"); - issueFound = true; - } - } else if (pgcryptoAvailable != null && pgcryptoAvailable.compareTo(PostgresUtils.PGCRYPTO_VERSION) < 0) { - // If installed in Postgres, but an unsupported version - - System.out.println( - "\nWARNING: UNSUPPORTED version of PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension found " + - "(version=" + pgcryptoAvailable + ")."); - System.out.println(requirementsMsg); - System.out.println( - "Make sure you are running a supported version of PostgreSQL, and then install " + PostgresUtils - .PGCRYPTO + " version >= " + PostgresUtils.PGCRYPTO_VERSION); - System.out.println( - "The '" + PostgresUtils.PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' " + - "package for your operating system."); - issueFound = true; - } else if (pgcryptoAvailable == null) { - // If it's not installed in Postgres - - System.out.println( - "\nWARNING: PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is NOT AVAILABLE. Please " + - "install it into this PostgreSQL instance."); - System.out.println(requirementsMsg); - System.out.println( - "The '" + PostgresUtils.PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' " + - "package for your operating system."); - System.out.println( - "Once the extension is installed globally, please connect to your DSpace database as a " + - "'superuser' and manually run the following command: "); - System.out.println("\n CREATE EXTENSION " + PostgresUtils.PGCRYPTO + ";\n"); - issueFound = true; - } - } - return issueFound; - } - /** * Setup/Initialize the Flyway Configuration to run against our DSpace database * and point at our migration scripts. diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java deleted file mode 100644 index 5459cc3cc3..0000000000 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.storage.rdbms; - -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; - -import org.apache.logging.log4j.Logger; -import org.flywaydb.core.api.FlywayException; -import org.flywaydb.core.api.callback.Callback; -import org.flywaydb.core.api.callback.Context; -import org.flywaydb.core.api.callback.Event; - -/** - * This is a FlywayCallback class which automatically verifies that "pgcrypto" - * is at the proper version before running any database migrations. - *
- * When running PostgreSQL, pgcrypto is REQUIRED by DSpace as it allows UUIDs - * to be generated. - *
- * During a database "clean", this also de-registers "pgcrypto" proir to the - * full database clean. - * - * @author Tim Donohue - */ -public class PostgreSQLCryptoChecker implements Callback { - private Logger log = org.apache.logging.log4j.LogManager.getLogger(PostgreSQLCryptoChecker.class); - - /** - * Check for pgcrypto (if needed). Throws an exception if pgcrypto is - * not installed or needs an upgrade. - * - * @param connection database connection - */ - public void checkPgCrypto(Connection connection) { - String dbType; - try { - dbType = DatabaseUtils.getDbType(connection); - } catch (SQLException se) { - throw new FlywayException("Unable to determine database type.", se); - } - - // ONLY Check if this is a PostgreSQL database - if (dbType != null && dbType.equals(DatabaseUtils.DBMS_POSTGRES)) { - // If this is a PostgreSQL database, then a supported version - // of the 'pgcrypto' extension MUST be installed to continue. - - // Check if pgcrypto is both installed & a supported version - if (!PostgresUtils.isPgcryptoUpToDate()) { - throw new FlywayException( - "This PostgreSQL Database is INCOMPATIBLE with DSpace. The upgrade will NOT proceed. " + - "A supported version (>=" + PostgresUtils.PGCRYPTO_VERSION + ") of the '" + PostgresUtils - .PGCRYPTO + "' extension must be installed! " + - "Please run 'dspace database info' for additional info/tips."); - } - } - } - - /** - * Remove pgcrypto (if necessary). - *
- * The pgcrypto extension MUST be removed before a clean or else errors occur. - * This method checks if it needs to be removed and, if so, removes it. - * - * @param connection database connection - */ - public void removePgCrypto(Connection connection) { - try { - String dbType = DatabaseUtils.getDbType(connection); - - // ONLY remove if this is a PostgreSQL database - if (dbType != null && dbType.equals(DatabaseUtils.DBMS_POSTGRES)) { - // Get current schema - String schema = DatabaseUtils.getSchemaName(connection); - - // Check if pgcrypto is in this schema - // If so, it MUST be removed before a 'clean' - if (PostgresUtils.isPgcryptoInSchema(schema)) { - // remove the extension - try (Statement statement = connection.createStatement()) { - // WARNING: ONLY superusers can remove pgcrypto. However, at this point, - // we have already verified user acct permissions via PostgresUtils.checkCleanPermissions() - // (which is called prior to a 'clean' being triggered). - statement.execute("DROP EXTENSION " + PostgresUtils.PGCRYPTO + " CASCADE"); - } - } - } - } catch (SQLException e) { - throw new FlywayException("Failed to check for and/or remove '" + PostgresUtils.PGCRYPTO + "' extension", - e); - } - } - - /** - * The callback name, Flyway will use this to sort the callbacks alphabetically before executing them - * @return The callback name - */ - @Override - public String getCallbackName() { - // Return class name only (not prepended by package) - return PostgreSQLCryptoChecker.class.getSimpleName(); - } - - /** - * Events supported by this callback. - * @param event Flyway event - * @param context Flyway context - * @return true if BEFORE_BASELINE, BEFORE_MIGRATE or BEFORE_CLEAN - */ - @Override - public boolean supports(Event event, Context context) { - return event.equals(Event.BEFORE_BASELINE) || event.equals(Event.BEFORE_MIGRATE) || - event.equals(Event.BEFORE_CLEAN); - } - - /** - * Whether event can be handled in a transaction or whether it must be handle outside of transaction. - * @param event Flyway event - * @param context Flyway context - * @return true - */ - @Override - public boolean canHandleInTransaction(Event event, Context context) { - return true; - } - - /** - * What to run when the callback is triggered. - * @param event Flyway event - * @param context Flyway context - */ - @Override - public void handle(Event event, Context context) { - // If, before initializing or migrating database, check for pgcrypto - // Else, before Cleaning database, remove pgcrypto (if exists) - if (event.equals(Event.BEFORE_BASELINE) || event.equals(Event.BEFORE_MIGRATE)) { - checkPgCrypto(context.getConnection()); - } else if (event.equals(Event.BEFORE_CLEAN)) { - removePgCrypto(context.getConnection()); - } - - } -} diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java deleted file mode 100644 index 38bb639983..0000000000 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java +++ /dev/null @@ -1,218 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.storage.rdbms; - -import static org.dspace.storage.rdbms.DatabaseUtils.getSchemaName; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import javax.sql.DataSource; - -import org.flywaydb.core.api.FlywayException; - -/** - * Database utility class specific to Postgres. - * This class contains tools and methods which are useful in determining - * the status of a PostgreSQL database backend. It's a companion class - * to DatabaseUtils, but PostgreSQL specific. - * - * @author Tim Donohue - */ -public class PostgresUtils { - // PostgreSQL pgcrypto extension name, and required versions of Postgres & pgcrypto - public static final String PGCRYPTO = "pgcrypto"; - public static final Double PGCRYPTO_VERSION = 1.1; - public static final Double POSTGRES_VERSION = 9.4; - - /** - * Default constructor - */ - private PostgresUtils() { } - - /** - * Get version of pgcrypto extension available. The extension is "available" - * if it's been installed via operating system tools/packages. It also - * MUST be installed in the DSpace database (see getPgcryptoInstalled()). - *
- * The pgcrypto extension is required for Postgres databases - * - * @param connection database connection - * @return version number or null if not available - */ - protected static Double getPgcryptoAvailableVersion(Connection connection) { - Double version = null; - - String checkPgCryptoAvailable = "SELECT default_version AS version FROM pg_available_extensions WHERE name=?"; - - // Run the query to obtain the version of 'pgcrypto' available - try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoAvailable)) { - statement.setString(1, PGCRYPTO); - try (ResultSet results = statement.executeQuery()) { - if (results.next()) { - version = results.getDouble("version"); - } - } - } catch (SQLException e) { - throw new FlywayException("Unable to determine whether 'pgcrypto' extension is available.", e); - } - - return version; - } - - /** - * Get version of pgcrypto extension installed in the DSpace database. - *
- * The pgcrypto extension is required for Postgres databases to support - * UUIDs. - * - * @param connection database connection - * @return version number or null if not installed - */ - protected static Double getPgcryptoInstalledVersion(Connection connection) { - Double version = null; - - String checkPgCryptoInstalled = "SELECT extversion AS version FROM pg_extension WHERE extname=?"; - - // Run the query to obtain the version of 'pgcrypto' installed on this database - try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoInstalled)) { - statement.setString(1, PGCRYPTO); - try (ResultSet results = statement.executeQuery()) { - if (results.next()) { - version = results.getDouble("version"); - } - } - } catch (SQLException e) { - throw new FlywayException("Unable to determine whether 'pgcrypto' extension is installed.", e); - } - - return version; - } - - /** - * Check if the pgcrypto extension is BOTH installed AND up-to-date. - *
- * This requirement is only needed for PostgreSQL databases. - * It doesn't matter what schema pgcrypto is installed in, as long as it exists. - * - * @return true if everything is installed and up-to-date. False otherwise. - */ - public static boolean isPgcryptoUpToDate() { - // Get our configured dataSource - DataSource dataSource = DatabaseUtils.getDataSource(); - - try (Connection connection = dataSource.getConnection()) { - Double pgcryptoInstalled = getPgcryptoInstalledVersion(connection); - - // Check if installed & up-to-date in this DSpace database - if (pgcryptoInstalled != null && pgcryptoInstalled.compareTo(PGCRYPTO_VERSION) >= 0) { - return true; - } - - return false; - } catch (SQLException e) { - throw new FlywayException("Unable to determine whether 'pgcrypto' extension is up-to-date.", e); - } - } - - /** - * Check if the pgcrypto extension is installed into a particular schema - *
- * This allows us to check if pgcrypto needs to be REMOVED prior to running - * a 'clean' on this database. If pgcrypto is in the same schema as the - * dspace database, a 'clean' will require removing pgcrypto FIRST. - * - * @param schema name of schema - * @return true if pgcrypto is in this schema. False otherwise. - */ - public static boolean isPgcryptoInSchema(String schema) { - // Get our configured dataSource - DataSource dataSource = DatabaseUtils.getDataSource(); - - try (Connection connection = dataSource.getConnection()) { - // Check if pgcrypto is installed in the current database schema. - String pgcryptoInstalledInSchema = "SELECT extversion FROM pg_extension,pg_namespace " + - "WHERE pg_extension.extnamespace=pg_namespace.oid " + - "AND extname=? " + - "AND nspname=?;"; - Double pgcryptoVersion = null; - try (PreparedStatement statement = connection.prepareStatement(pgcryptoInstalledInSchema)) { - statement.setString(1, PGCRYPTO); - statement.setString(2, schema); - try (ResultSet results = statement.executeQuery()) { - if (results.next()) { - pgcryptoVersion = results.getDouble("extversion"); - } - } - } - - // If a pgcrypto version returns, it's installed in this schema - if (pgcryptoVersion != null) { - return true; - } else { - return false; - } - } catch (SQLException e) { - throw new FlywayException( - "Unable to determine whether 'pgcrypto' extension is installed in schema '" + schema + "'.", e); - } - } - - - /** - * Check if the current user has permissions to run a clean on existing - * database. - *
- * Mostly this just checks if you need to remove pgcrypto, and if so,
- * whether you have permissions to do so.
- *
- * @param connection database connection
- * @return true if permissions valid, false otherwise
- */
- protected static boolean checkCleanPermissions(Connection connection) {
- try {
- // get username of our db user
- String username = connection.getMetaData().getUserName();
-
- // Check their permissions. Are they a 'superuser'?
- String checkSuperuser = "SELECT rolsuper FROM pg_roles WHERE rolname=?;";
- boolean superuser = false;
- try (PreparedStatement statement = connection.prepareStatement(checkSuperuser)) {
- statement.setString(1, username);
- try (ResultSet results = statement.executeQuery()) {
- if (results.next()) {
- superuser = results.getBoolean("rolsuper");
- }
- }
- } catch (SQLException e) {
- throw new FlywayException("Unable to determine if user '" + username + "' is a superuser.", e);
- }
-
- // If user is a superuser, then "clean" can be run successfully
- if (superuser) {
- return true;
- } else {
- // Otherwise, we'll need to see which schema 'pgcrypto' is installed in
-
- // Get current schema name
- String schema = getSchemaName(connection);
-
- // If pgcrypto is installed in this schema, then superuser privileges are needed to remove it
- if (isPgcryptoInSchema(schema)) {
- return false;
- } else {
- // otherwise, a 'clean' can be run by anyone
- return true;
- }
- }
- } catch (SQLException e) {
- throw new FlywayException("Unable to determine if DB user has 'clean' privileges.", e);
- }
- }
-}
diff --git a/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml b/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml
index 3ce641d99c..98ec222d91 100644
--- a/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml
+++ b/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml
@@ -27,7 +27,6 @@