From 374113ff0139ca7a526c7ece10b8a4551fea94f0 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 20 Feb 2016 07:25:14 +0100 Subject: [PATCH 1/4] #534 Send error if name is restricted --- .../fr/xephi/authme/datasource/DataSource.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 43693313..4009586c 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -14,7 +14,6 @@ public interface DataSource { * Return whether there is a record for the given username. * * @param user The username to look up - * * @return True if there is a record, false otherwise */ boolean isAuthAvailable(String user); @@ -23,7 +22,6 @@ public interface DataSource { * Return the hashed password of the player. * * @param user The user whose password should be retrieve - * * @return The password hash of the player */ HashedPassword getPassword(String user); @@ -32,7 +30,6 @@ public interface DataSource { * Retrieve the entire PlayerAuth object associated with the username. * * @param user The user to retrieve - * * @return The PlayerAuth object for the given username */ PlayerAuth getAuth(String user); @@ -41,7 +38,6 @@ public interface DataSource { * Save a new PlayerAuth object. * * @param auth The new PlayerAuth to persist - * * @return True upon success, false upon failure */ boolean saveAuth(PlayerAuth auth); @@ -50,7 +46,6 @@ public interface DataSource { * Update the session of a record (IP, last login, real name). * * @param auth The PlayerAuth object to update in the database - * * @return True upon success, false upon failure */ boolean updateSession(PlayerAuth auth); @@ -59,7 +54,6 @@ public interface DataSource { * Update the password of the given PlayerAuth object. * * @param auth The PlayerAuth whose password should be updated - * * @return True upon success, false upon failure */ boolean updatePassword(PlayerAuth auth); @@ -67,9 +61,8 @@ public interface DataSource { /** * Update the password of the given player. * - * @param user The user whose password should be updated + * @param user The user whose password should be updated * @param password The new password - * * @return True upon success, false upon failure */ boolean updatePassword(String user, HashedPassword password); @@ -79,7 +72,6 @@ public interface DataSource { * the given time. * * @param until The minimum last login - * * @return The account names that have been removed */ List autoPurgeDatabase(long until); @@ -88,7 +80,6 @@ public interface DataSource { * Remove a user record from the database. * * @param user The user to remove - * * @return True upon success, false upon failure */ boolean removeAuth(String user); @@ -97,7 +88,6 @@ public interface DataSource { * Update the quit location of a PlayerAuth. * * @param auth The entry whose quit location should be updated - * * @return True upon success, false upon failure */ boolean updateQuitLoc(PlayerAuth auth); @@ -106,7 +96,6 @@ public interface DataSource { * Return all usernames associated with the given IP address. * * @param ip The IP address to look up - * * @return Usernames associated with the given IP address */ List getAllAuthsByIp(String ip); @@ -115,7 +104,6 @@ public interface DataSource { * Return all usernames associated with the given email address. * * @param email The email address to look up - * * @return Users using the given email address */ List getAllAuthsByEmail(String email); @@ -124,7 +112,6 @@ public interface DataSource { * Update the email of the PlayerAuth in the data source. * * @param auth The PlayerAuth whose email should be updated - * * @return True upon success, false upon failure */ boolean updateEmail(PlayerAuth auth); From 614d544edffa0a6f1811490c7fee1f19ef4716e8 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 20 Feb 2016 07:26:58 +0100 Subject: [PATCH 2/4] #534 Send error if name is restricted (this time for real) --- .../java/fr/xephi/authme/process/join/AsynchronousJoin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java index db678ad1..f738268e 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -64,15 +64,16 @@ public class AsynchronousJoin { final String ip = plugin.getIP(player); - if (Settings.isAllowRestrictedIp && !isNameRestricted(name, ip, player.getAddress().getHostName())) { + if (Settings.isAllowRestrictedIp && isNameRestricted(name, ip, player.getAddress().getHostName())) { sched.scheduleSyncDelayedTask(plugin, new Runnable() { @Override public void run() { AuthMePlayerListener.causeByAuthMe.putIfAbsent(name, true); player.kickPlayer(m.retrieveSingle(MessageKey.NOT_OWNER_ERROR)); - if (Settings.banUnsafeIp) + if (Settings.banUnsafeIp) { plugin.getServer().banIP(ip); + } } }); return; From fd8991507159968bcbff884e2bc1f9cf19916776 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 20 Feb 2016 08:23:02 +0100 Subject: [PATCH 3/4] #517 Display welcome message for all logins --- .../process/login/ProcessSyncPlayerLogin.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 21bb427b..0c120b52 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -2,6 +2,8 @@ package fr.xephi.authme.process.login; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.HooksSettings; +import fr.xephi.authme.settings.properties.RegistrationSettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -92,7 +94,7 @@ public class ProcessSyncPlayerLogin implements Runnable { } private void restoreSpeedEffects() { - if (Settings.isRemoveSpeedEnabled) { + if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) { player.setWalkSpeed(0.2F); player.setFlySpeed(0.1F); } @@ -173,19 +175,19 @@ public class ProcessSyncPlayerLogin implements Runnable { } restoreSpeedEffects(); - if (Settings.applyBlindEffect) { + if (settings.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { player.removePotionEffect(PotionEffectType.BLINDNESS); } // The Login event now fires (as intended) after everything is processed Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player)); player.saveData(); - if (Settings.bungee) { + if (settings.getProperty(HooksSettings.BUNGEECORD)) { sendBungeeMessage(); } - // Login is finish, display welcome message if we use email registration - if (Settings.useWelcomeMessage && Settings.emailRegistration) { - if (Settings.broadcastWelcomeMessage) { + // Login is done, display welcome message + if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { + if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { for (String s : settings.getWelcomeMessage()) { Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); } From 8511a257edc610d126260d828af263683bd67164 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 20 Feb 2016 11:13:13 +0100 Subject: [PATCH 4/4] #494 Fix conversion plaintext to SHA256 - Make sure database is set up before attempting to perform the migration --- src/main/java/fr/xephi/authme/AuthMe.java | 95 ++++++++----------- .../executable/authme/ReloadCommand.java | 5 +- .../authme/datasource/DataSourceType.java | 1 + .../process/login/AsynchronousLogin.java | 2 +- .../authme/security/PasswordSecurity.java | 2 +- .../security/crypts/HexSaltedMethod.java | 2 +- .../settings/properties/BackupSettings.java | 2 +- .../xephi/authme/util/MigrationService.java | 72 ++++++++++++++ 8 files changed, 122 insertions(+), 59 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/util/MigrationService.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index f2595f37..56580cf9 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -17,7 +17,6 @@ import fr.xephi.authme.command.CommandInitializer; import fr.xephi.authme.command.CommandMapper; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.converter.ForceFlatToSqlite; import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSourceType; @@ -43,9 +42,8 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Management; -import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; @@ -58,9 +56,9 @@ import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.GeoLiteAPI; +import fr.xephi.authme.util.MigrationService; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; -import fr.xephi.authme.util.Wrapper; import net.minelink.ctplus.CombatTagPlus; import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; @@ -77,6 +75,7 @@ import org.bukkit.scheduler.BukkitTask; import java.io.File; import java.io.IOException; import java.net.URL; +import java.sql.SQLException; import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -105,7 +104,6 @@ public class AuthMe extends JavaPlugin { // Private Instances private static AuthMe plugin; private static Server server; - private static Wrapper wrapper = Wrapper.getInstance(); private Management management; private CommandHandler commandHandler = null; private PermissionsManager permsMan = null; @@ -117,9 +115,8 @@ public class AuthMe extends JavaPlugin { /* * Public Instances - * TODO: Encapsulation + * TODO #432: Encapsulation */ - public NewAPI api; public SendMailSSL mail; public DataManager dataManager; @@ -246,7 +243,7 @@ public class AuthMe extends JavaPlugin { // Connect to the database and setup tables try { - setupDatabase(); + setupDatabase(newSettings); } catch (Exception e) { ConsoleLogger.logException("Fatal error occurred during database connection! " + "Authme initialization aborted!", e); @@ -254,6 +251,7 @@ public class AuthMe extends JavaPlugin { return; } + MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); passwordSecurity = new PasswordSecurity(getDataSource(), newSettings.getProperty(SecuritySettings.PASSWORD_HASH), Bukkit.getPluginManager(), newSettings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH)); @@ -516,25 +514,42 @@ public class AuthMe extends JavaPlugin { } } - public void setupDatabase() throws Exception { - if (database != null) - database.close(); - // Backend MYSQL - FILE - SQLITE - SQLITEHIKARI - boolean isSQLite = false; - switch (newSettings.getProperty(DatabaseSettings.BACKEND)) { - case FILE: - database = new FlatFile(); - break; - case MYSQL: - database = new MySQL(newSettings); - break; - case SQLITE: - database = new SQLite(newSettings); - isSQLite = true; - break; + /** + * Sets up the data source. + * + * @param settings The settings instance + * @see AuthMe#database + */ + public void setupDatabase(NewSetting settings) throws ClassNotFoundException, SQLException { + if (this.database != null) { + this.database.close(); } - if (isSQLite) { + DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND); + DataSource dataSource; + switch (dataSourceType) { + case FILE: + dataSource = new FlatFile(); + break; + case MYSQL: + dataSource = new MySQL(settings); + break; + case SQLITE: + dataSource = new SQLite(settings); + break; + default: + throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'"); + } + + DataSource convertedSource = MigrationService.convertFlatfileToSqlite(newSettings, dataSource); + dataSource = convertedSource == null ? dataSource : convertedSource; + + if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) { + dataSource = new CacheDataSource(dataSource); + } + + database = dataSource; + if (DataSourceType.SQLITE == dataSourceType) { server.getScheduler().runTaskAsynchronously(this, new Runnable() { @Override public void run() { @@ -546,34 +561,6 @@ public class AuthMe extends JavaPlugin { } }); } - - if (Settings.getDataSource == DataSourceType.FILE) { - ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, it will be changed " + - "to SQLite... Connection will be impossible until conversion is done!"); - ForceFlatToSqlite converter = new ForceFlatToSqlite(database, newSettings); - DataSource source = converter.run(); - if (source != null) { - database = source; - } - } - - // TODO: Move this to another place maybe ? - if (HashAlgorithm.PLAINTEXT == newSettings.getProperty(SecuritySettings.PASSWORD_HASH)) { - ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " + - "it will be changed and hashed now to the AuthMe default hashing method"); - for (PlayerAuth auth : database.getAllAuths()) { - HashedPassword hashedPassword = passwordSecurity.computeHash( - HashAlgorithm.SHA256, auth.getPassword().getHash(), auth.getNickname()); - auth.setPassword(hashedPassword); - database.updatePassword(auth); - } - newSettings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); - newSettings.save(); - } - - if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) { - database = new CacheDataSource(database); - } } /** @@ -910,7 +897,7 @@ public class AuthMe extends JavaPlugin { String commandLabel, String[] args) { // Make sure the command handler has been initialized if (commandHandler == null) { - wrapper.getLogger().severe("AuthMe command handler is not available"); + getLogger().severe("AuthMe command handler is not available"); return false; } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java index 39acd6a1..3dce54e1 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java @@ -20,7 +20,10 @@ public class ReloadCommand implements ExecutableCommand { try { commandService.getSettings().reload(); commandService.reloadMessages(commandService.getSettings().getMessagesFile()); - plugin.setupDatabase(); + // TODO #432: We should not reload only certain plugin entities but actually reinitialize all elements, + // i.e. here in the future we might not have setupDatabase() but Authme.onEnable(), maybe after + // a call to some destructor method + plugin.setupDatabase(commandService.getSettings()); commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); } catch (Exception e) { sender.sendMessage("Error occurred during reload of AuthMe: aborting"); diff --git a/src/main/java/fr/xephi/authme/datasource/DataSourceType.java b/src/main/java/fr/xephi/authme/datasource/DataSourceType.java index edb72ac8..133b492f 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSourceType.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSourceType.java @@ -7,6 +7,7 @@ public enum DataSourceType { MYSQL, + @Deprecated FILE, SQLITE diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 5a4cf425..09647dff 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -220,7 +220,7 @@ public class AsynchronousLogin { } } - public void displayOtherAccounts(PlayerAuth auth) { + private void displayOtherAccounts(PlayerAuth auth) { if (!Settings.displayOtherAccounts || auth == null) { return; } diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 298d56be..1a8278e1 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -113,7 +113,7 @@ public class PasswordSecurity { */ private static EncryptionMethod initializeEncryptionMethodWithoutEvent(HashAlgorithm algorithm) { try { - return HashAlgorithm.CUSTOM.equals(algorithm) + return HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm) ? null : algorithm.getClazz().newInstance(); } catch (InstantiationException | IllegalAccessException e) { diff --git a/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java b/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java index 76441b1b..9f76dbbb 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java @@ -11,7 +11,7 @@ import fr.xephi.authme.security.crypts.description.Usage; * and store the salt with the hash itself. */ @Recommendation(Usage.ACCEPTABLE) -@HasSalt(SaltType.TEXT) // See saltLength() for length +@HasSalt(SaltType.TEXT) // See getSaltLength() for length public abstract class HexSaltedMethod implements EncryptionMethod { public abstract int getSaltLength(); diff --git a/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java b/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java index 32c439db..9c6a7866 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java @@ -20,7 +20,7 @@ public class BackupSettings implements SettingsClass { public static final Property ON_SERVER_STOP = newProperty("BackupSystem.OnServerStop", true); - @Comment(" Windows only mysql installation Path") + @Comment("Windows only mysql installation Path") public static final Property MYSQL_WINDOWS_PATH = newProperty("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\"); diff --git a/src/main/java/fr/xephi/authme/util/MigrationService.java b/src/main/java/fr/xephi/authme/util/MigrationService.java new file mode 100644 index 00000000..6da4d95e --- /dev/null +++ b/src/main/java/fr/xephi/authme/util/MigrationService.java @@ -0,0 +1,72 @@ +package fr.xephi.authme.util; + +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.converter.ForceFlatToSqlite; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.datasource.DataSourceType; +import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.security.crypts.SHA256; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; + +import java.util.List; + +/** + * Migrations to perform during the initialization of AuthMe. + */ +public final class MigrationService { + + private MigrationService() { + } + + /** + * Hash all passwords to SHA256 and updated the setting if the password hash is set to the deprecated PLAINTEXT. + * + * @param settings The settings instance + * @param dataSource The data source + * @param authmeSha256 Instance to the AuthMe SHA256 encryption method implementation + */ + public static void changePlainTextToSha256(NewSetting settings, DataSource dataSource, + SHA256 authmeSha256) { + if (HashAlgorithm.PLAINTEXT == settings.getProperty(SecuritySettings.PASSWORD_HASH)) { + ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated;" + + " it will be changed and hashed now to the AuthMe default hashing method"); + List allAuths = dataSource.getAllAuths(); + for (PlayerAuth auth : allAuths) { + HashedPassword hashedPassword = authmeSha256.computeHash( + auth.getPassword().getHash(), auth.getNickname()); + auth.setPassword(hashedPassword); + dataSource.updatePassword(auth); + } + settings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); + settings.save(); + ConsoleLogger.info("Migrated " + allAuths.size() + " accounts from plaintext to SHA256"); + } + } + + /** + * Converts the data source from the deprecated FLATFILE type to SQLITE. + * + * @param settings The settings instance + * @param dataSource The data source + * @return The converted datasource (SQLite), or null if no migration was necessary + */ + public static DataSource convertFlatfileToSqlite(NewSetting settings, DataSource dataSource) { + if (DataSourceType.FILE == settings.getProperty(DatabaseSettings.BACKEND)) { + ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated; it will be changed " + + "to SQLite... Connection will be impossible until conversion is done!"); + ForceFlatToSqlite converter = new ForceFlatToSqlite(dataSource, settings); + DataSource result = converter.run(); + if (result == null) { + throw new IllegalStateException("Error during conversion from flatfile to SQLite"); + } else { + return result; + } + } + return null; + } + +}