#358 Replace usage of static PasswordSecurity methods

- Replace static methods to instance methods
- Use PlayerAuth builder instead of constructor
This commit is contained in:
ljacqu 2015-12-29 00:13:20 +01:00
parent 1c12278c4b
commit b3b751920a
13 changed files with 314 additions and 371 deletions

View File

@ -42,6 +42,7 @@ import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.OtherAccounts;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.settings.Spawn;
@ -100,6 +101,7 @@ public class AuthMe extends JavaPlugin {
private Messages messages; private Messages messages;
private JsonCache playerBackup; private JsonCache playerBackup;
private ModuleManager moduleManager; private ModuleManager moduleManager;
private PasswordSecurity passwordSecurity;
// Public Instances // Public Instances
public NewAPI api; public NewAPI api;
@ -206,12 +208,24 @@ public class AuthMe extends JavaPlugin {
return; return;
} }
// Set up messages // Set up messages & password security
messages = Messages.getInstance(); messages = Messages.getInstance();
passwordSecurity = new PasswordSecurity(getDataSource(), Settings.getPasswordHash, Settings.supportOldPassword);
// Connect to the database and setup tables
try {
setupDatabase();
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError(e.getMessage());
ConsoleLogger.showError("Fatal error occurred during database connection! Authme initialization ABORTED!");
stopOrUnload();
return;
}
// Set up the permissions manager and command handler // Set up the permissions manager and command handler
permsMan = initializePermissionsManager(); permsMan = initializePermissionsManager();
commandHandler = initializeCommandHandler(permsMan, messages); commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity);
// Set up the module manager // Set up the module manager
setupModuleManager(); setupModuleManager();
@ -253,16 +267,7 @@ public class AuthMe extends JavaPlugin {
// Do a backup on start // Do a backup on start
new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.START); new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.START);
// Connect to the database and setup tables
try {
setupDatabase();
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError(e.getMessage());
ConsoleLogger.showError("Fatal error occurred during database connection! Authme initialization ABORTED!");
stopOrUnload();
return;
}
// Setup the inventory backup // Setup the inventory backup
playerBackup = new JsonCache(); playerBackup = new JsonCache();
@ -409,11 +414,12 @@ public class AuthMe extends JavaPlugin {
} }
} }
private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages) { private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages,
PasswordSecurity passwordSecurity) {
HelpProvider helpProvider = new HelpProvider(permissionsManager); HelpProvider helpProvider = new HelpProvider(permissionsManager);
Set<CommandDescription> baseCommands = CommandInitializer.buildCommands(); Set<CommandDescription> baseCommands = CommandInitializer.buildCommands();
CommandMapper mapper = new CommandMapper(baseCommands, messages, permissionsManager, helpProvider); CommandMapper mapper = new CommandMapper(baseCommands, messages, permissionsManager, helpProvider);
CommandService commandService = new CommandService(this, mapper, helpProvider, messages); CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity);
return new CommandHandler(commandService); return new CommandHandler(commandService);
} }
@ -563,14 +569,15 @@ public class AuthMe extends JavaPlugin {
int accounts = database.getAccountsRegistered(); int accounts = database.getAccountsRegistered();
if (accounts >= 4000) { if (accounts >= 4000) {
ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH " ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH "
+ accounts + "+ ACCOUNTS, FOR BETTER PERFORMANCES, PLEASE UPGRADE TO MYSQL!!"); + accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!");
} }
} }
}); });
} }
if (Settings.getDataSource == DataSource.DataSourceType.FILE) { if (Settings.getDataSource == DataSource.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!"); 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); ForceFlatToSqlite converter = new ForceFlatToSqlite(database);
DataSource source = converter.run(); DataSource source = converter.run();
if (source != null) { if (source != null) {
@ -579,12 +586,12 @@ public class AuthMe extends JavaPlugin {
} }
// TODO: Move this to another place maybe ? // TODO: Move this to another place maybe ?
if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT) if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT) {
{ ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " +
ConsoleLogger.showError("Your HashAlgorithm has been detected has plaintext and is now deprecrated, it will be changed and hashed now to AuthMe default hashing method"); "it will be changed and hashed now to the AuthMe default hashing method");
for (PlayerAuth auth : database.getAllAuths()) for (PlayerAuth auth : database.getAllAuths()) {
{ HashResult hashResult = passwordSecurity.computeHash(HashAlgorithm.SHA256, auth.getHash(), auth.getNickname());
auth.setHash(PasswordSecurity.getHash(HashAlgorithm.SHA256, auth.getHash(), auth.getNickname())); auth.setHash(hashResult.getHash());
database.updatePassword(auth); database.updatePassword(auth);
} }
Settings.setValue("settings.security.passwordHash", "SHA256"); Settings.setValue("settings.security.passwordHash", "SHA256");
@ -973,4 +980,8 @@ public class AuthMe extends JavaPlugin {
return database; return database;
} }
public PasswordSecurity getPasswordSecurity() {
return passwordSecurity;
}
} }

View File

@ -3,8 +3,7 @@ package fr.xephi.authme.api;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -12,9 +11,8 @@ import org.bukkit.Server;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.security.NoSuchAlgorithmException;
/** /**
* The current API of AuthMe.
*/ */
public class NewAPI { public class NewAPI {
@ -42,33 +40,36 @@ public class NewAPI {
/** /**
* Hook into AuthMe * Hook into AuthMe
* *
* @return AuthMe plugin * @return The API object
*/ */
public static NewAPI getInstance() { public static NewAPI getInstance() {
if (singleton != null) if (singleton != null) {
return singleton; return singleton;
}
Plugin p = Bukkit.getServer().getPluginManager().getPlugin("AuthMe"); Plugin p = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
if (p == null || !(p instanceof AuthMe)) { if (p == null || !(p instanceof AuthMe)) {
return null; return null;
} }
AuthMe authme = (AuthMe) p; AuthMe authme = (AuthMe) p;
singleton = (new NewAPI(authme)); singleton = new NewAPI(authme);
return singleton; return singleton;
} }
/** /**
* Method getPlugin. * Return the plugin instance.
* *
* @return AuthMe * @return The AuthMe instance
*/ */
public AuthMe getPlugin() { public AuthMe getPlugin() {
return plugin; return plugin;
} }
/** /**
* @param player * Return whether the given player is authenticated.
* *
* @return true if player is authenticate * @param player The player to verify
*
* @return true if the player is authenticated
*/ */
public boolean isAuthenticated(Player player) { public boolean isAuthenticated(Player player) {
return PlayerCache.getInstance().isAuthenticated(player.getName()); return PlayerCache.getInstance().isAuthenticated(player.getName());
@ -93,15 +94,15 @@ public class NewAPI {
} }
/** /**
* Method getLastLocation. * Get the last location of a player.
* *
* @param player Player * @param player Player The player to process
* *
* @return Location * @return Location The location of the player
*/ */
public Location getLastLocation(Player player) { public Location getLastLocation(Player player) {
try { try {
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase()); PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName());
if (auth != null) { if (auth != null) {
return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ()); return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
@ -121,81 +122,81 @@ public class NewAPI {
*/ */
public boolean isRegistered(String playerName) { public boolean isRegistered(String playerName) {
String player = playerName.toLowerCase(); String player = playerName.toLowerCase();
return plugin.database.isAuthAvailable(player); return plugin.getDataSource().isAuthAvailable(player);
} }
/** /**
* @param playerName String * Check the password for the given player.
* @param passwordToCheck String
* *
* @return true if the password is correct , false else * @param playerName The player to check the password for
* @param passwordToCheck The password to check
*
* @return true if the password is correct, false otherwise
*/ */
public boolean checkPassword(String playerName, String passwordToCheck) { public boolean checkPassword(String playerName, String passwordToCheck) {
if (!isRegistered(playerName)) if (!isRegistered(playerName)) {
return false;
String player = playerName.toLowerCase();
PlayerAuth auth = plugin.database.getAuth(player);
try {
return PasswordSecurity.comparePasswordWithHash(passwordToCheck, auth.getHash(), playerName);
} catch (NoSuchAlgorithmException e) {
return false; return false;
} }
String player = playerName.toLowerCase();
PlayerAuth auth = plugin.getDataSource().getAuth(player);
return plugin.getPasswordSecurity().comparePassword(passwordToCheck, auth.getHash(), playerName);
} }
/** /**
* Register a player * Register a player.
* *
* @param playerName String * @param playerName The player to register
* @param password String * @param password The password to register the player with
* *
* @return true if the player is register correctly * @return true if the player was registered successfully
*/ */
public boolean registerPlayer(String playerName, String password) { public boolean registerPlayer(String playerName, String password) {
try { String name = playerName.toLowerCase();
String name = playerName.toLowerCase(); HashResult result = plugin.getPasswordSecurity().computeHash(password, name);
String hash = PasswordSecurity.getHash(Settings.getPasswordHash, password, name); if (isRegistered(name)) {
if (isRegistered(name)) {
return false;
}
PlayerAuth auth = new PlayerAuth(name, hash, "192.168.0.1", 0, "your@email.com", playerName);
return plugin.database.saveAuth(auth);
} catch (NoSuchAlgorithmException ex) {
return false; return false;
} }
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.hash(result.getHash())
.salt(result.getSalt())
.realName(playerName)
.build();
return plugin.getDataSource().saveAuth(auth);
} }
/** /**
* Force a player to login * Force a player to login.
* *
* @param player * player * @param player The player to log in
*/ */
public void forceLogin(Player player) { public void forceLogin(Player player) {
plugin.getManagement().performLogin(player, "dontneed", true); plugin.getManagement().performLogin(player, "dontneed", true);
} }
/** /**
* Force a player to logout * Force a player to logout.
* *
* @param player * player * @param player The player to log out
*/ */
public void forceLogout(Player player) { public void forceLogout(Player player) {
plugin.getManagement().performLogout(player); plugin.getManagement().performLogout(player);
} }
/** /**
* Force a player to register * Force a player to register.
* *
* @param player * player * @param player The player to register
* @param password String * @param password The password to use
*/ */
public void forceRegister(Player player, String password) { public void forceRegister(Player player, String password) {
plugin.getManagement().performRegister(player, password, null); plugin.getManagement().performRegister(player, password, null);
} }
/** /**
* Force a player to unregister * Force a player to unregister.
* *
* @param player * player * @param player The player to unregister
*/ */
public void forceUnregister(Player player) { public void forceUnregister(Player player) {
plugin.getManagement().performUnregister(player, "", true); plugin.getManagement().performUnregister(player, "", true);

View File

@ -7,6 +7,7 @@ import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.List; import java.util.List;
@ -21,6 +22,7 @@ public class CommandService {
private final Messages messages; private final Messages messages;
private final HelpProvider helpProvider; private final HelpProvider helpProvider;
private final CommandMapper commandMapper; private final CommandMapper commandMapper;
private final PasswordSecurity passwordSecurity;
/** /**
* Constructor. * Constructor.
@ -30,11 +32,13 @@ public class CommandService {
* @param helpProvider Help provider * @param helpProvider Help provider
* @param messages Messages instance * @param messages Messages instance
*/ */
public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages) { public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages,
PasswordSecurity passwordSecurity) {
this.authMe = authMe; this.authMe = authMe;
this.messages = messages; this.messages = messages;
this.helpProvider = helpProvider; this.helpProvider = helpProvider;
this.commandMapper = commandMapper; this.commandMapper = commandMapper;
this.passwordSecurity = passwordSecurity;
} }
/** /**
@ -91,6 +95,15 @@ public class CommandService {
return authMe.getDataSource(); return authMe.getDataSource();
} }
/**
* Return the PasswordSecurity instance.
*
* @return The password security instance
*/
public PasswordSecurity getPasswordSecurity() {
return passwordSecurity;
}
/** /**
* Output the help for a given command. * Output the help for a given command.
* *

View File

@ -1,6 +1,5 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
@ -8,13 +7,11 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
/** /**
@ -60,13 +57,6 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
@Override @Override
public void run() { public void run() {
DataSource dataSource = commandService.getDataSource(); DataSource dataSource = commandService.getDataSource();
String hash;
try {
hash = PasswordSecurity.getHash(Settings.getPasswordHash, playerPass, playerNameLowerCase);
} catch (NoSuchAlgorithmException e) {
commandService.send(sender, MessageKey.ERROR);
return;
}
PlayerAuth auth = null; PlayerAuth auth = null;
if (PlayerCache.getInstance().isAuthenticated(playerNameLowerCase)) { if (PlayerCache.getInstance().isAuthenticated(playerNameLowerCase)) {
auth = PlayerCache.getInstance().getAuth(playerNameLowerCase); auth = PlayerCache.getInstance().getAuth(playerNameLowerCase);
@ -77,17 +67,21 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
commandService.send(sender, MessageKey.UNKNOWN_USER); commandService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} }
auth.setHash(hash);
// TODO #358: Do we always pass lowercase name?? In that case we need to do that in PasswordSecurity!
HashResult hashResult = commandService.getPasswordSecurity().computeHash(playerPass, playerNameLowerCase);
auth.setHash(hashResult.getHash());
auth.setSalt(hashResult.getSalt());
if (PasswordSecurity.userSalt.containsKey(playerNameLowerCase)) { if (PasswordSecurity.userSalt.containsKey(playerNameLowerCase)) {
auth.setSalt(PasswordSecurity.userSalt.get(playerNameLowerCase)); auth.setSalt(PasswordSecurity.userSalt.get(playerNameLowerCase));
commandService.getDataSource().updateSalt(auth); commandService.getDataSource().updateSalt(auth);
} }
if (!dataSource.updatePassword(auth)) { if (!dataSource.updatePassword(auth)) {
commandService.send(sender, MessageKey.ERROR); commandService.send(sender, MessageKey.ERROR);
return; } else {
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(playerNameLowerCase + "'s password changed");
} }
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(playerNameLowerCase + "'s password changed");
} }
}); });

View File

@ -5,12 +5,11 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
/** /**
@ -41,7 +40,8 @@ public class RegisterAdminCommand implements ExecutableCommand {
commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR);
return; return;
} }
if (playerPassLowerCase.length() < Settings.getPasswordMinLen || playerPassLowerCase.length() > Settings.passwordMaxLength) { if (playerPassLowerCase.length() < Settings.getPasswordMinLen
|| playerPassLowerCase.length() > Settings.passwordMaxLength) {
commandService.send(sender, MessageKey.INVALID_PASSWORD_LENGTH); commandService.send(sender, MessageKey.INVALID_PASSWORD_LENGTH);
return; return;
} }
@ -53,30 +53,30 @@ public class RegisterAdminCommand implements ExecutableCommand {
@Override @Override
public void run() { public void run() {
try { if (commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) {
if (commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) { commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); return;
return;
}
String hash = PasswordSecurity.getHash(Settings.getPasswordHash, playerPass, playerNameLowerCase);
PlayerAuth auth = new PlayerAuth(playerNameLowerCase, hash, "192.168.0.1", 0L, "your@email.com", playerName);
if (PasswordSecurity.userSalt.containsKey(playerNameLowerCase) && PasswordSecurity.userSalt.get(playerNameLowerCase) != null)
auth.setSalt(PasswordSecurity.userSalt.get(playerNameLowerCase));
else auth.setSalt("");
if (!commandService.getDataSource().saveAuth(auth)) {
commandService.send(sender, MessageKey.ERROR);
return;
}
commandService.getDataSource().setUnlogged(playerNameLowerCase);
if (Bukkit.getPlayerExact(playerName) != null)
Bukkit.getPlayerExact(playerName).kickPlayer("An admin just registered you, please log again");
commandService.send(sender, MessageKey.REGISTER_SUCCESS);
ConsoleLogger.info(playerNameLowerCase + " registered");
} catch (NoSuchAlgorithmException ex) {
ConsoleLogger.showError(ex.getMessage());
commandService.send(sender, MessageKey.ERROR);
} }
HashResult hashResult = commandService.getPasswordSecurity()
.computeHash(playerPass, playerNameLowerCase);
PlayerAuth auth = PlayerAuth.builder()
.name(playerNameLowerCase)
.realName(playerName)
.hash(hashResult.getHash())
.salt(hashResult.getSalt())
.build();
if (!commandService.getDataSource().saveAuth(auth)) {
commandService.send(sender, MessageKey.ERROR);
return;
}
commandService.getDataSource().setUnlogged(playerNameLowerCase);
if (Bukkit.getPlayerExact(playerName) != null) {
Bukkit.getPlayerExact(playerName).kickPlayer("An admin just registered you, please log again");
} else {
commandService.send(sender, MessageKey.REGISTER_SUCCESS);
ConsoleLogger.info(playerName + " registered");
}
} }
}); });
} }

View File

@ -1,20 +1,18 @@
package fr.xephi.authme.command.executable.email; package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
public class RecoverEmailCommand extends PlayerCommand { public class RecoverEmailCommand extends PlayerCommand {
@ -37,36 +35,33 @@ public class RecoverEmailCommand extends PlayerCommand {
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return; return;
} }
try {
String thePass = RandomString.generate(Settings.getRecoveryPassLength);
String hashNew = PasswordSecurity.getHash(Settings.getPasswordHash, thePass, playerName);
PlayerAuth auth;
if (PlayerCache.getInstance().isAuthenticated(playerName)) {
auth = PlayerCache.getInstance().getAuth(playerName);
} else if (dataSource.isAuthAvailable(playerName)) {
auth = dataSource.getAuth(playerName);
} else {
commandService.send(player, MessageKey.UNKNOWN_USER);
return;
}
if (Settings.getmailAccount.equals("") || Settings.getmailAccount.isEmpty()) {
commandService.send(player, MessageKey.ERROR);
return;
}
if (!playerMail.equalsIgnoreCase(auth.getEmail()) || playerMail.equalsIgnoreCase("your@email.com") String thePass = RandomString.generate(Settings.getRecoveryPassLength);
|| auth.getEmail().equalsIgnoreCase("your@email.com")) { HashResult hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName);
commandService.send(player, MessageKey.INVALID_EMAIL); PlayerAuth auth;
return; if (PlayerCache.getInstance().isAuthenticated(playerName)) {
} auth = PlayerCache.getInstance().getAuth(playerName);
auth.setHash(hashNew); } else if (dataSource.isAuthAvailable(playerName)) {
dataSource.updatePassword(auth); auth = dataSource.getAuth(playerName);
plugin.mail.main(auth, thePass); } else {
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); commandService.send(player, MessageKey.UNKNOWN_USER);
} catch (NoSuchAlgorithmException | NoClassDefFoundError ex) { return;
ConsoleLogger.showError(StringUtils.formatException(ex));
commandService.send(player, MessageKey.ERROR);
} }
if (StringUtils.isEmpty(Settings.getmailAccount)) {
commandService.send(player, MessageKey.ERROR);
return;
}
if (!playerMail.equalsIgnoreCase(auth.getEmail()) || playerMail.equalsIgnoreCase("your@email.com")
|| auth.getEmail().equalsIgnoreCase("your@email.com")) {
commandService.send(player, MessageKey.INVALID_EMAIL);
return;
}
auth.setHash(hashNew.getHash());
auth.setSalt(hashNew.getSalt());
dataSource.updatePassword(auth);
plugin.mail.main(auth, thePass);
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
} else { } else {
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE); commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
} }

View File

@ -6,6 +6,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -13,7 +14,6 @@ import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -28,15 +28,12 @@ public class RakamakConverter implements Converter {
public RakamakConverter(AuthMe instance, CommandSender sender) { public RakamakConverter(AuthMe instance, CommandSender sender) {
this.instance = instance; this.instance = instance;
this.database = instance.database; this.database = instance.getDataSource();
this.sender = sender; this.sender = sender;
} }
public RakamakConverter getInstance() {
return this;
}
@Override @Override
// TODO ljacqu 20151229: Restructure this into smaller portions
public void run() { public void run() {
HashAlgorithm hash = Settings.getPasswordHash; HashAlgorithm hash = Settings.getPasswordHash;
boolean useIP = Settings.rakamakUseIp; boolean useIP = Settings.rakamakUseIp;
@ -45,7 +42,7 @@ public class RakamakConverter implements Converter {
File source = new File(Settings.PLUGIN_FOLDER, fileName); File source = new File(Settings.PLUGIN_FOLDER, fileName);
File ipfiles = new File(Settings.PLUGIN_FOLDER, ipFileName); File ipfiles = new File(Settings.PLUGIN_FOLDER, ipFileName);
HashMap<String, String> playerIP = new HashMap<>(); HashMap<String, String> playerIP = new HashMap<>();
HashMap<String, String> playerPSW = new HashMap<>(); HashMap<String, HashResult> playerPSW = new HashMap<>();
try { try {
BufferedReader users; BufferedReader users;
BufferedReader ipFile; BufferedReader ipFile;
@ -61,30 +58,30 @@ public class RakamakConverter implements Converter {
} }
} }
ipFile.close(); ipFile.close();
users = new BufferedReader(new FileReader(source)); users = new BufferedReader(new FileReader(source));
PasswordSecurity passwordSecurity = instance.getPasswordSecurity();
while ((line = users.readLine()) != null) { while ((line = users.readLine()) != null) {
if (line.contains("=")) { if (line.contains("=")) {
String[] arguments = line.split("="); String[] arguments = line.split("=");
try { HashResult hashResult = passwordSecurity.computeHash(hash, arguments[1], arguments[0]);
playerPSW.put(arguments[0], PasswordSecurity.getHash(hash, arguments[1], arguments[0])); playerPSW.put(arguments[0], hashResult);
} catch (NoSuchAlgorithmException e) {
ConsoleLogger.showError(e.getMessage());
}
} }
} }
users.close(); users.close();
for (Entry<String, String> m : playerPSW.entrySet()) { for (Entry<String, HashResult> m : playerPSW.entrySet()) {
String playerName = m.getKey(); String playerName = m.getKey();
String psw = playerPSW.get(playerName); HashResult psw = playerPSW.get(playerName);
String ip; String ip = useIP ? playerIP.get(playerName) : "127.0.0.1";
if (useIP) { PlayerAuth auth = PlayerAuth.builder()
ip = playerIP.get(playerName); .name(playerName)
} else { .realName(playerName)
ip = "127.0.0.1"; .ip(ip)
} .hash(psw.getHash())
PlayerAuth auth = new PlayerAuth(playerName, psw, ip, System.currentTimeMillis(), playerName); .salt(psw.getSalt())
if (PasswordSecurity.userSalt.containsKey(playerName)) .lastLogin(System.currentTimeMillis())
auth.setSalt(PasswordSecurity.userSalt.get(playerName)); .build();
database.saveAuth(auth); database.saveAuth(auth);
} }
ConsoleLogger.info("Rakamak database has been imported correctly"); ConsoleLogger.info("Rakamak database has been imported correctly");

View File

@ -138,17 +138,18 @@ public class AsynchronousLogin {
String hash = pAuth.getHash(); String hash = pAuth.getHash();
String email = pAuth.getEmail(); String email = pAuth.getEmail();
boolean passwordVerified = true; boolean passwordVerified = forceLogin || plugin.getPasswordSecurity().comparePassword(password, hash, realName);
if (!forceLogin)
try {
passwordVerified = PasswordSecurity.comparePasswordWithHash(password, hash, realName);
} catch (Exception ex) {
ConsoleLogger.showError(ex.getMessage());
m.send(player, MessageKey.ERROR);
return;
}
if (passwordVerified && player.isOnline()) { if (passwordVerified && player.isOnline()) {
PlayerAuth auth = new PlayerAuth(name, hash, getIP(), new Date().getTime(), email, realName); PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(realName)
.ip(getIP())
.lastLogin(new Date().getTime())
.email(email)
.hash(hash)
.salt(pAuth.getSalt())
.build();
database.updateSession(auth); database.updateSession(auth);
if (Settings.useCaptcha) { if (Settings.useCaptcha) {

View File

@ -8,7 +8,7 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -44,7 +44,10 @@ public class AsyncRegister {
} else if (!Settings.isRegistrationEnabled) { } else if (!Settings.isRegistrationEnabled) {
m.send(player, MessageKey.REGISTRATION_DISABLED); m.send(player, MessageKey.REGISTRATION_DISABLED);
return false; return false;
} else if (passLow.contains("delete") || passLow.contains("where") || passLow.contains("insert") || passLow.contains("modify") || passLow.contains("from") || passLow.contains("select") || passLow.contains(";") || passLow.contains("null") || !passLow.matches(Settings.getPassRegex)) { } else if (passLow.contains("delete") || passLow.contains("where") || passLow.contains("insert")
|| passLow.contains("modify") || passLow.contains("from") || passLow.contains("select")
|| passLow.contains(";") || passLow.contains("null") || !passLow.matches(Settings.getPassRegex)) {
// TODO #308: Remove check for SQL keywords
m.send(player, MessageKey.PASSWORD_MATCH_ERROR); m.send(player, MessageKey.PASSWORD_MATCH_ERROR);
return false; return false;
} else if (passLow.equalsIgnoreCase(player.getName())) { } else if (passLow.equalsIgnoreCase(player.getName())) {
@ -87,26 +90,25 @@ public class AsyncRegister {
} }
} }
private void emailRegister() throws Exception { private void emailRegister() {
if (Settings.getmaxRegPerEmail > 0 if (Settings.getmaxRegPerEmail > 0
&& !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS) && !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS)
&& database.getAllAuthsByEmail(email).size() >= Settings.getmaxRegPerEmail) { && database.getAllAuthsByEmail(email).size() >= Settings.getmaxRegPerEmail) {
m.send(player, MessageKey.MAX_REGISTER_EXCEEDED); m.send(player, MessageKey.MAX_REGISTER_EXCEEDED);
return; return;
} }
final String hashNew = PasswordSecurity.getHash(Settings.getPasswordHash, password, name); final HashResult hashResult = plugin.getPasswordSecurity().computeHash(password, name);
final String salt = PasswordSecurity.userSalt.get(name);
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.realName(player.getName()) .realName(player.getName())
.hash(hashNew) .hash(hashResult.getHash())
.salt(hashResult.getSalt())
.ip(ip) .ip(ip)
.locWorld(player.getLocation().getWorld().getName()) .locWorld(player.getLocation().getWorld().getName())
.locX(player.getLocation().getX()) .locX(player.getLocation().getX())
.locY(player.getLocation().getY()) .locY(player.getLocation().getY())
.locZ(player.getLocation().getZ()) .locZ(player.getLocation().getZ())
.email(email) .email(email)
.salt(salt != null ? salt : "")
.build(); .build();
if (!database.saveAuth(auth)) { if (!database.saveAuth(auth)) {
@ -122,18 +124,17 @@ public class AsyncRegister {
} }
private void passwordRegister() throws Exception { private void passwordRegister() throws Exception {
final String hashNew = PasswordSecurity.getHash(Settings.getPasswordHash, password, name); final HashResult hashResult = plugin.getPasswordSecurity().computeHash(password, name);
final String salt = PasswordSecurity.userSalt.get(name);
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.realName(player.getName()) .realName(player.getName())
.hash(hashNew) .hash(hashResult.getHash())
.salt(hashResult.getSalt())
.ip(ip) .ip(ip)
.locWorld(player.getLocation().getWorld().getName()) .locWorld(player.getLocation().getWorld().getName())
.locX(player.getLocation().getX()) .locX(player.getLocation().getX())
.locY(player.getLocation().getY()) .locY(player.getLocation().getY())
.locZ(player.getLocation().getZ()) .locZ(player.getLocation().getZ())
.salt(salt != null ? salt : "")
.build(); .build();
if (!database.saveAuth(auth)) { if (!database.saveAuth(auth)) {

View File

@ -62,55 +62,52 @@ public class AsynchronousUnregister {
} }
public void process() { public void process() {
try { if (force || plugin.getPasswordSecurity().comparePassword(password, PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) {
if (force || PasswordSecurity.comparePasswordWithHash(password, PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) { if (!plugin.database.removeAuth(name)) {
if (!plugin.database.removeAuth(name)) { m.send(player, MessageKey.ERROR);
m.send(player, MessageKey.ERROR); return;
return; }
int timeOut = Settings.getRegistrationTimeout * 20;
if (Settings.isForcedRegistrationEnabled) {
Utils.teleportToSpawn(player);
player.saveData();
PlayerCache.getInstance().removePlayer(player.getName().toLowerCase());
if (!Settings.getRegisteredGroup.isEmpty()) {
Utils.setGroup(player, GroupType.UNREGISTERED);
} }
int timeOut = Settings.getRegistrationTimeout * 20; LimboCache.getInstance().addLimboPlayer(player);
if (Settings.isForcedRegistrationEnabled) { LimboPlayer limboPlayer = LimboCache.getInstance().getLimboPlayer(name);
Utils.teleportToSpawn(player); int interval = Settings.getWarnMessageInterval;
player.saveData(); BukkitScheduler scheduler = plugin.getServer().getScheduler();
PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); if (timeOut != 0) {
if (!Settings.getRegisteredGroup.isEmpty()) { BukkitTask id = scheduler.runTaskLaterAsynchronously(plugin,
Utils.setGroup(player, GroupType.UNREGISTERED); new TimeoutTask(plugin, name, player), timeOut);
} limboPlayer.setTimeoutTaskId(id);
LimboCache.getInstance().addLimboPlayer(player);
LimboPlayer limboPlayer = LimboCache.getInstance().getLimboPlayer(name);
int interval = Settings.getWarnMessageInterval;
BukkitScheduler scheduler = plugin.getServer().getScheduler();
if (timeOut != 0) {
BukkitTask id = scheduler.runTaskLaterAsynchronously(plugin,
new TimeoutTask(plugin, name, player), timeOut);
limboPlayer.setTimeoutTaskId(id);
}
limboPlayer.setMessageTaskId(scheduler.runTaskAsynchronously(plugin,
new MessageTask(plugin, name, m.retrieve(MessageKey.REGISTER_MESSAGE), interval)));
m.send(player, MessageKey.UNREGISTERED_SUCCESS);
ConsoleLogger.info(player.getDisplayName() + " unregistered himself");
return;
}
if (!Settings.unRegisteredGroup.isEmpty()) {
Utils.setGroup(player, Utils.GroupType.UNREGISTERED);
}
PlayerCache.getInstance().removePlayer(name);
// check if Player cache File Exist and delete it, preventing
// duplication of items
if (playerCache.doesCacheExist(player)) {
playerCache.removeCache(player);
}
// Apply blind effect
if (Settings.applyBlindEffect) {
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2));
} }
limboPlayer.setMessageTaskId(scheduler.runTaskAsynchronously(plugin,
new MessageTask(plugin, name, m.retrieve(MessageKey.REGISTER_MESSAGE), interval)));
m.send(player, MessageKey.UNREGISTERED_SUCCESS); m.send(player, MessageKey.UNREGISTERED_SUCCESS);
ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); ConsoleLogger.info(player.getDisplayName() + " unregistered himself");
Utils.teleportToSpawn(player); return;
} else {
m.send(player, MessageKey.WRONG_PASSWORD);
} }
} catch (NoSuchAlgorithmException ignored) { if (!Settings.unRegisteredGroup.isEmpty()) {
Utils.setGroup(player, Utils.GroupType.UNREGISTERED);
}
PlayerCache.getInstance().removePlayer(name);
// check if Player cache File Exist and delete it, preventing
// duplication of items
if (playerCache.doesCacheExist(player)) {
playerCache.removeCache(player);
}
// Apply blind effect
if (Settings.applyBlindEffect) {
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2));
}
m.send(player, MessageKey.UNREGISTERED_SUCCESS);
ConsoleLogger.info(player.getDisplayName() + " unregistered himself");
Utils.teleportToSpawn(player);
} else {
m.send(player, MessageKey.WRONG_PASSWORD);
} }
} }
} }

View File

@ -4,7 +4,6 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.PasswordEncryptionEvent; import fr.xephi.authme.events.PasswordEncryptionEvent;
import fr.xephi.authme.security.crypts.BCRYPT;
import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
@ -20,9 +19,13 @@ public class PasswordSecurity {
@Deprecated @Deprecated
public static final HashMap<String, String> userSalt = new HashMap<>(); public static final HashMap<String, String> userSalt = new HashMap<>();
private final DataSource dataSource; private final DataSource dataSource;
private final HashAlgorithm algorithm;
private final boolean supportOldAlgorithm;
public PasswordSecurity(DataSource dataSource) { public PasswordSecurity(DataSource dataSource, HashAlgorithm algorithm, boolean supportOldAlgorithm) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.algorithm = algorithm;
this.supportOldAlgorithm = supportOldAlgorithm;
} }
@Deprecated @Deprecated
@ -32,96 +35,7 @@ public class PasswordSecurity {
@Deprecated @Deprecated
public static String getHash(HashAlgorithm alg, String password, String playerName) throws NoSuchAlgorithmException { public static String getHash(HashAlgorithm alg, String password, String playerName) throws NoSuchAlgorithmException {
EncryptionMethod method; return "";
try {
if (alg != HashAlgorithm.CUSTOM)
method = alg.getClazz().newInstance();
else method = null;
} catch (InstantiationException | IllegalAccessException e) {
throw new NoSuchAlgorithmException("Problem with hash algorithm '" + alg + "'", e);
}
String salt = "";
switch (alg) {
case SHA256:
salt = createSalt(16);
break;
case MD5VB:
salt = createSalt(16);
break;
case XAUTH:
salt = createSalt(12);
break;
case MYBB:
salt = createSalt(8);
userSalt.put(playerName, salt);
break;
case IPB3:
salt = createSalt(5);
userSalt.put(playerName, salt);
break;
case PHPFUSION:
salt = createSalt(12);
userSalt.put(playerName, salt);
break;
case SALTED2MD5:
salt = createSalt(Settings.saltLength);
userSalt.put(playerName, salt);
break;
case JOOMLA:
salt = createSalt(32);
userSalt.put(playerName, salt);
break;
case BCRYPT:
salt = BCRYPT.gensalt(Settings.bCryptLog2Rounds);
userSalt.put(playerName, salt);
break;
case WBB3:
salt = createSalt(40);
userSalt.put(playerName, salt);
break;
case WBB4:
salt = BCRYPT.gensalt(8);
userSalt.put(playerName, salt);
break;
case PBKDF2DJANGO:
case PBKDF2:
salt = createSalt(12);
userSalt.put(playerName, salt);
break;
case SMF:
return method.computeHash(password, null, playerName);
case PHPBB:
salt = createSalt(16);
userSalt.put(playerName, salt);
break;
case BCRYPT2Y:
salt = createSalt(16);
userSalt.put(playerName, salt);
break;
case SALTEDSHA512:
salt = createSalt(32);
userSalt.put(playerName, salt);
break;
case MD5:
case SHA1:
case WHIRLPOOL:
case PLAINTEXT:
case SHA512:
case ROYALAUTH:
case CRAZYCRYPT1:
case DOUBLEMD5:
case WORDPRESS:
case CUSTOM:
break;
default:
throw new NoSuchAlgorithmException("Unknown hash algorithm");
}
PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName);
Bukkit.getPluginManager().callEvent(event);
method = event.getMethod();
if (method == null)
throw new NoSuchAlgorithmException("Unknown hash algorithm");
return method.computeHash(password, salt, playerName);
} }
@Deprecated @Deprecated
@ -167,11 +81,19 @@ public class PasswordSecurity {
return false; return false;
} }
public HashResult computeHash(String password, String playerName) {
return computeHash(algorithm, password, playerName);
}
public HashResult computeHash(HashAlgorithm algorithm, String password, String playerName) { public HashResult computeHash(HashAlgorithm algorithm, String password, String playerName) {
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
return method.computeHash(password, playerName); return method.computeHash(password, playerName);
} }
public boolean comparePassword(String hash, String password, String playerName) {
return comparePassword(algorithm, hash, password, playerName);
}
public boolean comparePassword(HashAlgorithm algorithm, String hash, String password, String playerName) { public boolean comparePassword(HashAlgorithm algorithm, String hash, String password, String playerName) {
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
String salt = null; String salt = null;

View File

@ -1,20 +1,18 @@
package fr.xephi.authme.task; package fr.xephi.authme.task;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.security.NoSuchAlgorithmException;
public class ChangePasswordTask implements Runnable { public class ChangePasswordTask implements Runnable {
private final AuthMe plugin; private final AuthMe plugin;
@ -32,48 +30,41 @@ public class ChangePasswordTask implements Runnable {
@Override @Override
public void run() { public void run() {
Messages m = plugin.getMessages(); Messages m = plugin.getMessages();
try { PasswordSecurity passwordSecurity = plugin.getPasswordSecurity();
final String name = player.getName().toLowerCase();
String hashNew = PasswordSecurity.getHash(Settings.getPasswordHash, newPassword, name);
PlayerAuth auth = PlayerCache.getInstance().getAuth(name);
if (PasswordSecurity.comparePasswordWithHash(oldPassword, auth.getHash(), player.getName())) {
auth.setHash(hashNew);
if (PasswordSecurity.userSalt.containsKey(name) && PasswordSecurity.userSalt.get(name) != null) {
auth.setSalt(PasswordSecurity.userSalt.get(name));
} else {
auth.setSalt("");
}
if (!plugin.database.updatePassword(auth)) {
m.send(player, MessageKey.ERROR);
return;
}
plugin.database.updateSalt(auth);
PlayerCache.getInstance().updatePlayer(auth);
m.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(player.getName() + " changed his password");
if (Settings.bungee)
{
final String hash = auth.getHash();
final String salt = auth.getSalt();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable(){
@Override final String name = player.getName().toLowerCase();
public void run() { PlayerAuth auth = PlayerCache.getInstance().getAuth(name);
ByteArrayDataOutput out = ByteStreams.newDataOutput(); if (passwordSecurity.comparePassword(oldPassword, auth.getHash(), player.getName())) {
out.writeUTF("Forward"); HashResult hashResult = passwordSecurity.computeHash(newPassword, name);
out.writeUTF("ALL"); auth.setHash(hashResult.getHash());
out.writeUTF("AuthMe"); auth.setSalt(hashResult.getSalt());
out.writeUTF("changepassword;" + name + ";" + hash + ";" + salt);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); if (!plugin.getDataSource().updatePassword(auth)) {
} m.send(player, MessageKey.ERROR);
}); return;
}
} else {
m.send(player, MessageKey.WRONG_PASSWORD);
} }
} catch (NoSuchAlgorithmException ex) { plugin.getDataSource().updateSalt(auth);
ConsoleLogger.showError(ex.getMessage()); PlayerCache.getInstance().updatePlayer(auth);
m.send(player, MessageKey.ERROR); m.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(player.getName() + " changed his password");
if (Settings.bungee) {
final String hash = auth.getHash();
final String salt = auth.getSalt();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable(){
@Override
public void run() {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Forward");
out.writeUTF("ALL");
out.writeUTF("AuthMe");
out.writeUTF("changepassword;" + name + ";" + hash + ";" + salt);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
});
}
} else {
m.send(player, MessageKey.WRONG_PASSWORD);
} }
} }
} }

View File

@ -2,10 +2,12 @@ package fr.xephi.authme.command;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.junit.Before; import org.junit.Before;
@ -32,6 +34,7 @@ public class CommandServiceTest {
private CommandMapper commandMapper; private CommandMapper commandMapper;
private HelpProvider helpProvider; private HelpProvider helpProvider;
private Messages messages; private Messages messages;
private PasswordSecurity passwordSecurity;
private CommandService commandService; private CommandService commandService;
@Before @Before
@ -40,7 +43,8 @@ public class CommandServiceTest {
commandMapper = mock(CommandMapper.class); commandMapper = mock(CommandMapper.class);
helpProvider = mock(HelpProvider.class); helpProvider = mock(HelpProvider.class);
messages = mock(Messages.class); messages = mock(Messages.class);
commandService = new CommandService(authMe, commandMapper, helpProvider, messages); passwordSecurity = mock(PasswordSecurity.class);
commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity);
} }
@Test @Test
@ -110,9 +114,25 @@ public class CommandServiceTest {
} }
@Test @Test
@Ignore
public void shouldGetDataSource() { public void shouldGetDataSource() {
// TODO ljacqu 20151226: Cannot mock calls to fields // given
DataSource dataSource = mock(DataSource.class);
given(authMe.getDataSource()).willReturn(dataSource);
// when
DataSource result = commandService.getDataSource();
// then
assertThat(result, equalTo(dataSource));
}
@Test
public void shouldGetPasswordSecurity() {
// given/when
PasswordSecurity passwordSecurity = commandService.getPasswordSecurity();
// then
assertThat(passwordSecurity, equalTo(this.passwordSecurity));
} }
@Test @Test