diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index b86ad716..22560be0 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -5,17 +5,15 @@ import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.security.crypts.XfBCrypt; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; -import java.sql.Blob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; @@ -44,19 +42,11 @@ public class MySQL implements DataSource { private int maxLifetime; private List columnOthers; private Columns col; - private HashAlgorithm hashAlgorithm; + private MySqlExtension sqlExtension; private HikariDataSource ds; - private String phpBbPrefix; - private String ipbPrefix; - private String xfPrefix; - private String wordpressPrefix; - private int phpBbGroup; - private int ipbGroup; - private int xfGroup; - - public MySQL(Settings settings) throws ClassNotFoundException, SQLException { - setParameters(settings); + public MySQL(Settings settings, MySqlExtensionsFactory extensionsFactory) throws SQLException { + setParameters(settings, extensionsFactory); // Set the connection arguments (and check if connection is ok) try { @@ -86,9 +76,9 @@ public class MySQL implements DataSource { } @VisibleForTesting - MySQL(Settings settings, HikariDataSource hikariDataSource) { + MySQL(Settings settings, HikariDataSource hikariDataSource, MySqlExtensionsFactory extensionsFactory) { ds = hikariDataSource; - setParameters(settings); + setParameters(settings, extensionsFactory); } /** @@ -96,7 +86,7 @@ public class MySQL implements DataSource { * * @param settings the settings to read properties from */ - private void setParameters(Settings settings) { + private void setParameters(Settings settings, MySqlExtensionsFactory extensionsFactory) { this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST); this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT); this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); @@ -105,14 +95,7 @@ public class MySQL implements DataSource { this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS); this.col = new Columns(settings); - this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); - this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); - this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); - this.ipbPrefix = settings.getProperty(HooksSettings.IPB_TABLE_PREFIX); - this.ipbGroup = settings.getProperty(HooksSettings.IPB_ACTIVATED_GROUP_ID); - this.xfPrefix = settings.getProperty(HooksSettings.XF_TABLE_PREFIX); - this.xfGroup = settings.getProperty(HooksSettings.XF_ACTIVATED_GROUP_ID); - this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); + sqlExtension = extensionsFactory.buildExtension(col); this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); if (poolSize == -1) { poolSize = Utils.getCoreCount() * 3; @@ -303,28 +286,14 @@ public class MySQL implements DataSource { PlayerAuth auth; try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { pst.setString(1, user.toLowerCase()); - int id; try (ResultSet rs = pst.executeQuery()) { - if (!rs.next()) { - return null; - } - id = rs.getInt(col.ID); - auth = buildAuthFromResultSet(rs); - } - if (hashAlgorithm == HashAlgorithm.XFBCRYPT) { - try (PreparedStatement pst2 = con.prepareStatement( - "SELECT data FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;")) { - pst2.setInt(1, id); - try (ResultSet rs = pst2.executeQuery()) { - if (rs.next()) { - Blob blob = rs.getBlob("data"); - byte[] bytes = blob.getBytes(1, (int) blob.length()); - auth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes))); - } - } + if (rs.next()) { + int id = rs.getInt(col.ID); + auth = buildAuthFromResultSet(rs); + sqlExtension.extendAuth(auth, id, con); + return auth; } } - return auth; } catch (SQLException ex) { logSqlException(ex); } @@ -364,231 +333,8 @@ public class MySQL implements DataSource { } } } - if (hashAlgorithm == HashAlgorithm.IPB4) { - sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, auth.getNickname()); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - // Update player group in core_members - sql = "UPDATE " + ipbPrefix + tableName + " SET " + tableName + ".member_group_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, ipbGroup); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Get current time without ms - long time = System.currentTimeMillis() / 1000; - // update joined date - sql = "UPDATE " + ipbPrefix + tableName + " SET " + tableName + ".joined=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setLong(1, time); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Update last_visit - sql = "UPDATE " + ipbPrefix + tableName + " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setLong(1, time); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - } - } - } - } else if (hashAlgorithm == HashAlgorithm.PHPBB) { - sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, auth.getNickname()); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - // Insert player in phpbb_user_group - sql = "INSERT INTO " + phpBbPrefix - + "user_group (group_id, user_id, group_leader, user_pending) VALUES (?,?,?,?);"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, phpBbGroup); - pst2.setInt(2, id); - pst2.setInt(3, 0); - pst2.setInt(4, 0); - pst2.executeUpdate(); - } - // Update username_clean in phpbb_users - sql = "UPDATE " + tableName + " SET " + tableName - + ".username_clean=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setString(1, auth.getNickname()); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Update player group in phpbb_users - sql = "UPDATE " + tableName + " SET " + tableName - + ".group_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, phpBbGroup); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Get current time without ms - long time = System.currentTimeMillis() / 1000; - // Update user_regdate - sql = "UPDATE " + tableName + " SET " + tableName - + ".user_regdate=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setLong(1, time); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Update user_lastvisit - sql = "UPDATE " + tableName + " SET " + tableName - + ".user_lastvisit=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setLong(1, time); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Increment num_users - sql = "UPDATE " + phpBbPrefix - + "config SET config_value = config_value + 1 WHERE config_name = 'num_users';"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.executeUpdate(); - } - } - } - } - } else if (hashAlgorithm == HashAlgorithm.WORDPRESS) { - // NOTE: Eclipse says pst should be closed HERE, but it's a bug, we already close it above. -sgdc3 - try (PreparedStatement pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;")) { - pst.setString(1, auth.getNickname()); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?)"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - // First Name - pst2.setInt(1, id); - pst2.setString(2, "first_name"); - pst2.setString(3, ""); - pst2.addBatch(); - // Last Name - pst2.setInt(1, id); - pst2.setString(2, "last_name"); - pst2.setString(3, ""); - pst2.addBatch(); - // Nick Name - pst2.setInt(1, id); - pst2.setString(2, "nickname"); - pst2.setString(3, auth.getNickname()); - pst2.addBatch(); - // Description - pst2.setInt(1, id); - pst2.setString(2, "description"); - pst2.setString(3, ""); - pst2.addBatch(); - // Rich_Editing - pst2.setInt(1, id); - pst2.setString(2, "rich_editing"); - pst2.setString(3, "true"); - pst2.addBatch(); - // Comments_Shortcuts - pst2.setInt(1, id); - pst2.setString(2, "comment_shortcuts"); - pst2.setString(3, "false"); - pst2.addBatch(); - // admin_color - pst2.setInt(1, id); - pst2.setString(2, "admin_color"); - pst2.setString(3, "fresh"); - pst2.addBatch(); - // use_ssl - pst2.setInt(1, id); - pst2.setString(2, "use_ssl"); - pst2.setString(3, "0"); - pst2.addBatch(); - // show_admin_bar_front - pst2.setInt(1, id); - pst2.setString(2, "show_admin_bar_front"); - pst2.setString(3, "true"); - pst2.addBatch(); - // wp_capabilities - pst2.setInt(1, id); - pst2.setString(2, wordpressPrefix + "capabilities"); - pst2.setString(3, "a:1:{s:10:\"subscriber\";b:1;}"); - pst2.addBatch(); - // wp_user_level - pst2.setInt(1, id); - pst2.setString(2, wordpressPrefix + "user_level"); - pst2.setString(3, "0"); - pst2.addBatch(); - // default_password_nag - pst2.setInt(1, id); - pst2.setString(2, "default_password_nag"); - pst2.setString(3, ""); - pst2.addBatch(); - // Execute queries - pst2.executeBatch(); - pst2.clearBatch(); - } - } - } - } - } else if (hashAlgorithm == HashAlgorithm.XFBCRYPT) { - // NOTE: Eclipse says pst should be closed HERE, but it's a bug, we already close it above. -sgdc3 - try (PreparedStatement pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;")) { - pst.setString(1, auth.getNickname()); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - // Insert player password, salt in xf_user_authenticate - sql = "INSERT INTO " + xfPrefix + "user_authenticate (user_id, scheme_class, data) VALUES (?,?,?)"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, id); - pst2.setString(2, XfBCrypt.SCHEME_CLASS); - String serializedHash = XfBCrypt.serializeHash(auth.getPassword().getHash()); - byte[] bytes = serializedHash.getBytes(); - Blob blob = con.createBlob(); - blob.setBytes(1, bytes); - pst2.setBlob(3, blob); - pst2.executeUpdate(); - } - // Update player group in xf_users - sql = "UPDATE " + tableName + " SET " + tableName + ".user_group_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, xfGroup); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Update player permission combination in xf_users - sql = "UPDATE " + tableName + " SET " + tableName + ".permission_combination_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, xfGroup); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Insert player privacy combination in xf_user_privacy - sql = "INSERT INTO " + xfPrefix + "user_privacy (user_id, allow_view_profile, allow_post_profile, allow_send_personal_conversation, allow_view_identities, allow_receive_news_feed) VALUES (?,?,?,?,?,?)"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, id); - pst2.setString(2, "everyone"); - pst2.setString(3, "members"); - pst2.setString(4, "members"); - pst2.setString(5, "everyone"); - pst2.setString(6, "everyone"); - pst2.executeUpdate(); - } - // Insert player group relation in xf_user_group_relation - sql = "INSERT INTO " + xfPrefix + "user_group_relation (user_id, user_group_id, is_primary) VALUES (?,?,?)"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, id); - pst2.setInt(2, xfGroup); - pst2.setString(3, "1"); - pst2.executeUpdate(); - } - } - } - } - } + sqlExtension.saveAuth(auth, con); return true; } catch (SQLException ex) { logSqlException(ex); @@ -624,35 +370,7 @@ public class MySQL implements DataSource { pst.executeUpdate(); } } - if (hashAlgorithm == HashAlgorithm.XFBCRYPT) { - String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - // Insert password in the correct table - sql = "UPDATE " + xfPrefix + "user_authenticate SET data=? WHERE " + col.ID + "=?;"; - PreparedStatement pst2 = con.prepareStatement(sql); - String serializedHash = XfBCrypt.serializeHash(password.getHash()); - byte[] bytes = serializedHash.getBytes(); - Blob blob = con.createBlob(); - blob.setBytes(1, bytes); - pst2.setBlob(1, blob); - pst2.setInt(2, id); - pst2.executeUpdate(); - pst2.close(); - // ... - sql = "UPDATE " + xfPrefix + "user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;"; - pst2 = con.prepareStatement(sql); - pst2.setString(1, XfBCrypt.SCHEME_CLASS); - pst2.setInt(2, id); - pst2.executeUpdate(); - pst2.close(); - } - } - } - } + sqlExtension.changePassword(user, password, con); return true; } catch (SQLException ex) { logSqlException(ex); @@ -704,22 +422,7 @@ public class MySQL implements DataSource { user = user.toLowerCase(); String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - if (hashAlgorithm == HashAlgorithm.XFBCRYPT) { - sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement xfSelect = con.prepareStatement(sql)) { - xfSelect.setString(1, user); - try (ResultSet rs = xfSelect.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - sql = "DELETE FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;"; - try (PreparedStatement xfDelete = con.prepareStatement(sql)) { - xfDelete.setInt(1, id); - xfDelete.executeUpdate(); - } - } - } - } - } + sqlExtension.removeAuth(user, con); pst.setString(1, user.toLowerCase()); pst.executeUpdate(); return true; @@ -922,26 +625,12 @@ public class MySQL implements DataSource { @Override public List getAllAuths() { List auths = new ArrayList<>(); - try (Connection con = getConnection()) { - try (Statement st = con.createStatement()) { - try (ResultSet rs = st.executeQuery("SELECT * FROM " + tableName)) { - while (rs.next()) { - PlayerAuth pAuth = buildAuthFromResultSet(rs); - if (hashAlgorithm == HashAlgorithm.XFBCRYPT) { - try (PreparedStatement pst = con.prepareStatement("SELECT data FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;")) { - int id = rs.getInt(col.ID); - pst.setInt(1, id); - ResultSet rs2 = pst.executeQuery(); - if (rs2.next()) { - Blob blob = rs2.getBlob("data"); - byte[] bytes = blob.getBytes(1, (int) blob.length()); - pAuth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes))); - } - rs2.close(); - } - } - auths.add(pAuth); - } + try (Connection con = getConnection(); Statement st = con.createStatement()) { + try (ResultSet rs = st.executeQuery("SELECT * FROM " + tableName)) { + while (rs.next()) { + PlayerAuth auth = buildAuthFromResultSet(rs); + sqlExtension.extendAuth(auth, rs.getInt(col.ID), con); + auths.add(auth); } } } catch (SQLException ex) { @@ -987,36 +676,6 @@ public class MySQL implements DataSource { .build(); } - /** - * Closes a {@link ResultSet} safely. - * - * @param rs the result set to close - */ - private static void close(ResultSet rs) { - try { - if (rs != null && !rs.isClosed()) { - rs.close(); - } - } catch (SQLException e) { - ConsoleLogger.logException("Could not close ResultSet", e); - } - } - - /** - * Closes a {@link Statement} safely. - * - * @param st the statement set to close - */ - private static void close(Statement st) { - try { - if (st != null && !st.isClosed()) { - st.close(); - } - } catch (SQLException e) { - ConsoleLogger.logException("Could not close Statement", e); - } - } - /** * Checks if the last login column has a type that needs to be migrated. * diff --git a/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java b/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java index 7b793e8b..b1a485b9 100644 --- a/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java +++ b/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java @@ -3,6 +3,7 @@ package fr.xephi.authme.datasource.converter; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSourceType; import fr.xephi.authme.datasource.MySQL; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; import fr.xephi.authme.settings.Settings; import javax.inject.Inject; @@ -14,15 +15,17 @@ import java.sql.SQLException; public class MySqlToSqlite extends AbstractDataSourceConverter { private final Settings settings; + private final MySqlExtensionsFactory mySqlExtensionsFactory; @Inject - MySqlToSqlite(DataSource dataSource, Settings settings) { + MySqlToSqlite(DataSource dataSource, Settings settings, MySqlExtensionsFactory mySqlExtensionsFactory) { super(dataSource, DataSourceType.SQLITE); this.settings = settings; + this.mySqlExtensionsFactory = mySqlExtensionsFactory; } @Override - protected MySQL getSource() throws SQLException, ClassNotFoundException { - return new MySQL(settings); + protected MySQL getSource() throws SQLException { + return new MySQL(settings, mySqlExtensionsFactory); } } diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/Ipb4Extension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/Ipb4Extension.java new file mode 100644 index 00000000..0407d7d6 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/Ipb4Extension.java @@ -0,0 +1,68 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.Columns; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.HooksSettings; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Extension for IPB4. + */ +class Ipb4Extension extends MySqlExtension { + + private final Columns col; + private final String tableName; + private final String ipbPrefix; + private final int ipbGroup; + + Ipb4Extension(Settings settings, Columns col) { + this.col = col; + this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + this.ipbPrefix = settings.getProperty(HooksSettings.IPB_TABLE_PREFIX); + this.ipbGroup = settings.getProperty(HooksSettings.IPB_ACTIVATED_GROUP_ID); + } + + @Override + public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { + String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setString(1, auth.getNickname()); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + // Update player group in core_members + sql = "UPDATE " + ipbPrefix + tableName + + " SET " + tableName + ".member_group_id=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst2 = con.prepareStatement(sql)) { + pst2.setInt(1, ipbGroup); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + } + // Get current time without ms + long time = System.currentTimeMillis() / 1000; + // update joined date + sql = "UPDATE " + ipbPrefix + tableName + + " SET " + tableName + ".joined=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst2 = con.prepareStatement(sql)) { + pst2.setLong(1, time); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + } + // Update last_visit + sql = "UPDATE " + ipbPrefix + tableName + + " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst2 = con.prepareStatement(sql)) { + pst2.setLong(1, time); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + } + } + } + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtension.java new file mode 100644 index 00000000..8b5bf575 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtension.java @@ -0,0 +1,62 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.security.crypts.HashedPassword; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Extension for the MySQL data source for forums. For certain password hashes (e.g. phpBB), we want + * to hook into the forum board and execute some actions specific to the forum software. + */ +public abstract class MySqlExtension { + + /** + * Performs additional actions when a new player is saved. + * + * @param auth the player auth that has been saved + * @param con connection to the sql table + * @throws SQLException . + */ + public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { + // extend for custom behavior + } + + /** + * Writes properties to the given PlayerAuth object that need to be retrieved in a specific manner + * when a PlayerAuth object is read from the table. + * + * @param auth the player auth object to extend + * @param id the database id of the player auth entry + * @param con connection to the sql table + * @throws SQLException . + */ + public void extendAuth(PlayerAuth auth, int id, Connection con) throws SQLException { + // extend for custom behavior + } + + /** + * Performs additional actions when a user's password is changed. + * + * @param user the name of the player (lowercase) + * @param password the new password to set + * @param con connection to the sql table + * @throws SQLException . + */ + public void changePassword(String user, HashedPassword password, Connection con) throws SQLException { + // extend for custom behavior + } + + /** + * Performs additional actions when a player is removed from the database. + * + * @param user the user to remove + * @param con connection to the sql table + * @throws SQLException . + */ + public void removeAuth(String user, Connection con) throws SQLException { + // extend for custom behavior + } + +} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtensionsFactory.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtensionsFactory.java new file mode 100644 index 00000000..8974e2c1 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtensionsFactory.java @@ -0,0 +1,33 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +import fr.xephi.authme.datasource.Columns; +import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.SecuritySettings; + +import javax.inject.Inject; + +/** + * Creates the appropriate {@link MySqlExtension}, depending on the configured password hashing algorithm. + */ +public class MySqlExtensionsFactory { + + @Inject + private Settings settings; + + public MySqlExtension buildExtension(Columns columnsConfig) { + HashAlgorithm hash = settings.getProperty(SecuritySettings.PASSWORD_HASH); + switch (hash) { + case IPB4: + return new Ipb4Extension(settings, columnsConfig); + case PHPBB: + return new PhpBbExtension(settings, columnsConfig); + case WORDPRESS: + return new WordpressExtension(settings, columnsConfig); + case XFBCRYPT: + return new XfBcryptExtension(settings, columnsConfig); + default: + return new NoOpExtension(); + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/NoOpExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/NoOpExtension.java new file mode 100644 index 00000000..8146c6ce --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/NoOpExtension.java @@ -0,0 +1,7 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +/** + * Extension implementation that does not do anything. + */ +class NoOpExtension extends MySqlExtension { +} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/PhpBbExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/PhpBbExtension.java new file mode 100644 index 00000000..33a6a88f --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/PhpBbExtension.java @@ -0,0 +1,93 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.Columns; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.HooksSettings; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Extensions for phpBB when MySQL is used as data source. + */ +class PhpBbExtension extends MySqlExtension { + + private final Columns col; + private final String tableName; + private final String phpBbPrefix; + private final int phpBbGroup; + + PhpBbExtension(Settings settings, Columns col) { + this.col = col; + this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); + this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); + } + + @Override + public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { + String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setString(1, auth.getNickname()); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + int id = rs.getInt(col.ID); + updateSpecificsOnSave(id, auth.getNickname(), con); + } + } + } + } + + private void updateSpecificsOnSave(int id, String name, Connection con) throws SQLException { + // Insert player in phpbb_user_group + String sql = "INSERT INTO " + phpBbPrefix + + "user_group (group_id, user_id, group_leader, user_pending) VALUES (?,?,?,?);"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, phpBbGroup); + pst.setInt(2, id); + pst.setInt(3, 0); + pst.setInt(4, 0); + pst.executeUpdate(); + } + // Update username_clean in phpbb_users + sql = "UPDATE " + tableName + " SET " + tableName + ".username_clean=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setString(1, name); + pst.setString(2, name); + pst.executeUpdate(); + } + // Update player group in phpbb_users + sql = "UPDATE " + tableName + " SET " + tableName + ".group_id=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, phpBbGroup); + pst.setString(2, name); + pst.executeUpdate(); + } + // Get current time without ms + long time = System.currentTimeMillis() / 1000; + // Update user_regdate + sql = "UPDATE " + tableName + " SET " + tableName + ".user_regdate=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setLong(1, time); + pst.setString(2, name); + pst.executeUpdate(); + } + // Update user_lastvisit + sql = "UPDATE " + tableName + " SET " + tableName + ".user_lastvisit=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setLong(1, time); + pst.setString(2, name); + pst.executeUpdate(); + } + // Increment num_users + sql = "UPDATE " + phpBbPrefix + + "config SET config_value = config_value + 1 WHERE config_name = 'num_users';"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.executeUpdate(); + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/WordpressExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/WordpressExtension.java new file mode 100644 index 00000000..64e6a13f --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/WordpressExtension.java @@ -0,0 +1,107 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.Columns; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.HooksSettings; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * MySQL extensions for Wordpress. + */ +class WordpressExtension extends MySqlExtension { + + private final Columns col; + private final String tableName; + private final String wordpressPrefix; + + WordpressExtension(Settings settings, Columns col) { + this.col = col; + this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); + } + + @Override + public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { + try (PreparedStatement pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;")) { + pst.setString(1, auth.getNickname()); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + int id = rs.getInt(col.ID); + String sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?)"; + try (PreparedStatement pst2 = con.prepareStatement(sql)) { + // First Name + pst2.setInt(1, id); + pst2.setString(2, "first_name"); + pst2.setString(3, ""); + pst2.addBatch(); + // Last Name + pst2.setInt(1, id); + pst2.setString(2, "last_name"); + pst2.setString(3, ""); + pst2.addBatch(); + // Nick Name + pst2.setInt(1, id); + pst2.setString(2, "nickname"); + pst2.setString(3, auth.getNickname()); + pst2.addBatch(); + // Description + pst2.setInt(1, id); + pst2.setString(2, "description"); + pst2.setString(3, ""); + pst2.addBatch(); + // Rich_Editing + pst2.setInt(1, id); + pst2.setString(2, "rich_editing"); + pst2.setString(3, "true"); + pst2.addBatch(); + // Comments_Shortcuts + pst2.setInt(1, id); + pst2.setString(2, "comment_shortcuts"); + pst2.setString(3, "false"); + pst2.addBatch(); + // admin_color + pst2.setInt(1, id); + pst2.setString(2, "admin_color"); + pst2.setString(3, "fresh"); + pst2.addBatch(); + // use_ssl + pst2.setInt(1, id); + pst2.setString(2, "use_ssl"); + pst2.setString(3, "0"); + pst2.addBatch(); + // show_admin_bar_front + pst2.setInt(1, id); + pst2.setString(2, "show_admin_bar_front"); + pst2.setString(3, "true"); + pst2.addBatch(); + // wp_capabilities + pst2.setInt(1, id); + pst2.setString(2, wordpressPrefix + "capabilities"); + pst2.setString(3, "a:1:{s:10:\"subscriber\";b:1;}"); + pst2.addBatch(); + // wp_user_level + pst2.setInt(1, id); + pst2.setString(2, wordpressPrefix + "user_level"); + pst2.setString(3, "0"); + pst2.addBatch(); + // default_password_nag + pst2.setInt(1, id); + pst2.setString(2, "default_password_nag"); + pst2.setString(3, ""); + pst2.addBatch(); + + // Execute queries + pst2.executeBatch(); + pst2.clearBatch(); + } + } + } + } + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/XfBcryptExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/XfBcryptExtension.java new file mode 100644 index 00000000..de8ffb35 --- /dev/null +++ b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/XfBcryptExtension.java @@ -0,0 +1,160 @@ +package fr.xephi.authme.datasource.mysqlextensions; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.Columns; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.security.crypts.XfBCrypt; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.HooksSettings; + +import java.sql.Blob; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Extension for XFBCRYPT. + */ +class XfBcryptExtension extends MySqlExtension { + + private final Columns col; + private final String tableName; + private final String xfPrefix; + private final int xfGroup; + + XfBcryptExtension(Settings settings, Columns col) { + this.col = col; + this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + this.xfPrefix = settings.getProperty(HooksSettings.XF_TABLE_PREFIX); + this.xfGroup = settings.getProperty(HooksSettings.XF_ACTIVATED_GROUP_ID); + } + + @Override + public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { + String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setString(1, auth.getNickname()); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + int id = rs.getInt(col.ID); + updateXenforoTablesOnSave(auth, id, con); + } + } + } + } + + private void updateXenforoTablesOnSave(PlayerAuth auth, int id, Connection con) throws SQLException { + // Insert player password, salt in xf_user_authenticate + String sql = "INSERT INTO " + xfPrefix + "user_authenticate (user_id, scheme_class, data) VALUES (?,?,?)"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, id); + pst.setString(2, XfBCrypt.SCHEME_CLASS); + String serializedHash = XfBCrypt.serializeHash(auth.getPassword().getHash()); + byte[] bytes = serializedHash.getBytes(); + Blob blob = con.createBlob(); + blob.setBytes(1, bytes); + pst.setBlob(3, blob); + pst.executeUpdate(); + } + // Update player group in xf_users + sql = "UPDATE " + tableName + " SET " + tableName + ".user_group_id=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, xfGroup); + pst.setString(2, auth.getNickname()); + pst.executeUpdate(); + } + // Update player permission combination in xf_users + sql = "UPDATE " + tableName + " SET " + tableName + ".permission_combination_id=? WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, xfGroup); + pst.setString(2, auth.getNickname()); + pst.executeUpdate(); + } + // Insert player privacy combination in xf_user_privacy + sql = "INSERT INTO " + xfPrefix + "user_privacy (user_id, allow_view_profile, allow_post_profile, " + + "allow_send_personal_conversation, allow_view_identities, allow_receive_news_feed) VALUES (?,?,?,?,?,?)"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, id); + pst.setString(2, "everyone"); + pst.setString(3, "members"); + pst.setString(4, "members"); + pst.setString(5, "everyone"); + pst.setString(6, "everyone"); + pst.executeUpdate(); + } + // Insert player group relation in xf_user_group_relation + sql = "INSERT INTO " + xfPrefix + "user_group_relation (user_id, user_group_id, is_primary) VALUES (?,?,?)"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setInt(1, id); + pst.setInt(2, xfGroup); + pst.setString(3, "1"); + pst.executeUpdate(); + } + } + + public void extendAuth(PlayerAuth auth, int id, Connection con) throws SQLException { + try (PreparedStatement pst = con.prepareStatement( + "SELECT data FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;")) { + pst.setInt(1, id); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + Blob blob = rs.getBlob("data"); + byte[] bytes = blob.getBytes(1, (int) blob.length()); + auth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes))); + } + } + } + } + + @Override + public void changePassword(String user, HashedPassword password, Connection con) throws SQLException { + String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; + try (PreparedStatement pst = con.prepareStatement(sql)) { + pst.setString(1, user); + try (ResultSet rs = pst.executeQuery()) { + if (rs.next()) { + int id = rs.getInt(col.ID); + // Insert password in the correct table + // TODO #1255: Close these statements with try-catch + sql = "UPDATE " + xfPrefix + "user_authenticate SET data=? WHERE " + col.ID + "=?;"; + PreparedStatement pst2 = con.prepareStatement(sql); + String serializedHash = XfBCrypt.serializeHash(password.getHash()); + byte[] bytes = serializedHash.getBytes(); + Blob blob = con.createBlob(); + blob.setBytes(1, bytes); + pst2.setBlob(1, blob); + pst2.setInt(2, id); + pst2.executeUpdate(); + pst2.close(); + // ... + sql = "UPDATE " + xfPrefix + "user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;"; + pst2 = con.prepareStatement(sql); + pst2.setString(1, XfBCrypt.SCHEME_CLASS); + pst2.setInt(2, id); + pst2.executeUpdate(); + pst2.close(); + } + } + } + } + + @Override + public void removeAuth(String user, Connection con) throws SQLException { + String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; + try (PreparedStatement xfSelect = con.prepareStatement(sql)) { + xfSelect.setString(1, user); + try (ResultSet rs = xfSelect.executeQuery()) { + if (rs.next()) { + int id = rs.getInt(col.ID); + sql = "DELETE FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;"; + try (PreparedStatement xfDelete = con.prepareStatement(sql)) { + xfDelete.setInt(1, id); + xfDelete.executeUpdate(); + } + } + } + } + } +} diff --git a/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java b/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java index 594cabf4..4f5d3d4d 100644 --- a/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java +++ b/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java @@ -9,6 +9,7 @@ import fr.xephi.authme.datasource.FlatFile; import fr.xephi.authme.datasource.MySQL; import fr.xephi.authme.datasource.SQLite; import fr.xephi.authme.datasource.converter.ForceFlatToSqlite; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; @@ -36,6 +37,8 @@ public class DataSourceProvider implements Provider { private BukkitService bukkitService; @Inject private PlayerCache playerCache; + @Inject + private MySqlExtensionsFactory mySqlExtensionsFactory; DataSourceProvider() { } @@ -67,7 +70,7 @@ public class DataSourceProvider implements Provider { dataSource = new FlatFile(source); break; case MYSQL: - dataSource = new MySQL(settings); + dataSource = new MySQL(settings, mySqlExtensionsFactory); break; case SQLITE: dataSource = new SQLite(settings); @@ -82,12 +85,12 @@ public class DataSourceProvider implements Provider { dataSource = new CacheDataSource(dataSource, playerCache); } if (DataSourceType.SQLITE.equals(dataSourceType)) { - checkDataSourceSize(dataSource, bukkitService); + checkDataSourceSize(dataSource); } return dataSource; } - private void checkDataSourceSize(final DataSource dataSource, BukkitService bukkitService) { + private void checkDataSourceSize(DataSource dataSource) { bukkitService.runTaskAsynchronously(() -> { int accounts = dataSource.getAccountsRegistered(); if (accounts >= SQLITE_MAX_SIZE) { diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java index 1da098e1..845923b9 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractResourceClosingTest.java @@ -1,16 +1,13 @@ package fr.xephi.authme.datasource; import ch.jalu.configme.properties.Property; -import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import fr.xephi.authme.TestHelper; import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -19,7 +16,6 @@ import org.junit.runners.Parameterized; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; @@ -64,13 +60,6 @@ public abstract class AbstractResourceClosingTest { /** Collection of values to use to call methods with the parameters they expect. */ private static final Map, Object> PARAM_VALUES = getDefaultParameters(); - /** - * Custom list of hash algorithms to use to test a method. By default we define {@link HashAlgorithm#XFBCRYPT} as - * algorithms we use as a lot of methods execute additional statements in {@link MySQL}. If other algorithms - * have custom behaviors, they can be supplied in this map so it will be tested as well. - */ - private static final Map CUSTOM_ALGORITHMS = getCustomAlgorithmList(); - /** Mock of a settings instance. */ private static Settings settings; @@ -84,23 +73,21 @@ public abstract class AbstractResourceClosingTest { private List closeables = new ArrayList<>(); /** - * Constructor for the test instance verifying the given method with the given hash algorithm. + * Constructor for the test instance verifying the given method. * * @param method The DataSource method to test * @param name The name of the method - * @param algorithm The hash algorithm to use */ - public AbstractResourceClosingTest(Method method, String name, HashAlgorithm algorithm) { + public AbstractResourceClosingTest(Method method, String name) { // Note ljacqu 20160227: The name parameter is necessary as we pass it from the @Parameters method; // we use the method name in the annotation to name the test sensibly this.method = method; - given(settings.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(algorithm); } /** Initialize the settings mock and makes it return the default of any given property by default. */ - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings("unchecked") @BeforeClass - public static void initializeSettings() throws IOException, ClassNotFoundException { + public static void initializeSettings() { settings = mock(Settings.class); given(settings.getProperty(any(Property.class))).willAnswer(new Answer() { @Override @@ -129,24 +116,16 @@ public abstract class AbstractResourceClosingTest { } /** - * Initialization method -- provides the parameters to run the test with by scanning all DataSource - * methods. By default, we run one test per method with the default hash algorithm, XFBCRYPT. - * If the map of custom algorithms has an entry for the method name, we add an entry for each algorithm - * supplied by the map. + * Initialization method -- provides the parameters to run the test with by scanning all DataSource methods. * * @return Test parameters */ - @Parameterized.Parameters(name = "{1}({2})") + @Parameterized.Parameters(name = "{1}") public static Collection data() { List methods = getDataSourceMethods(); List data = new ArrayList<>(); - // Use XFBCRYPT if nothing else specified as there is a lot of specific behavior to this hash algorithm in MySQL - final HashAlgorithm[] defaultAlgorithm = new HashAlgorithm[]{HashAlgorithm.XFBCRYPT}; for (Method method : methods) { - HashAlgorithm[] algorithms = MoreObjects.firstNonNull(CUSTOM_ALGORITHMS.get(method.getName()), defaultAlgorithm); - for (HashAlgorithm algorithm : algorithms) { - data.add(new Object[]{method, method.getName(), algorithm}); - } + data.add(new Object[]{method, method.getName()}); } return data; } @@ -247,20 +226,6 @@ public abstract class AbstractResourceClosingTest { .build(); } - /** - * Return the custom list of hash algorithms to test a method with to execute code specific to - * one hash algorithm. By default, XFBCRYPT is used. Only MySQL has code specific to algorithms - * but for technical reasons the custom list will be used for all tested classes. - * - * @return List of custom algorithms by method - */ - private static Map getCustomAlgorithmList() { - // We use XFBCRYPT as default encryption method so we don't have to list many of the special cases for it - return ImmutableMap.builder() - .put("saveAuth", new HashAlgorithm[]{HashAlgorithm.PHPBB, HashAlgorithm.WORDPRESS}) - .build(); - } - // --------------------- // Mock initialization // --------------------- diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index 1ec75312..62e1ac3e 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -4,6 +4,8 @@ import ch.jalu.configme.properties.Property; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import fr.xephi.authme.TestHelper; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; import org.junit.After; @@ -30,6 +32,8 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { /** Mock of a settings instance. */ private static Settings settings; + /** Mock of extensions factory. */ + private static MySqlExtensionsFactory extensionsFactory; /** SQL statement to execute before running a test. */ private static String sqlInitialize; /** Connection to the H2 test database. */ @@ -51,6 +55,8 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { return ((Property) invocation.getArguments()[0]).getDefaultValue(); } }); + extensionsFactory = mock(MySqlExtensionsFactory.class); + when(extensionsFactory.buildExtension(any(Columns.class))).thenReturn(mock(MySqlExtension.class)); set(DatabaseSettings.MYSQL_DATABASE, "h2_test"); set(DatabaseSettings.MYSQL_TABLE, "authme"); TestHelper.setRealLogger(); @@ -85,7 +91,7 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { @Override protected DataSource getDataSource(String saltColumn) { when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn); - return new MySQL(settings, hikariSource); + return new MySQL(settings, hikariSource, extensionsFactory); } private static void set(Property property, T value) { diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlResourceClosingTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlResourceClosingTest.java index 7dccb08b..f41a2164 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlResourceClosingTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlResourceClosingTest.java @@ -1,12 +1,14 @@ package fr.xephi.authme.datasource; import com.zaxxer.hikari.HikariDataSource; -import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; +import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; import fr.xephi.authme.settings.Settings; import java.lang.reflect.Method; import java.sql.Connection; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -15,15 +17,17 @@ import static org.mockito.Mockito.mock; */ public class MySqlResourceClosingTest extends AbstractResourceClosingTest { - public MySqlResourceClosingTest(Method method, String name, HashAlgorithm algorithm) { - super(method, name, algorithm); + public MySqlResourceClosingTest(Method method, String name) { + super(method, name); } @Override protected DataSource createDataSource(Settings settings, Connection connection) throws Exception { HikariDataSource hikariDataSource = mock(HikariDataSource.class); given(hikariDataSource.getConnection()).willReturn(connection); - return new MySQL(settings, hikariDataSource); + MySqlExtensionsFactory extensionsFactory = mock(MySqlExtensionsFactory.class); + given(extensionsFactory.buildExtension(any(Columns.class))).willReturn(mock(MySqlExtension.class)); + return new MySQL(settings, hikariDataSource, extensionsFactory); } } diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteResourceClosingTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteResourceClosingTest.java index 9eac9463..69eade8f 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteResourceClosingTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteResourceClosingTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.datasource; -import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.settings.Settings; import java.lang.reflect.Method; @@ -11,8 +10,8 @@ import java.sql.Connection; */ public class SQLiteResourceClosingTest extends AbstractResourceClosingTest { - public SQLiteResourceClosingTest(Method method, String name, HashAlgorithm algorithm) { - super(method, name, algorithm); + public SQLiteResourceClosingTest(Method method, String name) { + super(method, name); } @Override