diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 7681a536..64d293a5 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -43,7 +43,7 @@ import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; @@ -592,8 +592,9 @@ public class AuthMe extends JavaPlugin { 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()) { - HashResult hashResult = passwordSecurity.computeHash(HashAlgorithm.SHA256, auth.getHash(), auth.getNickname()); - auth.setHash(hashResult.getHash()); + EncryptedPassword encryptedPassword = passwordSecurity.computeHash( + HashAlgorithm.SHA256, auth.getPassword().getHash(), auth.getNickname()); + auth.setPassword(encryptedPassword); database.updatePassword(auth); } Settings.setValue("settings.security.passwordHash", "SHA256"); diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java index af96bf96..2d799b8d 100644 --- a/src/main/java/fr/xephi/authme/api/API.java +++ b/src/main/java/fr/xephi/authme/api/API.java @@ -4,8 +4,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; 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.security.crypts.EncryptedPassword; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -135,13 +134,13 @@ public class API { @Deprecated public static boolean registerPlayer(String playerName, String password) { String name = playerName.toLowerCase(); - HashResult hashResult = passwordSecurity.computeHash(Settings.getPasswordHash, password, name); + EncryptedPassword encryptedPassword = passwordSecurity.computeHash(password, name); if (isRegistered(name)) { return false; } PlayerAuth auth = PlayerAuth.builder() .name(name) - .hash(hashResult.getHash()) + .hash(encryptedPassword) .lastLogin(0) .realName(playerName) .build(); diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index ee48d5d6..2990f1df 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -3,7 +3,7 @@ package fr.xephi.authme.api; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -149,14 +149,13 @@ public class NewAPI { */ public boolean registerPlayer(String playerName, String password) { String name = playerName.toLowerCase(); - HashResult result = plugin.getPasswordSecurity().computeHash(password, name); + EncryptedPassword result = plugin.getPasswordSecurity().computeHash(password, name); if (isRegistered(name)) { return false; } PlayerAuth auth = PlayerAuth.builder() .name(name) - .hash(result.getHash()) - .salt(result.getSalt()) + .hash(result) .realName(playerName) .build(); return plugin.getDataSource().saveAuth(auth); diff --git a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java index c501e8eb..64132afa 100644 --- a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java +++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java @@ -1,11 +1,9 @@ package fr.xephi.authme.cache.auth; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.security.crypts.EncryptedPassword; import static com.google.common.base.Objects.firstNonNull; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Strings.nullToEmpty; /** @@ -13,14 +11,13 @@ import static com.google.common.base.Strings.nullToEmpty; public class PlayerAuth { private String nickname; - private String hash; + private EncryptedPassword password; private String ip; private long lastLogin; private double x; private double y; private double z; private String world; - private String salt; private int groupId; private String email; private String realName; @@ -41,7 +38,7 @@ public class PlayerAuth { * @param realName String */ public PlayerAuth(String nickname, String ip, long lastLogin, String realName) { - this(nickname, "", "", -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); + this(nickname, new EncryptedPassword(""), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); } /** @@ -55,7 +52,8 @@ public class PlayerAuth { * @param realName String */ public PlayerAuth(String nickname, double x, double y, double z, String world, String realName) { - this(nickname, "", "", -1, "127.0.0.1", System.currentTimeMillis(), x, y, z, world, "your@email.com", realName); + this(nickname, new EncryptedPassword(""), -1, "127.0.0.1", System.currentTimeMillis(), x, y, z, world, + "your@email.com", realName); } /** @@ -68,7 +66,7 @@ public class PlayerAuth { * @param realName String */ public PlayerAuth(String nickname, String hash, String ip, long lastLogin, String realName) { - this(nickname, hash, "", -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); + this(nickname, new EncryptedPassword(hash), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); } /** @@ -82,7 +80,7 @@ public class PlayerAuth { * @param realName String */ public PlayerAuth(String nickname, String hash, String ip, long lastLogin, String email, String realName) { - this(nickname, hash, "", -1, ip, lastLogin, 0, 0, 0, "world", email, realName); + this(nickname, new EncryptedPassword(hash), -1, ip, lastLogin, 0, 0, 0, "world", email, realName); } /** @@ -96,7 +94,7 @@ public class PlayerAuth { * @param realName String */ public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, String realName) { - this(nickname, hash, salt, -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); + this(nickname, new EncryptedPassword(hash, salt), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); } /** @@ -113,8 +111,9 @@ public class PlayerAuth { * @param email String * @param realName String */ - public PlayerAuth(String nickname, String hash, String ip, long lastLogin, double x, double y, double z, String world, String email, String realName) { - this(nickname, hash, "", -1, ip, lastLogin, x, y, z, world, email, realName); + public PlayerAuth(String nickname, String hash, String ip, long lastLogin, double x, double y, double z, + String world, String email, String realName) { + this(nickname, new EncryptedPassword(hash), -1, ip, lastLogin, x, y, z, world, email, realName); } /** @@ -132,8 +131,10 @@ public class PlayerAuth { * @param email String * @param realName String */ - public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, double x, double y, double z, String world, String email, String realName) { - this(nickname, hash, salt, -1, ip, lastLogin, x, y, z, world, email, realName); + public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, double x, double y, + double z, String world, String email, String realName) { + this(nickname, new EncryptedPassword(hash, salt), -1, ip, lastLogin, + x, y, z, world, email, realName); } /** @@ -147,38 +148,37 @@ public class PlayerAuth { * @param lastLogin long * @param realName String */ - public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip, long lastLogin, String realName) { - this(nickname, hash, salt, groupId, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); - } - - /** - * Constructor for PlayerAuth. - * - * @param nickname String - * @param hash String - * @param salt String - * @param groupId int - * @param ip String - * @param lastLogin long - * @param x double - * @param y double - * @param z double - * @param world String - * @param email String - * @param realName String - */ public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip, - long lastLogin, double x, double y, double z, String world, String email, - String realName) { + long lastLogin, String realName) { + this(nickname, new EncryptedPassword(hash, salt), groupId, ip, lastLogin, + 0, 0, 0, "world", "your@email.com", realName); + } + + /** + * Constructor for PlayerAuth. + * + * @param nickname String + * @param password String + * @param groupId int + * @param ip String + * @param lastLogin long + * @param x double + * @param y double + * @param z double + * @param world String + * @param email String + * @param realName String + */ + public PlayerAuth(String nickname, EncryptedPassword password, int groupId, String ip, long lastLogin, + double x, double y, double z, String world, String email, String realName) { this.nickname = nickname.toLowerCase(); - this.hash = hash; + this.password = password; this.ip = ip; this.lastLogin = lastLogin; this.x = x; this.y = y; this.z = z; this.world = world; - this.salt = salt; this.groupId = groupId; this.email = email; this.realName = realName; @@ -191,237 +191,108 @@ public class PlayerAuth { */ public void set(PlayerAuth auth) { this.setEmail(auth.getEmail()); - this.setHash(auth.getHash()); + this.setPassword(auth.getPassword()); this.setIp(auth.getIp()); this.setLastLogin(auth.getLastLogin()); this.setNickname(auth.getNickname()); this.setQuitLocX(auth.getQuitLocX()); this.setQuitLocY(auth.getQuitLocY()); this.setQuitLocZ(auth.getQuitLocZ()); - this.setSalt(auth.getSalt()); this.setWorld(auth.getWorld()); this.setRealName(auth.getRealName()); } - /** - * Method setNickname. - * - * @param nickname String - */ + public void setNickname(String nickname) { this.nickname = nickname.toLowerCase(); } - /** - * Method getNickname. - * - * @return String - */ public String getNickname() { return nickname; } - /** - * Method getRealName. - * - * @return String - */ public String getRealName() { return realName; } - /** - * Method setRealName. - * - * @param realName String - */ public void setRealName(String realName) { this.realName = realName; } - /** - * Method getGroupId. - * - * @return int - */ public int getGroupId() { return groupId; } - /** - * Method getQuitLocX. - * - * @return double - */ public double getQuitLocX() { return x; } - /** - * Method setQuitLocX. - * - * @param d double - */ public void setQuitLocX(double d) { this.x = d; } - /** - * Method getQuitLocY. - * - * @return double - */ public double getQuitLocY() { return y; } - /** - * Method setQuitLocY. - * - * @param d double - */ public void setQuitLocY(double d) { this.y = d; } - /** - * Method getQuitLocZ. - * - * @return double - */ public double getQuitLocZ() { return z; } - /** - * Method setQuitLocZ. - * - * @param d double - */ public void setQuitLocZ(double d) { this.z = d; } - /** - * Method getWorld. - * - * @return String - */ public String getWorld() { return world; } - /** - * Method setWorld. - * - * @param world String - */ public void setWorld(String world) { this.world = world; } - /** - * Method getIp. - * - * @return String - */ public String getIp() { return ip; } - /** - * Method setIp. - * - * @param ip String - */ public void setIp(String ip) { this.ip = ip; } - /** - * Method getLastLogin. - * - * @return long - */ public long getLastLogin() { return lastLogin; } - /** - * Method setLastLogin. - * - * @param lastLogin long - */ public void setLastLogin(long lastLogin) { this.lastLogin = lastLogin; } - /** - * Method getEmail. - * - * @return String - */ public String getEmail() { return email; } - /** - * Method setEmail. - * - * @param email String - */ public void setEmail(String email) { this.email = email; } - /** - * Method getSalt. - * - * @return String - */ - public String getSalt() { - return this.salt; - } - - /** - * Method setSalt. - * - * @param salt String - */ - public void setSalt(String salt) { - this.salt = salt; - } - - /** - * Method getHash. - * - * @return String - */ - public String getHash() { - if (Settings.getPasswordHash == HashAlgorithm.MD5VB) { + public EncryptedPassword getPassword() { + // TODO #358: Check whether this check is really necessary. It's been here since the first commit. + /*if (Settings.getPasswordHash == HashAlgorithm.MD5VB) { if (salt != null && !salt.isEmpty() && Settings.getPasswordHash == HashAlgorithm.MD5VB) { return "$MD5vb$" + salt + "$" + hash; } - } - return hash; + }*/ + return password; } - /** - * Method setHash. - * - * @param hash String - */ - public void setHash(String hash) { - this.hash = hash; + public void setPassword(EncryptedPassword password) { + this.password = password; } - /** - * Method equals. - * - * @param obj Object - * - * @return boolean - */ @Override public boolean equals(Object obj) { if (!(obj instanceof PlayerAuth)) { @@ -431,11 +302,6 @@ public class PlayerAuth { return other.getIp().equals(this.ip) && other.getNickname().equals(this.nickname); } - /** - * Method hashCode. - * - * @return int - */ @Override public int hashCode() { int hashCode = 7; @@ -444,20 +310,14 @@ public class PlayerAuth { return hashCode; } - /** - * Method toString. - * - * @return String - */ @Override public String toString() { - return ("Player : " + nickname + " | " + realName + return "Player : " + nickname + " | " + realName + " ! IP : " + ip + " ! LastLogin : " + lastLogin + " ! LastPosition : " + x + "," + y + "," + z + "," + world + " ! Email : " + email - + " ! Hash : " + hash - + " ! Salt : " + salt); + + " ! Hash : {" + password.getHash() + ", " + password.getSalt() + "}"; } /** @@ -472,8 +332,8 @@ public class PlayerAuth { str.append(this.realName).append(d); str.append(this.ip).append(d); str.append(this.email).append(d); - str.append(this.hash).append(d); - str.append(this.salt).append(d); + str.append(this.password.getHash()).append(d); + str.append(this.password.getSalt()).append(d); str.append(this.groupId).append(d); str.append(this.lastLogin).append(d); str.append(this.world).append(d); @@ -492,8 +352,7 @@ public class PlayerAuth { this.realName = args[1]; this.ip = args[2]; this.email = args[3]; - this.hash = args[4]; - this.salt = args[5]; + this.password = new EncryptedPassword(args[4], args[5]); this.groupId = Integer.parseInt(args[6]); this.lastLogin = Long.parseLong(args[7]); this.world = args[8]; @@ -509,8 +368,7 @@ public class PlayerAuth { public static final class Builder { private String name; private String realName; - private String hash; - private String salt; + private EncryptedPassword hash; private String ip; private String world; private String email; @@ -523,8 +381,7 @@ public class PlayerAuth { public PlayerAuth build() { return new PlayerAuth( checkNotNull(name), - nullToEmpty(hash), - nullToEmpty(salt), + firstNonNull(hash, new EncryptedPassword("")), groupId, firstNonNull(ip, "127.0.0.1"), lastLogin, @@ -545,14 +402,13 @@ public class PlayerAuth { return this; } - public Builder hash(String hash) { + public Builder hash(EncryptedPassword hash) { this.hash = hash; return this; } - public Builder salt(String salt) { - this.salt = salt; - return this; + public Builder hash(String hash, String salt) { + return hash(new EncryptedPassword(hash, salt)); } public Builder ip(String ip) { diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java index 74954521..17f3b333 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java @@ -7,7 +7,7 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import org.bukkit.command.CommandSender; @@ -68,11 +68,9 @@ public class ChangePasswordAdminCommand implements ExecutableCommand { } // 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()); + EncryptedPassword encryptedPassword = commandService.getPasswordSecurity().computeHash(playerPass, playerNameLowerCase); + auth.setPassword(encryptedPassword); - // TODO #358: updatePassword(auth) needs to update the salt, too. if (!dataSource.updatePassword(auth)) { commandService.send(sender, MessageKey.ERROR); } else { diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java index 44c0be4a..5131ac28 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java @@ -5,7 +5,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -57,13 +57,12 @@ public class RegisterAdminCommand implements ExecutableCommand { commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); return; } - HashResult hashResult = commandService.getPasswordSecurity() + EncryptedPassword encryptedPassword = commandService.getPasswordSecurity() .computeHash(playerPass, playerNameLowerCase); PlayerAuth auth = PlayerAuth.builder() .name(playerNameLowerCase) .realName(playerName) - .hash(hashResult.getHash()) - .salt(hashResult.getSalt()) + .hash(encryptedPassword) .build(); if (!commandService.getDataSource().saveAuth(auth)) { diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java index 045bf00a..5e2ed660 100644 --- a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java @@ -8,7 +8,7 @@ import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.RandomString; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.StringUtils; import org.bukkit.entity.Player; @@ -37,7 +37,7 @@ public class RecoverEmailCommand extends PlayerCommand { } String thePass = RandomString.generate(Settings.getRecoveryPassLength); - HashResult hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName); + EncryptedPassword hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName); PlayerAuth auth; if (PlayerCache.getInstance().isAuthenticated(playerName)) { auth = PlayerCache.getInstance().getAuth(playerName); @@ -57,8 +57,7 @@ public class RecoverEmailCommand extends PlayerCommand { commandService.send(player, MessageKey.INVALID_EMAIL); return; } - auth.setHash(hashNew.getHash()); - auth.setSalt(hashNew.getSalt()); + auth.setPassword(hashNew); dataSource.updatePassword(auth); plugin.mail.main(auth, thePass); commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); diff --git a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java index 15e26efc..a86b6826 100644 --- a/src/main/java/fr/xephi/authme/converter/RakamakConverter.java +++ b/src/main/java/fr/xephi/authme/converter/RakamakConverter.java @@ -6,7 +6,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import org.bukkit.command.CommandSender; @@ -42,7 +42,7 @@ public class RakamakConverter implements Converter { File source = new File(Settings.PLUGIN_FOLDER, fileName); File ipfiles = new File(Settings.PLUGIN_FOLDER, ipFileName); HashMap playerIP = new HashMap<>(); - HashMap playerPSW = new HashMap<>(); + HashMap playerPSW = new HashMap<>(); try { BufferedReader users; BufferedReader ipFile; @@ -64,22 +64,21 @@ public class RakamakConverter implements Converter { while ((line = users.readLine()) != null) { if (line.contains("=")) { String[] arguments = line.split("="); - HashResult hashResult = passwordSecurity.computeHash(hash, arguments[1], arguments[0]); - playerPSW.put(arguments[0], hashResult); + EncryptedPassword encryptedPassword = passwordSecurity.computeHash(hash, arguments[1], arguments[0]); + playerPSW.put(arguments[0], encryptedPassword); } } users.close(); - for (Entry m : playerPSW.entrySet()) { + for (Entry m : playerPSW.entrySet()) { String playerName = m.getKey(); - HashResult psw = playerPSW.get(playerName); + EncryptedPassword psw = playerPSW.get(playerName); String ip = useIP ? playerIP.get(playerName) : "127.0.0.1"; PlayerAuth auth = PlayerAuth.builder() .name(playerName) .realName(playerName) .ip(ip) - .hash(psw.getHash()) - .salt(psw.getSalt()) + .hash(psw) .lastLogin(System.currentTimeMillis()) .build(); database.saveAuth(auth); diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 8b26b08c..2351c6cb 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -270,24 +270,6 @@ public class CacheDataSource implements DataSource { return result; } - /** - * Method updateSalt. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth) - */ - @Override - public synchronized boolean updateSalt(final PlayerAuth auth) { - boolean result = source.updateSalt(auth); - if (result) { - cachedAuths.refresh(auth.getNickname()); - } - return result; - } - /** * Method getAllAuthsByName. * diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index e43dffa8..10f74b92 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -134,15 +134,6 @@ public interface DataSource { */ boolean updateEmail(PlayerAuth auth); - /** - * Method updateSalt. - * - * @param auth PlayerAuth - * - * @return boolean - */ - boolean updateSalt(PlayerAuth auth); - void close(); void reload(); diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index b7fb5517..55646ddc 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -102,7 +102,7 @@ public class FlatFile implements DataSource { BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(source, true)); - bw.write(auth.getNickname() + ":" + auth.getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n"); + bw.write(auth.getNickname() + ":" + auth.getPassword() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n"); } catch (IOException ex) { ConsoleLogger.showError(ex.getMessage()); return false; @@ -137,25 +137,26 @@ public class FlatFile implements DataSource { while ((line = br.readLine()) != null) { String[] args = line.split(":"); if (args[0].equals(auth.getNickname())) { + // Note ljacqu 20151230: This does not persist the salt; it is not supported in flat file. switch (args.length) { case 4: { - newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), 0, 0, 0, "world", "your@email.com", args[0]); + newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), 0, 0, 0, "world", "your@email.com", args[0]); break; } case 7: { - newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), "world", "your@email.com", args[0]); + newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), "world", "your@email.com", args[0]); break; } case 8: { - newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], "your@email.com", args[0]); + newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], "your@email.com", args[0]); break; } case 9: { - newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], args[8], args[0]); + newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], args[8], args[0]); break; } default: { - newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], 0, 0, 0, 0, "world", "your@email.com", args[0]); + newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], 0, 0, 0, 0, "world", "your@email.com", args[0]); break; } } @@ -600,18 +601,6 @@ public class FlatFile implements DataSource { return true; } - /** - * Method updateSalt. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth) - */ - @Override - public boolean updateSalt(PlayerAuth auth) { - return false; - } - /** * Method getAllAuthsByName. * diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 7135d6ad..245c6934 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -6,7 +6,9 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.StringUtils; import java.sql.*; import java.util.ArrayList; @@ -284,13 +286,14 @@ public class MySQL implements DataSource { if (!rs.next()) { return null; } - String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : ""; - int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; + String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null; + String hash = rs.getString(columnPassword); + int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; int id = rs.getInt(columnID); pAuth = PlayerAuth.builder() .name(rs.getString(columnName)) .realName(rs.getString(columnRealName)) - .hash(rs.getString(columnPassword)) + .hash(new EncryptedPassword(hash, salt)) .lastLogin(rs.getLong(columnLastLogin)) .ip(rs.getString(columnIp)) .locWorld(rs.getString(lastlocWorld)) @@ -298,7 +301,6 @@ public class MySQL implements DataSource { .locY(rs.getDouble(lastlocY)) .locZ(rs.getDouble(lastlocZ)) .email(rs.getString(columnEmail)) - .salt(salt) .groupId(group) .build(); rs.close(); @@ -328,7 +330,7 @@ public class MySQL implements DataSource { ResultSet rs; String sql; - boolean useSalt = !columnSalt.isEmpty() || !auth.getSalt().isEmpty(); + boolean useSalt = !columnSalt.isEmpty() || !StringUtils.isEmpty(auth.getPassword().getSalt()); sql = "INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnRealName @@ -336,12 +338,12 @@ public class MySQL implements DataSource { + ") VALUES (?,?,?,?,?" + (useSalt ? ",?" : "") + ");"; pst = con.prepareStatement(sql); pst.setString(1, auth.getNickname()); - pst.setString(2, auth.getHash()); + pst.setString(2, auth.getPassword().getHash()); pst.setString(3, auth.getIp()); pst.setLong(4, auth.getLastLogin()); pst.setString(5, auth.getRealName()); if (useSalt) { - pst.setString(6, auth.getSalt()); + pst.setString(6, auth.getPassword().getSalt()); } pst.executeUpdate(); pst.close(); @@ -513,10 +515,22 @@ public class MySQL implements DataSource { @Override public synchronized boolean updatePassword(PlayerAuth auth) { try (Connection con = getConnection()) { - String sql = "UPDATE " + tableName + " SET " + columnPassword + "=? WHERE " + columnName + "=?;"; - PreparedStatement pst = con.prepareStatement(sql); - pst.setString(1, auth.getHash()); - pst.setString(2, auth.getNickname()); + boolean useSalt = !columnSalt.isEmpty(); + PreparedStatement pst; + if (useSalt) { + String sql = String.format("UPDATE %s SET %s = ?, %s = ? WHERE %s = ?;", + tableName, columnPassword, columnSalt, columnName); + pst = con.prepareStatement(sql); + pst.setString(1, auth.getPassword().getHash()); + pst.setString(2, auth.getPassword().getSalt()); + pst.setString(3, auth.getNickname()); + } else { + String sql = String.format("UPDATE %s SET %s = ? WHERE %s = ?;", + tableName, columnPassword, columnName); + pst = con.prepareStatement(sql); + pst.setString(1, auth.getPassword().getHash()); + pst.setString(2, auth.getNickname()); + } pst.executeUpdate(); pst.close(); return true; @@ -719,35 +733,6 @@ public class MySQL implements DataSource { return false; } - /** - * Method updateSalt. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth) - */ - @Override - public synchronized boolean updateSalt(PlayerAuth auth) { - if (columnSalt.isEmpty()) { - return false; - } - try (Connection con = getConnection()) { - String sql = "UPDATE " + tableName + " SET " + columnSalt + " =? WHERE " + columnName + "=?;"; - PreparedStatement pst = con.prepareStatement(sql); - pst.setString(1, auth.getSalt()); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - pst.close(); - return true; - } catch (SQLException ex) { - ConsoleLogger.showError(ex.getMessage()); - ConsoleLogger.writeStackTrace(ex); - } - return false; - } - /** * Method reload. * @@ -1045,12 +1030,12 @@ public class MySQL implements DataSource { ResultSet rs = st.executeQuery("SELECT * FROM " + tableName); PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;"); while (rs.next()) { - String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : ""; - int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; + String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null; + int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; PlayerAuth pAuth = PlayerAuth.builder() .name(rs.getString(columnName)) .realName(rs.getString(columnRealName)) - .hash(rs.getString(columnPassword)) + .hash(new EncryptedPassword(rs.getString(columnPassword), salt)) .lastLogin(rs.getLong(columnLastLogin)) .ip(rs.getString(columnIp)) .locWorld(rs.getString(lastlocWorld)) @@ -1058,7 +1043,6 @@ public class MySQL implements DataSource { .locY(rs.getDouble(lastlocY)) .locZ(rs.getDouble(lastlocZ)) .email(rs.getString(columnEmail)) - .salt(salt) .groupId(group) .build(); @@ -1089,12 +1073,12 @@ public class MySQL implements DataSource { ResultSet rs = st.executeQuery("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;"); while (rs.next()) { - String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : ""; - int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; + String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null; + int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; PlayerAuth pAuth = PlayerAuth.builder() .name(rs.getString(columnName)) .realName(rs.getString(columnRealName)) - .hash(rs.getString(columnPassword)) + .hash(new EncryptedPassword(rs.getString(columnPassword), salt)) .lastLogin(rs.getLong(columnLastLogin)) .ip(rs.getString(columnIp)) .locWorld(rs.getString(lastlocWorld)) @@ -1102,7 +1086,6 @@ public class MySQL implements DataSource { .locY(rs.getDouble(lastlocY)) .locZ(rs.getDouble(lastlocZ)) .email(rs.getString(columnEmail)) - .salt(salt) .groupId(group) .build(); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 9c4301ae..590dd6bf 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -2,6 +2,7 @@ package fr.xephi.authme.datasource; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import java.sql.*; @@ -174,15 +175,7 @@ public class SQLite implements DataSource { pst.setString(1, user); rs = pst.executeQuery(); if (rs.next()) { - if (rs.getString(columnIp).isEmpty()) { - return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "192.168.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } else { - if (!columnSalt.isEmpty()) { - return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } else { - return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } - } + return buildAuthFromResultSet(rs); } else { return null; } @@ -206,21 +199,25 @@ public class SQLite implements DataSource { public synchronized boolean saveAuth(PlayerAuth auth) { PreparedStatement pst = null; try { - if (columnSalt.isEmpty() && auth.getSalt().isEmpty()) { - pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);"); + EncryptedPassword password = auth.getPassword(); + if (columnSalt.isEmpty() && password.getSalt().isEmpty()) { + pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + + "," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);"); pst.setString(1, auth.getNickname()); - pst.setString(2, auth.getHash()); + pst.setString(2, password.getHash()); pst.setString(3, auth.getIp()); pst.setLong(4, auth.getLastLogin()); pst.setString(5, auth.getRealName()); pst.executeUpdate(); } else { - pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnSalt + "," + columnRealName + ") VALUES (?,?,?,?,?,?);"); + pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + + columnIp + "," + columnLastLogin + "," + columnSalt + "," + columnRealName + + ") VALUES (?,?,?,?,?,?);"); pst.setString(1, auth.getNickname()); - pst.setString(2, auth.getHash()); + pst.setString(2, password.getHash()); pst.setString(3, auth.getIp()); pst.setLong(4, auth.getLastLogin()); - pst.setString(5, auth.getSalt()); + pst.setString(5, password.getSalt()); pst.setString(6, auth.getRealName()); pst.executeUpdate(); } @@ -244,9 +241,19 @@ public class SQLite implements DataSource { public synchronized boolean updatePassword(PlayerAuth auth) { PreparedStatement pst = null; try { - pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnPassword + "=? WHERE " + columnName + "=?;"); - pst.setString(1, auth.getHash()); - pst.setString(2, auth.getNickname()); + EncryptedPassword password = auth.getPassword(); + boolean useSalt = !columnSalt.isEmpty(); + String sql = "UPDATE " + tableName + " SET " + columnPassword + " = ?" + + (useSalt ? ", " + columnSalt + " = ?" : "") + + " WHERE " + columnName + " = ?"; + pst = con.prepareStatement(sql); + pst.setString(1, password.getHash()); + if (useSalt) { + pst.setString(2, password.getSalt()); + pst.setString(3, auth.getNickname()); + } else { + pst.setString(2, auth.getNickname()); + } pst.executeUpdate(); } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); @@ -398,6 +405,7 @@ public class SQLite implements DataSource { ResultSet rs = null; int countIp = 0; try { + // TODO ljacqu 20151230: Simply fetch COUNT(1) and return that pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); pst.setString(1, ip); rs = pst.executeQuery(); @@ -438,33 +446,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method updateSalt. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth) - */ - @Override - public boolean updateSalt(PlayerAuth auth) { - if (columnSalt.isEmpty()) { - return false; - } - PreparedStatement pst = null; - try { - pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnSalt + "=? WHERE " + columnName + "=?;"); - pst.setString(1, auth.getSalt()); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - } catch (SQLException ex) { - ConsoleLogger.showError(ex.getMessage()); - return false; - } finally { - close(pst); - } - return true; - } - /** * Method close. * @@ -761,14 +742,6 @@ public class SQLite implements DataSource { return result; } - /** - * Method updateName. - * - * @param oldOne String - * @param newOne String - * - * @see fr.xephi.authme.datasource.DataSource#updateName(String, String) - */ @Override public void updateName(String oldOne, String newOne) { PreparedStatement pst = null; @@ -787,7 +760,7 @@ public class SQLite implements DataSource { /** * Method getAllAuths. * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuths() + * @return List */ @Override public List getAllAuths() { @@ -798,17 +771,8 @@ public class SQLite implements DataSource { pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth; - if (rs.getString(columnIp).isEmpty()) { - pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } else { - if (!columnSalt.isEmpty()) { - pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } else { - pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } - } - auths.add(pAuth); + PlayerAuth auth = buildAuthFromResultSet(rs); + auths.add(auth); } } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); @@ -822,7 +786,7 @@ public class SQLite implements DataSource { /** * Method getLoggedPlayers. * - * @return List * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers() + * @return List */ @Override public List getLoggedPlayers() { @@ -833,17 +797,8 @@ public class SQLite implements DataSource { pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); rs = pst.executeQuery(); while (rs.next()) { - PlayerAuth pAuth; - if (rs.getString(columnIp).isEmpty()) { - pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } else { - if (!columnSalt.isEmpty()) { - pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } else { - pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName)); - } - } - auths.add(pAuth); + PlayerAuth auth = buildAuthFromResultSet(rs); + auths.add(auth); } } catch (SQLException ex) { ConsoleLogger.showError(ex.getMessage()); @@ -853,4 +808,25 @@ public class SQLite implements DataSource { } return auths; } + + private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { + String salt = !columnSalt.isEmpty() ? row.getString(columnSalt) : null; + + PlayerAuth.Builder authBuilder = PlayerAuth.builder() + .name(row.getString(columnName)) + .email(row.getString(columnEmail)) + .realName(row.getString(columnRealName)) + .hash(row.getString(columnPassword), salt) + .lastLogin(row.getLong(columnLastLogin)) + .locX(row.getDouble(lastlocX)) + .locY(row.getDouble(lastlocY)) + .locZ(row.getDouble(lastlocZ)) + .locWorld(row.getString(lastlocWorld)); + + String ip = row.getString(columnIp); + if (!ip.isEmpty()) { + authBuilder.ip(ip); + } + return authBuilder.build(); + } } diff --git a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java index 3202f45d..731de626 100644 --- a/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java +++ b/src/main/java/fr/xephi/authme/hooks/BungeeCordMessage.java @@ -7,6 +7,7 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.security.crypts.EncryptedPassword; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; @@ -65,10 +66,8 @@ public class BungeeCordMessage implements PluginMessageListener { + " has registered out from one of your server!"); } else if ("changepassword".equals(act)) { final String password = args[2]; - auth.setHash(password); - if (args.length == 4) { - auth.setSalt(args[3]); - } + final String salt = args.length >= 4 ? args[3] : null; + auth.setPassword(new EncryptedPassword(password, salt)); PlayerCache.getInstance().updatePlayer(auth); dataSource.updatePassword(auth); } 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 0d99d04c..a4d8d299 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -8,7 +8,6 @@ import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent; import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; @@ -138,7 +137,7 @@ public class AsynchronousLogin { String email = pAuth.getEmail(); boolean passwordVerified = forceLogin || plugin.getPasswordSecurity() - .comparePassword(password, pAuth.getHash(), pAuth.getSalt(), realName); + .comparePassword(password, pAuth.getPassword(), realName); if (passwordVerified && player.isOnline()) { PlayerAuth auth = PlayerAuth.builder() @@ -147,8 +146,7 @@ public class AsynchronousLogin { .ip(getIP()) .lastLogin(new Date().getTime()) .email(email) - .hash(pAuth.getHash()) - .salt(pAuth.getSalt()) + .hash(pAuth.getPassword()) .build(); database.updateSession(auth); diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index 9796dbb0..13baacae 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -8,7 +8,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import org.bukkit.entity.Player; @@ -97,12 +97,11 @@ public class AsyncRegister { m.send(player, MessageKey.MAX_REGISTER_EXCEEDED); return; } - final HashResult hashResult = plugin.getPasswordSecurity().computeHash(password, name); + final EncryptedPassword encryptedPassword = plugin.getPasswordSecurity().computeHash(password, name); PlayerAuth auth = PlayerAuth.builder() .name(name) .realName(player.getName()) - .hash(hashResult.getHash()) - .salt(hashResult.getSalt()) + .hash(encryptedPassword) .ip(ip) .locWorld(player.getLocation().getWorld().getName()) .locX(player.getLocation().getX()) @@ -124,12 +123,11 @@ public class AsyncRegister { } private void passwordRegister() throws Exception { - final HashResult hashResult = plugin.getPasswordSecurity().computeHash(password, name); + final EncryptedPassword encryptedPassword = plugin.getPasswordSecurity().computeHash(password, name); PlayerAuth auth = PlayerAuth.builder() .name(name) .realName(player.getName()) - .hash(hashResult.getHash()) - .salt(hashResult.getSalt()) + .hash(encryptedPassword) .ip(ip) .locWorld(player.getLocation().getWorld().getName()) .locX(player.getLocation().getX()) diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java index 1545552e..58c17694 100644 --- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java +++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java @@ -55,7 +55,7 @@ public class AsynchronousUnregister { public void process() { PlayerAuth cachedAuth = PlayerCache.getInstance().getAuth(name); if (force || plugin.getPasswordSecurity().comparePassword( - password, cachedAuth.getHash(), cachedAuth.getSalt(), player.getName())) { + password, cachedAuth.getPassword(), player.getName())) { if (!plugin.getDataSource().removeAuth(name)) { m.send(player, MessageKey.ERROR); return; diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 678396b5..9ea1ccfa 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -3,12 +3,10 @@ package fr.xephi.authme.security; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.PasswordEncryptionEvent; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.security.crypts.EncryptionMethod; -import fr.xephi.authme.security.crypts.HashResult; import org.bukkit.Bukkit; -import java.util.HashMap; - /** * Manager class for password-related operations. */ @@ -24,48 +22,53 @@ public class PasswordSecurity { this.supportOldAlgorithm = supportOldAlgorithm; } - public HashResult computeHash(String password, String playerName) { + public EncryptedPassword computeHash(String password, String playerName) { return computeHash(algorithm, password, playerName); } - public HashResult computeHash(HashAlgorithm algorithm, String password, String playerName) { + public EncryptedPassword computeHash(HashAlgorithm algorithm, String password, String playerName) { EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); return method.computeHash(password, playerName); } public boolean comparePassword(String password, String playerName) { + // TODO ljacqu 20151230: Defining a dataSource.getPassword() method would be more efficient PlayerAuth auth = dataSource.getAuth(playerName); if (auth != null) { - return comparePassword(auth.getHash(), auth.getSalt(), password, playerName); + return comparePassword(password, auth.getPassword(), playerName); } return false; } - public boolean comparePassword(String hash, String salt, String password, String playerName) { + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) { EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); // User is not in data source, so the result will invariably be wrong because an encryption // method with hasSeparateSalt() == true NEEDS the salt to evaluate the password + String salt = encryptedPassword.getSalt(); if (method.hasSeparateSalt() && salt == null) { return false; } - return method.comparePassword(hash, password, salt, playerName) - || supportOldAlgorithm && compareWithAllEncryptionMethods(password, hash, salt, playerName); + + return method.comparePassword(password, encryptedPassword, playerName) + || supportOldAlgorithm && compareWithAllEncryptionMethods(password, encryptedPassword, playerName); } /** - * Compare the given hash with all available encryption methods to support the migration to a new encryption method. + * Compare the given hash with all available encryption methods to support + * the migration to a new encryption method. Upon a successful match, the password + * will be hashed with the new encryption method and persisted. * - * @param password The clear-text password to check - * @param hash The hash to text the password against - * @param salt The salt (or null if none available) - * @param playerName The name of the player + * @param password The clear-text password to check + * @param encryptedPassword The encrypted password to test the clear-text password against + * @param playerName The name of the player * @return True if the */ - private boolean compareWithAllEncryptionMethods(String password, String hash, String salt, String playerName) { + private boolean compareWithAllEncryptionMethods(String password, EncryptedPassword encryptedPassword, + String playerName) { for (HashAlgorithm algorithm : HashAlgorithm.values()) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) { EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm); - if (method != null && method.comparePassword(hash, password, salt, playerName)) { + if (method != null && method.comparePassword(password, encryptedPassword, playerName)) { hashPasswordForNewAlgorithm(password, playerName); return true; } @@ -75,8 +78,8 @@ public class PasswordSecurity { } /** - * Get the encryption method from the given {@link HashAlgorithm} value and emits a - * {@link PasswordEncryptionEvent}. The encryption method from the event is returned, + * Get the encryption method from the given {@link HashAlgorithm} value and emit a + * {@link PasswordEncryptionEvent}. The encryption method from the event is then returned, * which may have been changed by an external listener. * * @param algorithm The algorithm to retrieve the encryption method for @@ -110,14 +113,10 @@ public class PasswordSecurity { private void hashPasswordForNewAlgorithm(String password, String playerName) { PlayerAuth auth = dataSource.getAuth(playerName); if (auth != null) { - HashResult hashResult = initializeEncryptionMethod(algorithm, playerName) + EncryptedPassword encryptedPassword = initializeEncryptionMethod(algorithm, playerName) .computeHash(password, playerName); - - // TODO #358: updatePassword() should just take the HashResult..., or at least hash & salt. Idem for setHash - auth.setSalt(hashResult.getSalt()); - auth.setHash(hashResult.getHash()); + auth.setPassword(encryptedPassword); dataSource.updatePassword(auth); - dataSource.updateSalt(auth); } } diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java index 3c0bc785..6b660d7b 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java +++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java @@ -520,14 +520,14 @@ public class BCRYPT implements EncryptionMethod { } @Override - public HashResult computeHash(String password, String name) { + public EncryptedPassword computeHash(String password, String name) { String salt = generateSalt(); - return new HashResult(hashpw(password, salt), null); + return new EncryptedPassword(hashpw(password, salt), null); } @Override - public boolean comparePassword(String hash, String password, String salt, String name) { - return checkpw(password, hash); + public boolean comparePassword(String password, EncryptedPassword hash, String name) { + return checkpw(password, hash.getHash()); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT2Y.java b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT2Y.java index 664b3c93..57f3894f 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT2Y.java +++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT2Y.java @@ -15,11 +15,13 @@ public class BCRYPT2Y extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { + public boolean comparePassword(String password, EncryptedPassword encrypted, String unusedName) { + String hash = encrypted.getHash(); if (hash.length() != 60) { return false; } // The salt is the first 29 characters of the hash + String salt = hash.substring(0, 29); return hash.equals(computeHash(password, salt, null)); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java b/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java index c5d0cd13..73fae5db 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java @@ -28,11 +28,11 @@ public class CRAZYCRYPT1 extends UsernameSaltMethod { } @Override - public HashResult computeHash(String password, String name) { + public EncryptedPassword computeHash(String password, String name) { final String text = "ÜÄaeut//&/=I " + password + "7421€547" + name + "__+IÄIH§%NK " + password; final MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.SHA512); md.update(text.getBytes(charset), 0, text.length()); - return new HashResult(byteArrayToHexString(md.digest())); + return new EncryptedPassword(byteArrayToHexString(md.digest())); } } diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java index 2742d0b2..a3f2ea39 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java @@ -20,8 +20,8 @@ public class CryptPBKDF2 extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { - String[] line = hash.split("\\$"); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String unusedName) { + String[] line = encryptedPassword.getHash().split("\\$"); String salt = line[2]; String derivedKey = line[3]; PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes()); diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java index 3c9b5d60..e16b4c77 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java @@ -19,8 +19,8 @@ public class CryptPBKDF2Django extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { - String[] line = hash.split("\\$"); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String unusedName) { + String[] line = encryptedPassword.getHash().split("\\$"); String salt = line[2]; byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]); PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000, derivedKey); diff --git a/src/main/java/fr/xephi/authme/security/crypts/HashResult.java b/src/main/java/fr/xephi/authme/security/crypts/EncryptedPassword.java similarity index 89% rename from src/main/java/fr/xephi/authme/security/crypts/HashResult.java rename to src/main/java/fr/xephi/authme/security/crypts/EncryptedPassword.java index 767a3a0c..3425801c 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/HashResult.java +++ b/src/main/java/fr/xephi/authme/security/crypts/EncryptedPassword.java @@ -3,7 +3,7 @@ package fr.xephi.authme.security.crypts; /** * The result of a hash computation. See {@link #salt} for details. */ -public class HashResult { +public class EncryptedPassword { /** The generated hash. */ private final String hash; @@ -23,7 +23,7 @@ public class HashResult { * @param hash The computed hash * @param salt The generated salt */ - public HashResult(String hash, String salt) { + public EncryptedPassword(String hash, String salt) { this.hash = hash; this.salt = salt; } @@ -33,7 +33,7 @@ public class HashResult { * * @param hash The computed hash */ - public HashResult(String hash) { + public EncryptedPassword(String hash) { this(hash, null); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java index efc98b66..9381113c 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java @@ -12,9 +12,9 @@ public interface EncryptionMethod { * @param name The name of the player (sometimes required to generate a salt with) * * @return The hash result for the password. - * @see HashResult + * @see EncryptedPassword */ - HashResult computeHash(String password, String name); + EncryptedPassword computeHash(String password, String name); /** * Hash the given password with the given salt for the given player. @@ -31,14 +31,13 @@ public interface EncryptionMethod { /** * Check whether the given hash matches the clear-text password. * - * @param hash The hash to verify - * @param password The clear-text password to verify the hash against - * @param salt The salt if it is stored separately (null otherwise) - * @param name The player name to do the check for (sometimes required for generating the salt) + * @param password The clear-text password to verify + * @param encryptedPassword The hash to check the password against + * @param name The player name to do the check for (sometimes required for generating the salt) * * @return True if the password matches, false otherwise */ - boolean comparePassword(String hash, String password, String salt, String name); + boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name); /** * Generate a new salt to hash a password with. @@ -49,7 +48,7 @@ public interface EncryptionMethod { /** * Return whether the encryption method requires the salt to be stored separately and - * passed again to {@link #comparePassword(String, String, String, String)}. Note that + * passed again to {@link #comparePassword(String, EncryptedPassword, String)}. Note that * an encryption method returning {@code false} does not imply that it uses no salt; it * may be embedded into the hash or it may use the username as salt. * 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 25443420..2427e431 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java @@ -20,13 +20,13 @@ public abstract class HexSaltedMethod implements EncryptionMethod { public abstract String computeHash(String password, String salt, String name); @Override - public HashResult computeHash(String password, String name) { + public EncryptedPassword computeHash(String password, String name) { String salt = generateSalt(); - return new HashResult(computeHash(password, salt, null)); + return new EncryptedPassword(computeHash(password, salt, null)); } @Override - public abstract boolean comparePassword(String hash, String password, String salt, String name); + public abstract boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name); @Override public String generateSalt() { diff --git a/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java b/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java index 7abc0536..4e42958f 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java +++ b/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java @@ -13,7 +13,8 @@ public class JOOMLA extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String unusedName) { + String hash = encryptedPassword.getHash(); String[] hashParts = hash.split(":"); return hashParts.length == 2 && hash.equals(computeHash(password, hashParts[1], null)); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/MD5VB.java b/src/main/java/fr/xephi/authme/security/crypts/MD5VB.java index 8fb92e60..39a08b7f 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/MD5VB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/MD5VB.java @@ -10,7 +10,8 @@ public class MD5VB extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String name) { + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) { + String hash = encryptedPassword.getHash(); String[] line = hash.split("\\$"); return line.length == 4 && hash.equals(computeHash(password, line[2], name)); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java index 753f419a..c7d85b6a 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/PHPBB.java @@ -144,8 +144,8 @@ public class PHPBB extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String name) { - return phpbb_check_hash(password, hash); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) { + return phpbb_check_hash(password, encryptedPassword.getHash()); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/SHA256.java b/src/main/java/fr/xephi/authme/security/crypts/SHA256.java index cc28507c..efe2c8dd 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/SHA256.java +++ b/src/main/java/fr/xephi/authme/security/crypts/SHA256.java @@ -14,7 +14,8 @@ public class SHA256 extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String playerName) { + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) { + String hash = encryptedPassword.getHash(); String[] line = hash.split("\\$"); return line.length == 4 && hash.equals(computeHash(password, line[2], "")); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/SMF.java b/src/main/java/fr/xephi/authme/security/crypts/SMF.java index 10361811..c1d33661 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/SMF.java +++ b/src/main/java/fr/xephi/authme/security/crypts/SMF.java @@ -4,8 +4,8 @@ import fr.xephi.authme.security.HashUtils; public class SMF extends UsernameSaltMethod { - public HashResult computeHash(String password, String name) { - return new HashResult(HashUtils.sha1(name.toLowerCase() + password)); + public EncryptedPassword computeHash(String password, String name) { + return new EncryptedPassword(HashUtils.sha1(name.toLowerCase() + password)); } } diff --git a/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java b/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java index c0b2f070..c7402fcc 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java @@ -12,14 +12,14 @@ public abstract class SeparateSaltMethod implements EncryptionMethod { public abstract String generateSalt(); @Override - public HashResult computeHash(String password, String name) { + public EncryptedPassword computeHash(String password, String name) { String salt = generateSalt(); - return new HashResult(computeHash(password, salt, name), salt); + return new EncryptedPassword(computeHash(password, salt, name), salt); } @Override - public boolean comparePassword(String hash, String password, String salt, String name) { - return hash.equals(computeHash(password, salt, null)); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) { + return encryptedPassword.getHash().equals(computeHash(password, encryptedPassword.getSalt(), null)); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java b/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java index b6949a72..6900b80f 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java @@ -15,8 +15,8 @@ public abstract class UnsaltedMethod implements EncryptionMethod { public abstract String computeHash(String password); @Override - public HashResult computeHash(String password, String name) { - return new HashResult(computeHash(password)); + public EncryptedPassword computeHash(String password, String name) { + return new EncryptedPassword(computeHash(password)); } @Override @@ -25,8 +25,8 @@ public abstract class UnsaltedMethod implements EncryptionMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String name) { - return hash.equals(computeHash(password)); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) { + return encryptedPassword.getHash().equals(computeHash(password)); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java b/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java index 1d294713..c7b46b11 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java +++ b/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java @@ -7,18 +7,18 @@ import fr.xephi.authme.security.crypts.description.Usage; /** * Common supertype of encryption methods that use a player's username - * (or something based on it) as salt. + * (or something based on it) as embedded salt. */ @Recommendation(Usage.DO_NOT_USE) @HasSalt(SaltType.USERNAME) public abstract class UsernameSaltMethod implements EncryptionMethod { @Override - public abstract HashResult computeHash(String password, String name); + public abstract EncryptedPassword computeHash(String password, String name); @Override - public boolean comparePassword(String hash, String password, String salt, String name) { - return hash.equals(computeHash(password, name).getHash()); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) { + return encryptedPassword.getHash().equals(computeHash(password, name).getHash()); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/WBB4.java b/src/main/java/fr/xephi/authme/security/crypts/WBB4.java index 5cfd954b..9f67d499 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/WBB4.java +++ b/src/main/java/fr/xephi/authme/security/crypts/WBB4.java @@ -12,8 +12,8 @@ public class WBB4 extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String playerName) { - return BCRYPT.checkpw(password, hash, 2); + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) { + return BCRYPT.checkpw(password, encryptedPassword.getHash(), 2); } @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java b/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java index d1e6a9dc..5b198056 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java +++ b/src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java @@ -117,7 +117,8 @@ public class WORDPRESS extends UnsaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String name) { + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) { + String hash = encryptedPassword.getHash(); String comparedHash = crypt(password, hash); return comparedHash.equals(hash); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java b/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java index f0ce068d..ff5236bd 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java +++ b/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java @@ -23,7 +23,8 @@ public class XAUTH extends HexSaltedMethod { } @Override - public boolean comparePassword(String hash, String password, String salt, String playerName) { + public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) { + String hash = encryptedPassword.getHash(); int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length()); String saltFromHash = hash.substring(saltPos, saltPos + 12); return hash.equals(computeHash(password, saltFromHash, null)); diff --git a/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java b/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java index 1b2f75ff..d85149b6 100644 --- a/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java +++ b/src/main/java/fr/xephi/authme/task/ChangePasswordTask.java @@ -9,7 +9,7 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashResult; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.settings.Settings; import org.bukkit.entity.Player; @@ -34,22 +34,21 @@ public class ChangePasswordTask implements Runnable { final String name = player.getName().toLowerCase(); PlayerAuth auth = PlayerCache.getInstance().getAuth(name); - if (passwordSecurity.comparePassword(oldPassword, auth.getHash(), auth.getSalt(), player.getName())) { - HashResult hashResult = passwordSecurity.computeHash(newPassword, name); - auth.setHash(hashResult.getHash()); - auth.setSalt(hashResult.getSalt()); + if (passwordSecurity.comparePassword(oldPassword, auth.getPassword(), player.getName())) { + EncryptedPassword encryptedPassword = passwordSecurity.computeHash(newPassword, name); + auth.setPassword(encryptedPassword); if (!plugin.getDataSource().updatePassword(auth)) { m.send(player, MessageKey.ERROR); return; } - plugin.getDataSource().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(); + final String hash = encryptedPassword.getHash(); + final String salt = encryptedPassword.getSalt(); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable(){ @Override diff --git a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java index 35e3b577..c5cfea95 100644 --- a/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/security/HashAlgorithmIntegrationTest.java @@ -1,7 +1,7 @@ package fr.xephi.authme.security; +import fr.xephi.authme.security.crypts.EncryptedPassword; import fr.xephi.authme.security.crypts.EncryptionMethod; -import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.WrapperMock; @@ -49,11 +49,11 @@ public class HashAlgorithmIntegrationTest { for (HashAlgorithm algorithm : HashAlgorithm.values()) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) { EncryptionMethod method = algorithm.getClazz().newInstance(); - HashResult hashResult = method.computeHash("pwd", "name"); + EncryptedPassword encryptedPassword = method.computeHash("pwd", "name"); assertThat("Salt should not be null if method.hasSeparateSalt(), and vice versa. Method: '" - + method + "'", StringUtils.isEmpty(hashResult.getSalt()), equalTo(!method.hasSeparateSalt())); + + method + "'", StringUtils.isEmpty(encryptedPassword.getSalt()), equalTo(!method.hasSeparateSalt())); assertThat("Hash should not be empty for method '" + method + "'", - StringUtils.isEmpty(hashResult.getHash()), equalTo(false)); + StringUtils.isEmpty(encryptedPassword.getHash()), equalTo(false)); } } } diff --git a/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java b/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java index ad3d183f..cb81164b 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java @@ -36,47 +36,42 @@ public abstract class AbstractEncryptionMethodTest { /** The encryption method to test. */ private EncryptionMethod method; /** Map with the hashes against which the entries in GIVEN_PASSWORDS are tested. */ - private Map hashes; - /** The accompanying salts for the hashes in {@link #hashes} if necessary. Can be empty otherwise. */ - private Map salts; + private Map hashes; /** * Create a new test for the given encryption method. * * @param method The encryption method to test - * @param hash0 The pre-generated hash for the first {@link #GIVEN_PASSWORDS} - * @param hash1 The pre-generated hash for the second {@link #GIVEN_PASSWORDS} - * @param hash2 The pre-generated hash for the third {@link #GIVEN_PASSWORDS} - * @param hash3 The pre-generated hash for the fourth {@link #GIVEN_PASSWORDS} + * @param computedHashes The pre-generated hashes for the elements in {@link #GIVEN_PASSWORDS} */ - public AbstractEncryptionMethodTest(EncryptionMethod method, String hash0, String hash1, - String hash2, String hash3) { - // TODO #358: Throw if method.hasSeparateSalt() is true + public AbstractEncryptionMethodTest(EncryptionMethod method, String... computedHashes) { + if (method.hasSeparateSalt()) { + throw new UnsupportedOperationException("Test must be initialized with EncryptedPassword objects if " + + "the salt is stored separately. Use the other constructor"); + } else if (computedHashes.length != GIVEN_PASSWORDS.length) { + throw new UnsupportedOperationException("Expected " + GIVEN_PASSWORDS.length + " hashes"); + } this.method = method; + hashes = new HashMap<>(); - hashes.put(GIVEN_PASSWORDS[0], hash0); - hashes.put(GIVEN_PASSWORDS[1], hash1); - hashes.put(GIVEN_PASSWORDS[2], hash2); - hashes.put(GIVEN_PASSWORDS[3], hash3); - salts = new HashMap<>(); + for (int i = 0; i < GIVEN_PASSWORDS.length; ++i) { + hashes.put(GIVEN_PASSWORDS[i], new EncryptedPassword(computedHashes[i])); + } } - public AbstractEncryptionMethodTest(EncryptionMethod method, HashResult result0, HashResult result1, - HashResult result2, HashResult result3) { - // TODO #358: Throw if method.hasSeparateSalt() is false + public AbstractEncryptionMethodTest(EncryptionMethod method, EncryptedPassword result0, EncryptedPassword result1, + EncryptedPassword result2, EncryptedPassword result3) { + if (!method.hasSeparateSalt()) { + throw new UnsupportedOperationException("Salt is not stored separately, so test should be initialized" + + " with the password hashes only. Use the other constructor"); + } this.method = method; hashes = new HashMap<>(); - hashes.put(GIVEN_PASSWORDS[0], result0.getHash()); - hashes.put(GIVEN_PASSWORDS[1], result1.getHash()); - hashes.put(GIVEN_PASSWORDS[2], result2.getHash()); - hashes.put(GIVEN_PASSWORDS[3], result3.getHash()); - - salts = new HashMap<>(); - salts.put(GIVEN_PASSWORDS[0], result0.getSalt()); - salts.put(GIVEN_PASSWORDS[1], result1.getSalt()); - salts.put(GIVEN_PASSWORDS[2], result2.getSalt()); - salts.put(GIVEN_PASSWORDS[3], result3.getSalt()); + hashes.put(GIVEN_PASSWORDS[0], result0); + hashes.put(GIVEN_PASSWORDS[1], result1); + hashes.put(GIVEN_PASSWORDS[2], result2); + hashes.put(GIVEN_PASSWORDS[3], result3); } @Test @@ -108,6 +103,7 @@ public abstract class AbstractEncryptionMethodTest { for (String password : internalPasswords) { final String salt = method.generateSalt(); final String hash = method.computeHash(password, salt, USERNAME); + EncryptedPassword encryptedPassword = new EncryptedPassword(hash, salt); // Check that the computeHash(password, salt, name) method has the same output for the returned salt if (testHashEqualityForSameSalt()) { @@ -116,22 +112,20 @@ public abstract class AbstractEncryptionMethodTest { } assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')", - method.comparePassword(hash, password, salt, USERNAME)); + method.comparePassword(password, encryptedPassword, USERNAME)); if (!password.equals(password.toLowerCase())) { assertFalse("Lower-case of '" + password + "' should not match generated hash '" + hash + "'", - method.comparePassword(hash, password.toLowerCase(), salt, USERNAME)); + method.comparePassword(password.toLowerCase(), encryptedPassword, USERNAME)); } if (!password.equals(password.toUpperCase())) { assertFalse("Upper-case of '" + password + "' should not match generated hash '" + hash + "'", - method.comparePassword(hash, password.toUpperCase(), salt, USERNAME)); + method.comparePassword(password.toUpperCase(), encryptedPassword, USERNAME)); } } } private boolean doesGivenHashMatch(String password, EncryptionMethod method) { - String hash = hashes.get(password); - String salt = salts.get(password); - return method.comparePassword(hash, password, salt, USERNAME); + return method.comparePassword(password, hashes.get(password), USERNAME); } // @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); } @@ -150,9 +144,9 @@ public abstract class AbstractEncryptionMethodTest { } if (method.hasSeparateSalt()) { - HashResult hashResult = method.computeHash(password, USERNAME); - System.out.println(String.format("\t\tnew HashResult(\"%s\", \"%s\")%s// %s", - hashResult.getHash(), hashResult.getSalt(), delim, password)); + EncryptedPassword encryptedPassword = method.computeHash(password, USERNAME); + System.out.println(String.format("\t\tnew EncryptedPassword(\"%s\", \"%s\")%s// %s", + encryptedPassword.getHash(), encryptedPassword.getSalt(), delim, password)); } else { System.out.println("\t\t\"" + method.computeHash(password, USERNAME).getHash() + "\"" + delim + "// " + password); diff --git a/src/test/java/fr/xephi/authme/security/crypts/IPB3Test.java b/src/test/java/fr/xephi/authme/security/crypts/IPB3Test.java index 53d3e4e1..0752b984 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/IPB3Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/IPB3Test.java @@ -7,10 +7,10 @@ public class IPB3Test extends AbstractEncryptionMethodTest { public IPB3Test() { super(new IPB3(), - new HashResult("f8ecea1ce42b5babef369ff7692dbe3f", "1715b"), //password - new HashResult("40a93731a931352e0619cdf09b975040", "ba91c"), //PassWord1 - new HashResult("a77ca982373946d5800430bd2947ba11", "a7725"), //&^%te$t?Pw@_ - new HashResult("383d7b9e2b707d6e894ec7b30e3032c3", "fa9fd")); //âË_3(íù* + new EncryptedPassword("f8ecea1ce42b5babef369ff7692dbe3f", "1715b"), //password + new EncryptedPassword("40a93731a931352e0619cdf09b975040", "ba91c"), //PassWord1 + new EncryptedPassword("a77ca982373946d5800430bd2947ba11", "a7725"), //&^%te$t?Pw@_ + new EncryptedPassword("383d7b9e2b707d6e894ec7b30e3032c3", "fa9fd")); //âË_3(íù* } } diff --git a/src/test/java/fr/xephi/authme/security/crypts/MYBBTest.java b/src/test/java/fr/xephi/authme/security/crypts/MYBBTest.java index 2d2e965a..01e3491d 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/MYBBTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/MYBBTest.java @@ -7,10 +7,10 @@ public class MYBBTest extends AbstractEncryptionMethodTest { public MYBBTest() { super(new MYBB(), - new HashResult("57c7a16d860833db5030738f5a465d2b", "acdc14e6"), //password - new HashResult("08fbdf721f2c42d9780b7d66df0ba830", "792fd7fb"), //PassWord1 - new HashResult("d602f38fb59ad9e185d5604f5d4ddb36", "4b5534a4"), //&^%te$t?Pw@_ - new HashResult("b3c39410d0ab8ae2a65c257820797fad", "e5a6cb14")); //âË_3(íù* + new EncryptedPassword("57c7a16d860833db5030738f5a465d2b", "acdc14e6"), //password + new EncryptedPassword("08fbdf721f2c42d9780b7d66df0ba830", "792fd7fb"), //PassWord1 + new EncryptedPassword("d602f38fb59ad9e185d5604f5d4ddb36", "4b5534a4"), //&^%te$t?Pw@_ + new EncryptedPassword("b3c39410d0ab8ae2a65c257820797fad", "e5a6cb14")); //âË_3(íù* } } diff --git a/src/test/java/fr/xephi/authme/security/crypts/PHPFUSIONTest.java b/src/test/java/fr/xephi/authme/security/crypts/PHPFUSIONTest.java index fe2259d2..66641470 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/PHPFUSIONTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/PHPFUSIONTest.java @@ -7,10 +7,10 @@ public class PHPFUSIONTest extends AbstractEncryptionMethodTest { public PHPFUSIONTest() { super(new PHPFUSION(), - new HashResult("f7a606c4eb3fcfbc382906476e05b06f21234a77d1a4eacc0f93f503deb69e70", "6cd1c97c55cb"), // password - new HashResult("8a9b7bb706a3347e5f684a7cb905bfb26b9a0d099358064139ab3ed1a66aeb2b", "d6012370b73f"), // PassWord1 - new HashResult("43f2f23f44c8f89e2dbf06050bc8c77dbcdf71a7b5d28c87ec657d474e63d62d", "f75400a209a4"), // &^%te$t?Pw@_ - new HashResult("4e7f4eb7e3653d7460f1cf590def4153c6fcdf8b8e16fb95538fdf9e54a95245", "d552e0f5b23a")); // âË_3(íù* + new EncryptedPassword("f7a606c4eb3fcfbc382906476e05b06f21234a77d1a4eacc0f93f503deb69e70", "6cd1c97c55cb"), // password + new EncryptedPassword("8a9b7bb706a3347e5f684a7cb905bfb26b9a0d099358064139ab3ed1a66aeb2b", "d6012370b73f"), // PassWord1 + new EncryptedPassword("43f2f23f44c8f89e2dbf06050bc8c77dbcdf71a7b5d28c87ec657d474e63d62d", "f75400a209a4"), // &^%te$t?Pw@_ + new EncryptedPassword("4e7f4eb7e3653d7460f1cf590def4153c6fcdf8b8e16fb95538fdf9e54a95245", "d552e0f5b23a")); // âË_3(íù* } } diff --git a/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java b/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java index 338238fd..56f01de3 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/SALTED2MD5Test.java @@ -17,10 +17,10 @@ public class SALTED2MD5Test extends AbstractEncryptionMethodTest { public SALTED2MD5Test() { super(new SALTED2MD5(), - new HashResult("9f3d13dc01a6fe61fd669954174399f3", "9b5f5749"), // password - new HashResult("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"), // PassWord1 - new HashResult("38dcb83cc68424afe3cda012700c2bb1", "eb2c3394"), // &^%te$t?Pw@_ - new HashResult("ad25606eae5b760c8a2469d65578ac39", "04eee598")); // âË_3(íù*) + new EncryptedPassword("9f3d13dc01a6fe61fd669954174399f3", "9b5f5749"), // password + new EncryptedPassword("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"), // PassWord1 + new EncryptedPassword("38dcb83cc68424afe3cda012700c2bb1", "eb2c3394"), // &^%te$t?Pw@_ + new EncryptedPassword("ad25606eae5b760c8a2469d65578ac39", "04eee598")); // âË_3(íù*) } } diff --git a/src/test/java/fr/xephi/authme/security/crypts/SALTEDSHA512Test.java b/src/test/java/fr/xephi/authme/security/crypts/SALTEDSHA512Test.java index f88984e9..f2976cc6 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/SALTEDSHA512Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/SALTEDSHA512Test.java @@ -7,10 +7,10 @@ public class SALTEDSHA512Test extends AbstractEncryptionMethodTest { public SALTEDSHA512Test() { super(new SALTEDSHA512(), - new HashResult("dea7a37cecf5384ae8e347fd1411efb51364b6ba1b328695de3b354612c1d7010807e8b7051c40f740e498490e1f133e2c2408327d13fbdd68e1b1f6d548e624", "29f8a3c52147f987fee7ba3e0fb311bd"), // password - new HashResult("7c06225aac574d2dc7c81a2ed306637adf025715f52083e05bdab014faaa234e24a97d0e69ea0108dfa77cc9228e58be319ee677e679b5d1ad168d40e50a42f6", "8ea37b85d020b98f60c0fe9b8ec9296c"), // PassWord1 - new HashResult("55711adbe03c9616f3505f0d57077fdd528c32243eb6f9840c1a6ff9e553940d6b89790750ebd52ebda63ca793fbe9980d54057af40836820c648750fe22d49c", "9f58079631ef21d32b4710694f1f461b"), // &^%te$t?Pw@_ - new HashResult("29dc5be8702975ea4563ed3de5b145e2d2f1c37ae661bbe0d3e94d964402cf09d539d65f3b90ff6921ea3d40727f76fb38fb34d1e5c2d62238c4e0203efc372f", "048bb76168265d906f1fd1f81d0616a9")); // âË_3(íù* + new EncryptedPassword("dea7a37cecf5384ae8e347fd1411efb51364b6ba1b328695de3b354612c1d7010807e8b7051c40f740e498490e1f133e2c2408327d13fbdd68e1b1f6d548e624", "29f8a3c52147f987fee7ba3e0fb311bd"), // password + new EncryptedPassword("7c06225aac574d2dc7c81a2ed306637adf025715f52083e05bdab014faaa234e24a97d0e69ea0108dfa77cc9228e58be319ee677e679b5d1ad168d40e50a42f6", "8ea37b85d020b98f60c0fe9b8ec9296c"), // PassWord1 + new EncryptedPassword("55711adbe03c9616f3505f0d57077fdd528c32243eb6f9840c1a6ff9e553940d6b89790750ebd52ebda63ca793fbe9980d54057af40836820c648750fe22d49c", "9f58079631ef21d32b4710694f1f461b"), // &^%te$t?Pw@_ + new EncryptedPassword("29dc5be8702975ea4563ed3de5b145e2d2f1c37ae661bbe0d3e94d964402cf09d539d65f3b90ff6921ea3d40727f76fb38fb34d1e5c2d62238c4e0203efc372f", "048bb76168265d906f1fd1f81d0616a9")); // âË_3(íù* } } diff --git a/src/test/java/fr/xephi/authme/security/crypts/WBB3Test.java b/src/test/java/fr/xephi/authme/security/crypts/WBB3Test.java index 3851cb4e..2a5d685f 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/WBB3Test.java +++ b/src/test/java/fr/xephi/authme/security/crypts/WBB3Test.java @@ -7,10 +7,10 @@ public class WBB3Test extends AbstractEncryptionMethodTest { public WBB3Test() { super(new WBB3(), - new HashResult("8df818ef7d56075ab2744f74b98ad68a375ccac4", "b7415b355492ea60314f259a35733a3092c03e3f"), // password - new HashResult("106da5cf5df92cb845e12cf62cbdb5235b6dc693", "6110f19b2b52910dccf592a19c59126873f42e69"), // PassWord1 - new HashResult("940a9fb7acec0178c6691e8b3c14bd7d789078b1", "f9dd501ff3d1bf74904f9e89649e378429af56e7"), // &^%te$t?Pw@_ - new HashResult("0fa12e8d96c9e95f73aa91f3b76f8cdc815ec8a5", "736be8669f6159ddb2d5b47a3e6428cdb8b324de")); // âË_3(íù* + new EncryptedPassword("8df818ef7d56075ab2744f74b98ad68a375ccac4", "b7415b355492ea60314f259a35733a3092c03e3f"), // password + new EncryptedPassword("106da5cf5df92cb845e12cf62cbdb5235b6dc693", "6110f19b2b52910dccf592a19c59126873f42e69"), // PassWord1 + new EncryptedPassword("940a9fb7acec0178c6691e8b3c14bd7d789078b1", "f9dd501ff3d1bf74904f9e89649e378429af56e7"), // &^%te$t?Pw@_ + new EncryptedPassword("0fa12e8d96c9e95f73aa91f3b76f8cdc815ec8a5", "736be8669f6159ddb2d5b47a3e6428cdb8b324de")); // âË_3(íù* } }