mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-18 16:25:11 +01:00
Merge pull request #85 from AuthMe-Team/358-encryptn-mthd-refactor
358 encryptn mthd refactor
This commit is contained in:
commit
9343cfe9da
@ -82,8 +82,6 @@ typing commands or using the inventory. It can also kick players with uncommonly
|
||||
<li>MyBB: MYBB</li>
|
||||
<li>IPB3: IPB3</li>
|
||||
<li>PhpFusion: PHPFUSION</li>
|
||||
<li><del>Xenforo SHA1: XFSHA1</del> <strong>(Deprecated)</strong></li>
|
||||
<li><del>Xenforo SHA256: XFSHA256</del> <strong>(Deprecated)</strong></li>
|
||||
<li>Joomla: JOOMLA</li>
|
||||
<li>WBB3: WBB3*</li>
|
||||
<li>SHA512: SHA512</li>
|
||||
@ -92,7 +90,7 @@ typing commands or using the inventory. It can also kick players with uncommonly
|
||||
</ul></li>
|
||||
<li>Custom MySQL tables/columns names (useful with forums databases)</li>
|
||||
<li><strong>Cached database queries!</strong></li>
|
||||
<li><strong>Full compatible with Citizens2, CombatTag, CombatTagPlus and ChestShop!</strong></li>
|
||||
<li><strong>Fully compatible with Citizens2, CombatTag, CombatTagPlus and ChestShop!</strong></li>
|
||||
<li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li>
|
||||
<li>Restricted users (associate a Username with an IP)</li>
|
||||
<li>Protect player's inventory until a correct Authentication</li>
|
||||
@ -120,7 +118,7 @@ typing commands or using the inventory. It can also kick players with uncommonly
|
||||
</li><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/">Website Integration</a>
|
||||
</li><li><a href="https://raw.githubusercontent.com/Xephi/AuthMeReloaded/master/src/main/resources/config.yml">Click here for an example of the Config file</a>
|
||||
</li><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-rakamak/">How to convert from Rakamak</a>
|
||||
</li><li>Convert from FlatFile (auths.db but not the sqlite one ) to MySQL: /converter
|
||||
</li><li>Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /converter
|
||||
</li></ul>
|
||||
<hr>
|
||||
|
||||
@ -139,5 +137,5 @@ GameHosting.it is leader in Italy as Game Server Provider. With its own DataCent
|
||||
|
||||
#####Credits
|
||||
<p>Team members: look at the <a href="https://github.com/AuthMe-Team/AuthMeReloaded/blob/master/team.txt">team.txt file</a>
|
||||
<p>Credit for old version of the plugin to: d4rkwarriors, fabe1337 , Whoami2 and pomo4ka</p>
|
||||
<p>Credit for old version of the plugin to: d4rkwarriors, fabe1337, Whoami2 and pomo4ka</p>
|
||||
<p>Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex</p>
|
||||
|
@ -43,6 +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.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.OtherAccounts;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.Spawn;
|
||||
@ -101,12 +102,13 @@ public class AuthMe extends JavaPlugin {
|
||||
private Messages messages;
|
||||
private JsonCache playerBackup;
|
||||
private ModuleManager moduleManager;
|
||||
private PasswordSecurity passwordSecurity;
|
||||
private DataSource database;
|
||||
|
||||
// Public Instances
|
||||
public NewAPI api;
|
||||
public SendMailSSL mail;
|
||||
public DataManager dataManager;
|
||||
public DataSource database;
|
||||
public OtherAccounts otherAccounts;
|
||||
public Location essentialsSpawn;
|
||||
|
||||
@ -192,7 +194,6 @@ public class AuthMe extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* Method called when the server enables the plugin.
|
||||
* @see org.bukkit.plugin.Plugin#onEnable()
|
||||
*/
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@ -209,12 +210,26 @@ public class AuthMe extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up messages
|
||||
// Set up messages & password security
|
||||
messages = Messages.getInstance();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
passwordSecurity = new PasswordSecurity(getDataSource(), Settings.getPasswordHash,
|
||||
Bukkit.getPluginManager(), Settings.supportOldPassword);
|
||||
|
||||
// Set up the permissions manager and command handler
|
||||
permsMan = initializePermissionsManager();
|
||||
commandHandler = initializeCommandHandler(permsMan, messages);
|
||||
commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity);
|
||||
|
||||
// Set up the module manager
|
||||
setupModuleManager();
|
||||
@ -256,16 +271,7 @@ public class AuthMe extends JavaPlugin {
|
||||
// Do a backup on 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
|
||||
playerBackup = new JsonCache();
|
||||
@ -412,11 +418,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);
|
||||
Set<CommandDescription> baseCommands = CommandInitializer.buildCommands();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -506,11 +513,6 @@ public class AuthMe extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method onDisable.
|
||||
*
|
||||
* @see org.bukkit.plugin.Plugin#onDisable()
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
// Save player data
|
||||
@ -525,7 +527,9 @@ public class AuthMe extends JavaPlugin {
|
||||
new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.STOP);
|
||||
|
||||
// Unload modules
|
||||
moduleManager.unloadModules();
|
||||
if (moduleManager != null) {
|
||||
moduleManager.unloadModules();
|
||||
}
|
||||
|
||||
// Close the database
|
||||
if (database != null) {
|
||||
@ -539,16 +543,13 @@ public class AuthMe extends JavaPlugin {
|
||||
// Stop/unload the server/plugin as defined in the configuration
|
||||
public void stopOrUnload() {
|
||||
if (Settings.isStopEnabled) {
|
||||
ConsoleLogger.showError("THE SERVER IS GOING TO SHUTDOWN AS DEFINED IN THE CONFIGURATION!");
|
||||
ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!");
|
||||
server.shutdown();
|
||||
} else {
|
||||
server.getPluginManager().disablePlugin(AuthMe.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setupDatabase.
|
||||
*/
|
||||
public void setupDatabase() throws Exception {
|
||||
if (database != null)
|
||||
database.close();
|
||||
@ -574,14 +575,15 @@ public class AuthMe extends JavaPlugin {
|
||||
int accounts = database.getAccountsRegistered();
|
||||
if (accounts >= 4000) {
|
||||
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) {
|
||||
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);
|
||||
DataSource source = converter.run();
|
||||
if (source != null) {
|
||||
@ -590,12 +592,13 @@ public class AuthMe extends JavaPlugin {
|
||||
}
|
||||
|
||||
// TODO: Move this to another place maybe ?
|
||||
if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT)
|
||||
{
|
||||
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");
|
||||
for (PlayerAuth auth : database.getAllAuths())
|
||||
{
|
||||
auth.setHash(PasswordSecurity.getHash(HashAlgorithm.SHA256, auth.getHash(), auth.getNickname()));
|
||||
if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT) {
|
||||
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()) {
|
||||
EncryptedPassword encryptedPassword = passwordSecurity.computeHash(
|
||||
HashAlgorithm.SHA256, auth.getPassword().getHash(), auth.getNickname());
|
||||
auth.setPassword(encryptedPassword);
|
||||
database.updatePassword(auth);
|
||||
}
|
||||
Settings.setValue("settings.security.passwordHash", "SHA256");
|
||||
@ -720,8 +723,8 @@ public class AuthMe extends JavaPlugin {
|
||||
}
|
||||
|
||||
// Save Player Data
|
||||
public void savePlayer(Player player) {
|
||||
if ((Utils.isNPC(player)) || (Utils.isUnrestricted(player))) {
|
||||
private void savePlayer(Player player) {
|
||||
if (Utils.isNPC(player) || Utils.isUnrestricted(player)) {
|
||||
return;
|
||||
}
|
||||
String name = player.getName().toLowerCase();
|
||||
@ -836,10 +839,10 @@ public class AuthMe extends JavaPlugin {
|
||||
|
||||
// Return the AuthMe spawn point
|
||||
private Location getAuthMeSpawn(Player player) {
|
||||
if ((!database.isAuthAvailable(player.getName().toLowerCase()) || !player.hasPlayedBefore()) && (Spawn.getInstance().getFirstSpawn() != null)) {
|
||||
if ((!database.isAuthAvailable(player.getName().toLowerCase()) || !player.hasPlayedBefore())
|
||||
&& (Spawn.getInstance().getFirstSpawn() != null)) {
|
||||
return Spawn.getInstance().getFirstSpawn();
|
||||
}
|
||||
if (Spawn.getInstance().getSpawn() != null) {
|
||||
} else if (Spawn.getInstance().getSpawn() != null) {
|
||||
return Spawn.getInstance().getSpawn();
|
||||
}
|
||||
return player.getWorld().getSpawnLocation();
|
||||
@ -889,8 +892,7 @@ public class AuthMe extends JavaPlugin {
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public void getVerygamesIp(final Player player)
|
||||
{
|
||||
public void getVerygamesIp(final Player player) {
|
||||
final String name = player.getName().toLowerCase();
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable(){
|
||||
@Override
|
||||
@ -986,4 +988,12 @@ public class AuthMe extends JavaPlugin {
|
||||
return management;
|
||||
}
|
||||
|
||||
public DataSource getDataSource() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public PasswordSecurity getPasswordSecurity() {
|
||||
return passwordSecurity;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +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.settings.Settings;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -12,34 +12,37 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Deprecated API of AuthMe. Please use {@link NewAPI} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class API {
|
||||
|
||||
public static final String newline = System.getProperty("line.separator");
|
||||
public static AuthMe instance;
|
||||
private static PasswordSecurity passwordSecurity;
|
||||
|
||||
/**
|
||||
* Constructor for API.
|
||||
* Constructor for the deprecated API.
|
||||
*
|
||||
* @param instance AuthMe
|
||||
*/
|
||||
@Deprecated
|
||||
public API(AuthMe instance) {
|
||||
API.instance = instance;
|
||||
passwordSecurity = instance.getPasswordSecurity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook into AuthMe
|
||||
* Hook into AuthMe.
|
||||
*
|
||||
* @return AuthMe instance
|
||||
*/
|
||||
@Deprecated
|
||||
public static AuthMe hookAuthMe() {
|
||||
if (instance != null)
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
Plugin plugin = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
|
||||
if (plugin == null || !(plugin instanceof AuthMe)) {
|
||||
return null;
|
||||
@ -49,9 +52,10 @@ public class API {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* Return whether the player is authenticated.
|
||||
*
|
||||
* @return true if player is authenticate
|
||||
* @param player The player to verify
|
||||
* @return true if the player is authenticated
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isAuthenticated(Player player) {
|
||||
@ -59,8 +63,9 @@ public class API {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* Return whether the player is unrestricted.
|
||||
*
|
||||
* @param player The player to verify
|
||||
* @return true if the player is unrestricted
|
||||
*/
|
||||
@Deprecated
|
||||
@ -68,13 +73,6 @@ public class API {
|
||||
return Utils.isUnrestricted(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getLastLocation.
|
||||
*
|
||||
* @param player Player
|
||||
*
|
||||
* @return Location
|
||||
*/
|
||||
@Deprecated
|
||||
public static Location getLastLocation(Player player) {
|
||||
try {
|
||||
@ -92,13 +90,6 @@ public class API {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setPlayerInventory.
|
||||
*
|
||||
* @param player Player
|
||||
* @param content ItemStack[]
|
||||
* @param armor ItemStack[]
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setPlayerInventory(Player player, ItemStack[] content,
|
||||
ItemStack[] armor) {
|
||||
@ -110,93 +101,72 @@ public class API {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerName
|
||||
* Check whether the given player name is registered.
|
||||
*
|
||||
* @param playerName The player name to verify
|
||||
* @return true if player is registered
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isRegistered(String playerName) {
|
||||
String player = playerName.toLowerCase();
|
||||
return instance.database.isAuthAvailable(player);
|
||||
return instance.getDataSource().isAuthAvailable(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerName String
|
||||
* @param passwordToCheck String
|
||||
* Check the password for the given player.
|
||||
*
|
||||
* @return true if the password is correct , false else
|
||||
* @param playerName The name of the player
|
||||
* @param passwordToCheck The password to check
|
||||
* @return true if the password is correct, false otherwise
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean checkPassword(String playerName,
|
||||
String passwordToCheck) {
|
||||
if (!isRegistered(playerName))
|
||||
return false;
|
||||
String player = playerName.toLowerCase();
|
||||
PlayerAuth auth = instance.database.getAuth(player);
|
||||
try {
|
||||
return PasswordSecurity.comparePasswordWithHash(passwordToCheck, auth.getHash(), playerName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return false;
|
||||
}
|
||||
public static boolean checkPassword(String playerName, String passwordToCheck) {
|
||||
return isRegistered(playerName) && passwordSecurity.comparePassword(passwordToCheck, playerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a player
|
||||
* Register a player.
|
||||
*
|
||||
* @param playerName String
|
||||
* @param password String
|
||||
*
|
||||
* @return true if the player is register correctly
|
||||
* @param playerName The name of the player
|
||||
* @param password The password
|
||||
* @return true if the player was registered correctly
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean registerPlayer(String playerName, String password) {
|
||||
try {
|
||||
String name = playerName.toLowerCase();
|
||||
String hash = PasswordSecurity.getHash(Settings.getPasswordHash, password, name);
|
||||
if (isRegistered(name)) {
|
||||
return false;
|
||||
}
|
||||
PlayerAuth auth = new PlayerAuth(name, hash, "198.18.0.1", 0, "your@email.com", playerName);
|
||||
return instance.database.saveAuth(auth);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
String name = playerName.toLowerCase();
|
||||
EncryptedPassword encryptedPassword = passwordSecurity.computeHash(password, name);
|
||||
if (isRegistered(name)) {
|
||||
return false;
|
||||
}
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(name)
|
||||
.password(encryptedPassword)
|
||||
.lastLogin(0)
|
||||
.realName(playerName)
|
||||
.build();
|
||||
return instance.getDataSource().saveAuth(auth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a player to login
|
||||
* Force a player to log in.
|
||||
*
|
||||
* @param player * player
|
||||
* @param player The player to log in
|
||||
*/
|
||||
@Deprecated
|
||||
public static void forceLogin(Player player) {
|
||||
instance.getManagement().performLogin(player, "dontneed", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPlugin.
|
||||
*
|
||||
* @return AuthMe
|
||||
*/
|
||||
@Deprecated
|
||||
public AuthMe getPlugin() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
* Check whether the player is an NPC.
|
||||
*
|
||||
* @return true if player is a npc
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isaNPC(Player player) {
|
||||
return Utils.isNPC(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player
|
||||
*
|
||||
* @return true if player is a npc
|
||||
* @param player The player to verify
|
||||
* @return true if player is an npc
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isNPC(Player player) {
|
||||
|
@ -3,8 +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.PasswordSecurity;
|
||||
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;
|
||||
@ -12,9 +11,8 @@ import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* The current API of AuthMe.
|
||||
*/
|
||||
public class NewAPI {
|
||||
|
||||
@ -42,33 +40,36 @@ public class NewAPI {
|
||||
/**
|
||||
* Hook into AuthMe
|
||||
*
|
||||
* @return AuthMe plugin
|
||||
* @return The API object
|
||||
*/
|
||||
public static NewAPI getInstance() {
|
||||
if (singleton != null)
|
||||
if (singleton != null) {
|
||||
return singleton;
|
||||
}
|
||||
Plugin p = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
|
||||
if (p == null || !(p instanceof AuthMe)) {
|
||||
return null;
|
||||
}
|
||||
AuthMe authme = (AuthMe) p;
|
||||
singleton = (new NewAPI(authme));
|
||||
singleton = new NewAPI(authme);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPlugin.
|
||||
* Return the plugin instance.
|
||||
*
|
||||
* @return AuthMe
|
||||
* @return The AuthMe instance
|
||||
*/
|
||||
public AuthMe getPlugin() {
|
||||
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) {
|
||||
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) {
|
||||
try {
|
||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
|
||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName());
|
||||
|
||||
if (auth != null) {
|
||||
return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
|
||||
@ -115,87 +116,83 @@ public class NewAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerName
|
||||
* Return whether the player is registered.
|
||||
*
|
||||
* @return true if player is registered
|
||||
* @param playerName The player name to check
|
||||
*
|
||||
* @return true if player is registered, false otherwise
|
||||
*/
|
||||
public boolean isRegistered(String playerName) {
|
||||
String player = playerName.toLowerCase();
|
||||
return plugin.database.isAuthAvailable(player);
|
||||
return plugin.getDataSource().isAuthAvailable(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerName String
|
||||
* @param passwordToCheck String
|
||||
* Check the password for the given player.
|
||||
*
|
||||
* @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) {
|
||||
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 isRegistered(playerName) && plugin.getPasswordSecurity().comparePassword(passwordToCheck, playerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a player
|
||||
* Register a player.
|
||||
*
|
||||
* @param playerName String
|
||||
* @param password String
|
||||
* @param playerName The player to register
|
||||
* @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) {
|
||||
try {
|
||||
String name = playerName.toLowerCase();
|
||||
String hash = PasswordSecurity.getHash(Settings.getPasswordHash, password, 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) {
|
||||
String name = playerName.toLowerCase();
|
||||
EncryptedPassword result = plugin.getPasswordSecurity().computeHash(password, name);
|
||||
if (isRegistered(name)) {
|
||||
return false;
|
||||
}
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(name)
|
||||
.password(result)
|
||||
.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) {
|
||||
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) {
|
||||
plugin.getManagement().performLogout(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a player to register
|
||||
* Force a player to register.
|
||||
*
|
||||
* @param player * player
|
||||
* @param password String
|
||||
* @param player The player to register
|
||||
* @param password The password to use
|
||||
*/
|
||||
public void forceRegister(Player player, String password) {
|
||||
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) {
|
||||
plugin.getManagement().performUnregister(player, "", true);
|
||||
|
@ -1,11 +1,10 @@
|
||||
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 org.bukkit.Location;
|
||||
|
||||
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 +12,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 +39,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 +53,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 +67,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 +81,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 +95,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 +112,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 +132,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 +149,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 +192,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 +303,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 +311,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);
|
||||
+ " ! Password : {" + password.getHash() + ", " + password.getSalt() + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -472,8 +333,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 +353,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 +369,7 @@ public class PlayerAuth {
|
||||
public static final class Builder {
|
||||
private String name;
|
||||
private String realName;
|
||||
private String hash;
|
||||
private String salt;
|
||||
private EncryptedPassword password;
|
||||
private String ip;
|
||||
private String world;
|
||||
private String email;
|
||||
@ -523,8 +382,7 @@ public class PlayerAuth {
|
||||
public PlayerAuth build() {
|
||||
return new PlayerAuth(
|
||||
checkNotNull(name),
|
||||
nullToEmpty(hash),
|
||||
nullToEmpty(salt),
|
||||
firstNonNull(password, new EncryptedPassword("")),
|
||||
groupId,
|
||||
firstNonNull(ip, "127.0.0.1"),
|
||||
lastLogin,
|
||||
@ -545,14 +403,13 @@ public class PlayerAuth {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder hash(String hash) {
|
||||
this.hash = hash;
|
||||
public Builder password(EncryptedPassword password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder salt(String salt) {
|
||||
this.salt = salt;
|
||||
return this;
|
||||
public Builder password(String hash, String salt) {
|
||||
return password(new EncryptedPassword(hash, salt));
|
||||
}
|
||||
|
||||
public Builder ip(String ip) {
|
||||
@ -560,6 +417,14 @@ public class PlayerAuth {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder location(Location location) {
|
||||
this.x = location.getX();
|
||||
this.y = location.getY();
|
||||
this.z = location.getZ();
|
||||
this.world = location.getWorld().getName();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder locWorld(String world) {
|
||||
this.world = world;
|
||||
return this;
|
||||
|
@ -7,6 +7,7 @@ import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.process.Management;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
@ -21,6 +22,7 @@ public class CommandService {
|
||||
private final Messages messages;
|
||||
private final HelpProvider helpProvider;
|
||||
private final CommandMapper commandMapper;
|
||||
private final PasswordSecurity passwordSecurity;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -30,11 +32,13 @@ public class CommandService {
|
||||
* @param helpProvider Help provider
|
||||
* @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.messages = messages;
|
||||
this.helpProvider = helpProvider;
|
||||
this.commandMapper = commandMapper;
|
||||
this.passwordSecurity = passwordSecurity;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,8 +92,16 @@ public class CommandService {
|
||||
* @return The used data source
|
||||
*/
|
||||
public DataSource getDataSource() {
|
||||
// TODO ljacqu 20151222: Add getter for .database and rename the field to dataSource
|
||||
return authMe.database;
|
||||
return authMe.getDataSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PasswordSecurity instance.
|
||||
*
|
||||
* @return The password security instance
|
||||
*/
|
||||
public PasswordSecurity getPasswordSecurity() {
|
||||
return passwordSecurity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
@ -8,13 +7,10 @@ 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.output.Messages;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -60,13 +56,6 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
|
||||
@Override
|
||||
public void run() {
|
||||
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;
|
||||
if (PlayerCache.getInstance().isAuthenticated(playerNameLowerCase)) {
|
||||
auth = PlayerCache.getInstance().getAuth(playerNameLowerCase);
|
||||
@ -77,17 +66,17 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
|
||||
commandService.send(sender, MessageKey.UNKNOWN_USER);
|
||||
return;
|
||||
}
|
||||
auth.setHash(hash);
|
||||
if (PasswordSecurity.userSalt.containsKey(playerNameLowerCase)) {
|
||||
auth.setSalt(PasswordSecurity.userSalt.get(playerNameLowerCase));
|
||||
commandService.getDataSource().updateSalt(auth);
|
||||
}
|
||||
|
||||
// TODO #358: Do we always pass lowercase name?? In that case we need to do that in PasswordSecurity!
|
||||
EncryptedPassword encryptedPassword = commandService.getPasswordSecurity().computeHash(playerPass, playerNameLowerCase);
|
||||
auth.setPassword(encryptedPassword);
|
||||
|
||||
if (!dataSource.updatePassword(auth)) {
|
||||
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");
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -24,7 +24,7 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand {
|
||||
}
|
||||
|
||||
// Purge the banned players
|
||||
plugin.database.purgeBanned(bannedPlayers);
|
||||
plugin.getDataSource().purgeBanned(bannedPlayers);
|
||||
if (Settings.purgeEssentialsFile && plugin.ess != null)
|
||||
plugin.dataManager.purgeEssentials(bannedPlayers);
|
||||
if (Settings.purgePlayerDat)
|
||||
|
@ -5,12 +5,11 @@ 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.PasswordSecurity;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -41,7 +40,8 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
||||
commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -53,30 +53,29 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) {
|
||||
commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
|
||||
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);
|
||||
if (commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) {
|
||||
commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
|
||||
return;
|
||||
}
|
||||
EncryptedPassword encryptedPassword = commandService.getPasswordSecurity()
|
||||
.computeHash(playerPass, playerNameLowerCase);
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(playerNameLowerCase)
|
||||
.realName(playerName)
|
||||
.password(encryptedPassword)
|
||||
.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");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class CaptchaCommand extends PlayerCommand {
|
||||
|
||||
if (Settings.useCaptcha && !captcha.equals(plugin.cap.get(playerNameLowerCase))) {
|
||||
plugin.cap.remove(playerNameLowerCase);
|
||||
String randStr = new RandomString(Settings.captchaLength).nextString();
|
||||
String randStr = RandomString.generate(Settings.captchaLength);
|
||||
plugin.cap.put(playerNameLowerCase, randStr);
|
||||
commandService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, plugin.cap.get(playerNameLowerCase));
|
||||
return;
|
||||
|
@ -1,20 +1,18 @@
|
||||
package fr.xephi.authme.command.executable.email;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
import fr.xephi.authme.command.CommandService;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
public class RecoverEmailCommand extends PlayerCommand {
|
||||
@ -37,37 +35,32 @@ public class RecoverEmailCommand extends PlayerCommand {
|
||||
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
RandomString rand = new RandomString(Settings.getRecoveryPassLength);
|
||||
String thePass = rand.nextString();
|
||||
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")
|
||||
|| auth.getEmail().equalsIgnoreCase("your@email.com")) {
|
||||
commandService.send(player, MessageKey.INVALID_EMAIL);
|
||||
return;
|
||||
}
|
||||
auth.setHash(hashNew);
|
||||
dataSource.updatePassword(auth);
|
||||
plugin.mail.main(auth, thePass);
|
||||
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
||||
} catch (NoSuchAlgorithmException | NoClassDefFoundError ex) {
|
||||
ConsoleLogger.showError(StringUtils.formatException(ex));
|
||||
commandService.send(player, MessageKey.ERROR);
|
||||
String thePass = RandomString.generate(Settings.getRecoveryPassLength);
|
||||
EncryptedPassword hashNew = commandService.getPasswordSecurity().computeHash(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 (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.setPassword(hashNew);
|
||||
dataSource.updatePassword(auth);
|
||||
plugin.mail.main(auth, thePass);
|
||||
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
||||
} else {
|
||||
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class CrazyLoginConverter implements Converter {
|
||||
* @param sender CommandSender
|
||||
*/
|
||||
public CrazyLoginConverter(AuthMe instance, CommandSender sender) {
|
||||
this.database = instance.database;
|
||||
this.database = instance.getDataSource();
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
|
@ -6,6 +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.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@ -13,7 +14,6 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@ -28,15 +28,12 @@ public class RakamakConverter implements Converter {
|
||||
|
||||
public RakamakConverter(AuthMe instance, CommandSender sender) {
|
||||
this.instance = instance;
|
||||
this.database = instance.database;
|
||||
this.database = instance.getDataSource();
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public RakamakConverter getInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
// TODO ljacqu 20151229: Restructure this into smaller portions
|
||||
public void run() {
|
||||
HashAlgorithm hash = Settings.getPasswordHash;
|
||||
boolean useIP = Settings.rakamakUseIp;
|
||||
@ -45,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<String, String> playerIP = new HashMap<>();
|
||||
HashMap<String, String> playerPSW = new HashMap<>();
|
||||
HashMap<String, EncryptedPassword> playerPSW = new HashMap<>();
|
||||
try {
|
||||
BufferedReader users;
|
||||
BufferedReader ipFile;
|
||||
@ -61,30 +58,29 @@ public class RakamakConverter implements Converter {
|
||||
}
|
||||
}
|
||||
ipFile.close();
|
||||
|
||||
users = new BufferedReader(new FileReader(source));
|
||||
PasswordSecurity passwordSecurity = instance.getPasswordSecurity();
|
||||
while ((line = users.readLine()) != null) {
|
||||
if (line.contains("=")) {
|
||||
String[] arguments = line.split("=");
|
||||
try {
|
||||
playerPSW.put(arguments[0], PasswordSecurity.getHash(hash, arguments[1], arguments[0]));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
ConsoleLogger.showError(e.getMessage());
|
||||
}
|
||||
EncryptedPassword encryptedPassword = passwordSecurity.computeHash(hash, arguments[1], arguments[0]);
|
||||
playerPSW.put(arguments[0], encryptedPassword);
|
||||
|
||||
}
|
||||
}
|
||||
users.close();
|
||||
for (Entry<String, String> m : playerPSW.entrySet()) {
|
||||
for (Entry<String, EncryptedPassword> m : playerPSW.entrySet()) {
|
||||
String playerName = m.getKey();
|
||||
String psw = playerPSW.get(playerName);
|
||||
String ip;
|
||||
if (useIP) {
|
||||
ip = playerIP.get(playerName);
|
||||
} else {
|
||||
ip = "127.0.0.1";
|
||||
}
|
||||
PlayerAuth auth = new PlayerAuth(playerName, psw, ip, System.currentTimeMillis(), playerName);
|
||||
if (PasswordSecurity.userSalt.containsKey(playerName))
|
||||
auth.setSalt(PasswordSecurity.userSalt.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)
|
||||
.password(psw)
|
||||
.lastLogin(System.currentTimeMillis())
|
||||
.build();
|
||||
database.saveAuth(auth);
|
||||
}
|
||||
ConsoleLogger.info("Rakamak database has been imported correctly");
|
||||
|
@ -15,7 +15,7 @@ public class RoyalAuthConverter implements Converter {
|
||||
|
||||
public RoyalAuthConverter(AuthMe plugin) {
|
||||
this.plugin = plugin;
|
||||
this.data = plugin.database;
|
||||
this.data = plugin.getDataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,16 +21,14 @@ public class SqliteToSql implements Converter {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (plugin.database.getType() != DataSourceType.MYSQL)
|
||||
{
|
||||
if (plugin.getDataSource().getType() != DataSourceType.MYSQL) {
|
||||
sender.sendMessage("Please config your mySQL connection and re-run this command");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SQLite data = new SQLite();
|
||||
for (PlayerAuth auth : data.getAllAuths())
|
||||
{
|
||||
plugin.database.saveAuth(auth);
|
||||
for (PlayerAuth auth : data.getAllAuths()) {
|
||||
plugin.getDataSource().saveAuth(auth);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
sender.sendMessage(plugin.getMessages().retrieve(MessageKey.ERROR));
|
||||
|
@ -23,7 +23,7 @@ class vAuthFileReader {
|
||||
*/
|
||||
public vAuthFileReader(AuthMe plugin) {
|
||||
this.plugin = plugin;
|
||||
this.database = plugin.database;
|
||||
this.database = plugin.getDataSource();
|
||||
}
|
||||
|
||||
public void convert() {
|
||||
|
@ -30,7 +30,7 @@ class xAuthToFlat {
|
||||
*/
|
||||
public xAuthToFlat(AuthMe instance, CommandSender sender) {
|
||||
this.instance = instance;
|
||||
this.database = instance.database;
|
||||
this.database = instance.getDataSource();
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -7,6 +7,7 @@ import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.security.HashAlgorithm;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
@ -39,11 +40,6 @@ public class MySQL implements DataSource {
|
||||
private final List<String> columnOthers;
|
||||
private HikariDataSource ds;
|
||||
|
||||
/**
|
||||
* Constructor for MySQL.
|
||||
*
|
||||
* @throws ClassNotFoundException * @throws SQLException * @throws PoolInitializationException
|
||||
*/
|
||||
public MySQL() throws ClassNotFoundException, SQLException, PoolInitializationException {
|
||||
this.host = Settings.getMySQLHost;
|
||||
this.port = Settings.getMySQLPort;
|
||||
@ -96,11 +92,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setConnectionArguments.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private synchronized void setConnectionArguments() throws RuntimeException {
|
||||
ds = new HikariDataSource();
|
||||
ds.setPoolName("AuthMeMYSQLPool");
|
||||
@ -116,11 +107,6 @@ public class MySQL implements DataSource {
|
||||
ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method reloadArguments.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private synchronized void reloadArguments() throws RuntimeException {
|
||||
if (ds != null) {
|
||||
ds.close();
|
||||
@ -129,20 +115,10 @@ public class MySQL implements DataSource {
|
||||
ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getConnection.
|
||||
*
|
||||
* @return Connection * @throws SQLException
|
||||
*/
|
||||
private synchronized Connection getConnection() throws SQLException {
|
||||
return ds.getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setupConnection.
|
||||
*
|
||||
* @throws SQLException
|
||||
*/
|
||||
private synchronized void setupConnection() throws SQLException {
|
||||
try (Connection con = getConnection()) {
|
||||
Statement st = con.createStatement();
|
||||
@ -186,6 +162,15 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
rs.close();
|
||||
|
||||
if (!columnSalt.isEmpty()) {
|
||||
rs = md.getColumns(null, null, tableName, columnSalt);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + columnSalt + " VARCHAR(255);");
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
|
||||
rs = md.getColumns(null, null, tableName, columnIp);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
@ -244,13 +229,6 @@ public class MySQL implements DataSource {
|
||||
ConsoleLogger.info("MySQL Setup finished");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method isAuthAvailable.
|
||||
*
|
||||
* @param user String
|
||||
*
|
||||
* @return boolean * @see fr.xephi.authme.datasource.DataSource#isAuthAvailable(String)
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean isAuthAvailable(String user) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -266,13 +244,6 @@ public class MySQL implements DataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getAuth.
|
||||
*
|
||||
* @param user String
|
||||
*
|
||||
* @return PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getAuth(String)
|
||||
*/
|
||||
@Override
|
||||
public synchronized PlayerAuth getAuth(String user) {
|
||||
PlayerAuth pAuth;
|
||||
@ -284,13 +255,12 @@ 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;
|
||||
int id = rs.getInt(columnID);
|
||||
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
|
||||
int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
|
||||
pAuth = PlayerAuth.builder()
|
||||
.name(rs.getString(columnName))
|
||||
.realName(rs.getString(columnRealName))
|
||||
.hash(rs.getString(columnPassword))
|
||||
.password(rs.getString(columnPassword), salt)
|
||||
.lastLogin(rs.getLong(columnLastLogin))
|
||||
.ip(rs.getString(columnIp))
|
||||
.locWorld(rs.getString(lastlocWorld))
|
||||
@ -298,21 +268,10 @@ public class MySQL implements DataSource {
|
||||
.locY(rs.getDouble(lastlocY))
|
||||
.locZ(rs.getDouble(lastlocZ))
|
||||
.email(rs.getString(columnEmail))
|
||||
.salt(salt)
|
||||
.groupId(group)
|
||||
.build();
|
||||
rs.close();
|
||||
pst.close();
|
||||
if (Settings.getPasswordHash == HashAlgorithm.XENFORO) {
|
||||
pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;");
|
||||
pst.setInt(1, id);
|
||||
rs = pst.executeQuery();
|
||||
if (rs.next()) {
|
||||
Blob blob = rs.getBlob("data");
|
||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||
pAuth.setHash(new String(bytes));
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.writeStackTrace(ex);
|
||||
@ -321,15 +280,6 @@ public class MySQL implements DataSource {
|
||||
return pAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method saveAuth.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#saveAuth(PlayerAuth)
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean saveAuth(PlayerAuth auth) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -338,7 +288,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
|
||||
@ -346,12 +296,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();
|
||||
@ -502,25 +452,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
rs.close();
|
||||
pst.close();
|
||||
} else if (Settings.getPasswordHash == HashAlgorithm.XENFORO) {
|
||||
pst = con.prepareStatement("SELECT " + columnID + " FROM " + tableName + " WHERE " + columnName + "=?;");
|
||||
pst.setString(1, auth.getNickname());
|
||||
rs = pst.executeQuery();
|
||||
if (rs.next()) {
|
||||
int id = rs.getInt(columnID);
|
||||
// Insert password in the correct table
|
||||
pst2 = con.prepareStatement("INSERT INTO xf_user_authenticate (user_id, scheme_class, data) VALUES (?,?,?);");
|
||||
pst2.setInt(1, id);
|
||||
pst2.setString(2, "XenForo_Authentication_Core12");
|
||||
byte[] bytes = auth.getHash().getBytes();
|
||||
Blob blob = con.createBlob();
|
||||
blob.setBytes(1, bytes);
|
||||
pst2.setBlob(3, blob);
|
||||
pst2.executeUpdate();
|
||||
pst2.close();
|
||||
}
|
||||
rs.close();
|
||||
pst.close();
|
||||
}
|
||||
return true;
|
||||
} catch (SQLException ex) {
|
||||
@ -530,52 +461,27 @@ public class MySQL implements DataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updatePassword.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#updatePassword(PlayerAuth)
|
||||
*/
|
||||
@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();
|
||||
if (Settings.getPasswordHash == HashAlgorithm.XENFORO) {
|
||||
sql = "SELECT " + columnID + " FROM " + tableName + " WHERE " + columnName + "=?;";
|
||||
pst = con.prepareStatement(sql);
|
||||
pst.setString(1, auth.getNickname());
|
||||
ResultSet rs = pst.executeQuery();
|
||||
if (rs.next()) {
|
||||
int id = rs.getInt(columnID);
|
||||
// Insert password in the correct table
|
||||
sql = "UPDATE xf_user_authenticate SET data=? WHERE " + columnID + "=?;";
|
||||
PreparedStatement pst2 = con.prepareStatement(sql);
|
||||
byte[] bytes = auth.getHash().getBytes();
|
||||
Blob blob = con.createBlob();
|
||||
blob.setBytes(1, bytes);
|
||||
pst2.setBlob(1, blob);
|
||||
pst2.setInt(2, id);
|
||||
pst2.executeUpdate();
|
||||
pst2.close();
|
||||
// ...
|
||||
sql = "UPDATE xf_user_authenticate SET scheme_class=? WHERE " + columnID + "=?;";
|
||||
pst2 = con.prepareStatement(sql);
|
||||
pst2.setString(1, "XenForo_Authentication_Core12");
|
||||
pst2.setInt(2, id);
|
||||
pst2.executeUpdate();
|
||||
pst2.close();
|
||||
}
|
||||
rs.close();
|
||||
pst.close();
|
||||
}
|
||||
return true;
|
||||
} catch (SQLException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
@ -584,15 +490,6 @@ public class MySQL implements DataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updateSession.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#updateSession(PlayerAuth)
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean updateSession(PlayerAuth auth) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -612,15 +509,6 @@ public class MySQL implements DataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method purgeDatabase.
|
||||
*
|
||||
* @param until long
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#purgeDatabase(long)
|
||||
*/
|
||||
@Override
|
||||
public synchronized int purgeDatabase(long until) {
|
||||
int result = 0;
|
||||
@ -636,15 +524,6 @@ public class MySQL implements DataSource {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method autoPurgeDatabase.
|
||||
*
|
||||
* @param until long
|
||||
*
|
||||
* @return List
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long)
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<String> autoPurgeDatabase(long until) {
|
||||
List<String> list = new ArrayList<>();
|
||||
@ -666,37 +545,11 @@ public class MySQL implements DataSource {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method removeAuth.
|
||||
*
|
||||
* @param user String
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#removeAuth(String)
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean removeAuth(String user) {
|
||||
user = user.toLowerCase();
|
||||
try (Connection con = getConnection()) {
|
||||
String sql;
|
||||
PreparedStatement pst;
|
||||
if (Settings.getPasswordHash == HashAlgorithm.XENFORO) {
|
||||
sql = "SELECT " + columnID + " FROM " + tableName + " WHERE " + columnName + "=?;";
|
||||
pst = con.prepareStatement(sql);
|
||||
pst.setString(1, user);
|
||||
ResultSet rs = pst.executeQuery();
|
||||
if (rs.next()) {
|
||||
int id = rs.getInt(columnID);
|
||||
sql = "DELETE FROM xf_user_authenticate WHERE " + columnID + "=" + id;
|
||||
Statement st = con.createStatement();
|
||||
st.executeUpdate(sql);
|
||||
st.close();
|
||||
}
|
||||
rs.close();
|
||||
pst.close();
|
||||
}
|
||||
pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + columnName + "=?;");
|
||||
PreparedStatement pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + columnName + "=?;");
|
||||
pst.setString(1, user);
|
||||
pst.executeUpdate();
|
||||
return true;
|
||||
@ -707,15 +560,6 @@ public class MySQL implements DataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updateQuitLoc.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#updateQuitLoc(PlayerAuth)
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean updateQuitLoc(PlayerAuth auth) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -738,15 +582,6 @@ public class MySQL implements DataSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getIps.
|
||||
*
|
||||
* @param ip String
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getIps(String)
|
||||
*/
|
||||
@Override
|
||||
public synchronized int getIps(String ip) {
|
||||
int countIp = 0;
|
||||
@ -767,15 +602,6 @@ public class MySQL implements DataSource {
|
||||
return countIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updateEmail.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#updateEmail(PlayerAuth)
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean updateEmail(PlayerAuth auth) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -793,40 +619,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.
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#reload()
|
||||
*/
|
||||
@Override
|
||||
public void reload() {
|
||||
try {
|
||||
@ -839,11 +631,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method close.
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#close()
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (ds != null && !ds.isClosed()) {
|
||||
@ -851,15 +638,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getAllAuthsByName.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
*
|
||||
* @return List
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth)
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<String> getAllAuthsByName(PlayerAuth auth) {
|
||||
List<String> result = new ArrayList<>();
|
||||
@ -880,15 +658,6 @@ public class MySQL implements DataSource {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getAllAuthsByIp.
|
||||
*
|
||||
* @param ip String
|
||||
*
|
||||
* @return List
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String)
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<String> getAllAuthsByIp(String ip) {
|
||||
List<String> result = new ArrayList<>();
|
||||
@ -909,15 +678,6 @@ public class MySQL implements DataSource {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getAllAuthsByEmail.
|
||||
*
|
||||
* @param email String
|
||||
*
|
||||
* @return List
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String)
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<String> getAllAuthsByEmail(String email){
|
||||
List<String> countEmail = new ArrayList<>();
|
||||
@ -938,13 +698,6 @@ public class MySQL implements DataSource {
|
||||
return countEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method purgeBanned.
|
||||
*
|
||||
* @param banned List<String>
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#purgeBanned(List)
|
||||
*/
|
||||
@Override
|
||||
public synchronized void purgeBanned(List<String> banned) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -960,23 +713,11 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getType.
|
||||
*
|
||||
* @return DataSourceType * @see fr.xephi.authme.datasource.DataSource#getType()
|
||||
*/
|
||||
@Override
|
||||
public DataSourceType getType() {
|
||||
return DataSourceType.MYSQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method isLogged.
|
||||
*
|
||||
* @param user String
|
||||
*
|
||||
* @return boolean * @see fr.xephi.authme.datasource.DataSource#isLogged(String)
|
||||
*/
|
||||
@Override
|
||||
public boolean isLogged(String user) {
|
||||
boolean isLogged = false;
|
||||
@ -993,13 +734,6 @@ public class MySQL implements DataSource {
|
||||
return isLogged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setLogged.
|
||||
*
|
||||
* @param user String
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#setLogged(String)
|
||||
*/
|
||||
@Override
|
||||
public void setLogged(String user) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -1015,13 +749,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setUnlogged.
|
||||
*
|
||||
* @param user String
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#setUnlogged(String)
|
||||
*/
|
||||
@Override
|
||||
public void setUnlogged(String user) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -1037,11 +764,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method purgeLogged.
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#purgeLogged()
|
||||
*/
|
||||
@Override
|
||||
public void purgeLogged() {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -1057,13 +779,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getAccountsRegistered.
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getAccountsRegistered()
|
||||
*/
|
||||
@Override
|
||||
public int getAccountsRegistered() {
|
||||
int result = 0;
|
||||
@ -1082,14 +797,6 @@ public class MySQL 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) {
|
||||
try (Connection con = getConnection()) {
|
||||
@ -1104,13 +811,6 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getAllAuths.
|
||||
*
|
||||
* @return List
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getAllAuths()
|
||||
*/
|
||||
@Override
|
||||
public List<PlayerAuth> getAllAuths() {
|
||||
List<PlayerAuth> auths = new ArrayList<>();
|
||||
@ -1119,12 +819,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))
|
||||
.password(rs.getString(columnPassword), salt)
|
||||
.lastLogin(rs.getLong(columnLastLogin))
|
||||
.ip(rs.getString(columnIp))
|
||||
.locWorld(rs.getString(lastlocWorld))
|
||||
@ -1132,21 +832,9 @@ public class MySQL implements DataSource {
|
||||
.locY(rs.getDouble(lastlocY))
|
||||
.locZ(rs.getDouble(lastlocZ))
|
||||
.email(rs.getString(columnEmail))
|
||||
.salt(salt)
|
||||
.groupId(group)
|
||||
.build();
|
||||
|
||||
if (Settings.getPasswordHash == HashAlgorithm.XENFORO) {
|
||||
int id = rs.getInt(columnID);
|
||||
pst.setInt(1, id);
|
||||
ResultSet rs2 = pst.executeQuery();
|
||||
if (rs2.next()) {
|
||||
Blob blob = rs2.getBlob("data");
|
||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||
pAuth.setHash(new String(bytes));
|
||||
}
|
||||
rs2.close();
|
||||
}
|
||||
auths.add(pAuth);
|
||||
}
|
||||
pst.close();
|
||||
@ -1159,13 +847,6 @@ public class MySQL implements DataSource {
|
||||
return auths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getLoggedPlayers.
|
||||
*
|
||||
* @return List
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers()
|
||||
*/
|
||||
@Override
|
||||
public List<PlayerAuth> getLoggedPlayers() {
|
||||
List<PlayerAuth> auths = new ArrayList<>();
|
||||
@ -1174,12 +855,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))
|
||||
.password(rs.getString(columnPassword), salt)
|
||||
.lastLogin(rs.getLong(columnLastLogin))
|
||||
.ip(rs.getString(columnIp))
|
||||
.locWorld(rs.getString(lastlocWorld))
|
||||
@ -1187,21 +868,9 @@ public class MySQL implements DataSource {
|
||||
.locY(rs.getDouble(lastlocY))
|
||||
.locZ(rs.getDouble(lastlocZ))
|
||||
.email(rs.getString(columnEmail))
|
||||
.salt(salt)
|
||||
.groupId(group)
|
||||
.build();
|
||||
|
||||
if (Settings.getPasswordHash == HashAlgorithm.XENFORO) {
|
||||
int id = rs.getInt(columnID);
|
||||
pst.setInt(1, id);
|
||||
ResultSet rs2 = pst.executeQuery();
|
||||
if (rs2.next()) {
|
||||
Blob blob = rs2.getBlob("data");
|
||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||
pAuth.setHash(new String(bytes));
|
||||
}
|
||||
rs2.close();
|
||||
}
|
||||
auths.add(pAuth);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
|
@ -2,7 +2,9 @@ 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 fr.xephi.authme.util.StringUtils;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
@ -90,6 +92,13 @@ public class SQLite implements DataSource {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + columnPassword + " VARCHAR(255) NOT NULL;");
|
||||
}
|
||||
rs.close();
|
||||
if (!columnSalt.isEmpty()) {
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, columnSalt);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + columnSalt + " VARCHAR(255);");
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, columnIp);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + columnIp + " VARCHAR(40) NOT NULL;");
|
||||
@ -174,15 +183,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 +207,29 @@ 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()) {
|
||||
if (!StringUtils.isEmpty(auth.getPassword().getSalt())) {
|
||||
ConsoleLogger.showError("Warning! Detected hashed password with separate salt but the salt column "
|
||||
+ "is not set in the config!");
|
||||
}
|
||||
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 +253,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 +417,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 +458,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.
|
||||
*
|
||||
@ -611,13 +604,6 @@ public class SQLite implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method purgeBanned.
|
||||
*
|
||||
* @param banned List<String>
|
||||
*
|
||||
* @see fr.xephi.authme.datasource.DataSource#purgeBanned(List<String>)
|
||||
*/
|
||||
@Override
|
||||
public void purgeBanned(List<String> banned) {
|
||||
PreparedStatement pst = null;
|
||||
@ -761,14 +747,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 +765,7 @@ public class SQLite implements DataSource {
|
||||
/**
|
||||
* Method getAllAuths.
|
||||
*
|
||||
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getAllAuths()
|
||||
* @return List<PlayerAuth>
|
||||
*/
|
||||
@Override
|
||||
public List<PlayerAuth> getAllAuths() {
|
||||
@ -798,17 +776,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 +791,7 @@ public class SQLite implements DataSource {
|
||||
/**
|
||||
* Method getLoggedPlayers.
|
||||
*
|
||||
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers()
|
||||
* @return List<PlayerAuth>
|
||||
*/
|
||||
@Override
|
||||
public List<PlayerAuth> getLoggedPlayers() {
|
||||
@ -833,17 +802,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 +813,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))
|
||||
.password(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();
|
||||
}
|
||||
}
|
||||
|
@ -5,75 +5,41 @@ import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This event is called when we need to compare or get an hash password, for set
|
||||
* a custom EncryptionMethod
|
||||
* </p>
|
||||
* This event is called when we need to compare or hash password and allows
|
||||
* third-party listeners to change the encryption method. This is typically
|
||||
* done with the {@link fr.xephi.authme.security.HashAlgorithm#CUSTOM} setting.
|
||||
*
|
||||
* @author Xephi59
|
||||
* @version $Revision: 1.0 $
|
||||
* @see fr.xephi.authme.security.crypts.EncryptionMethod
|
||||
*/
|
||||
public class PasswordEncryptionEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private EncryptionMethod method = null;
|
||||
private String playerName = "";
|
||||
private EncryptionMethod method;
|
||||
private String playerName;
|
||||
|
||||
/**
|
||||
* Constructor for PasswordEncryptionEvent.
|
||||
*
|
||||
* @param method EncryptionMethod
|
||||
* @param playerName String
|
||||
*/
|
||||
public PasswordEncryptionEvent(EncryptionMethod method, String playerName) {
|
||||
super(false);
|
||||
this.method = method;
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getHandlerList.
|
||||
*
|
||||
* @return HandlerList
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getHandlers.
|
||||
*
|
||||
* @return HandlerList
|
||||
*/
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getMethod.
|
||||
*
|
||||
* @return EncryptionMethod
|
||||
*/
|
||||
public EncryptionMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setMethod.
|
||||
*
|
||||
* @param method EncryptionMethod
|
||||
*/
|
||||
public void setMethod(EncryptionMethod method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPlayerName.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import fr.xephi.authme.AuthMe;
|
||||
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;
|
||||
|
||||
@ -24,15 +26,6 @@ public class BungeeCordMessage implements PluginMessageListener {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method onPluginMessageReceived.
|
||||
*
|
||||
* @param channel String
|
||||
* @param player Player
|
||||
* @param message byte[]
|
||||
*
|
||||
* @see org.bukkit.plugin.messaging.PluginMessageListener#onPluginMessageReceived(String, Player, byte[])
|
||||
*/
|
||||
@Override
|
||||
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
|
||||
if (!channel.equals("BungeeCord")) {
|
||||
@ -50,21 +43,22 @@ public class BungeeCordMessage implements PluginMessageListener {
|
||||
final String[] args = str.split(";");
|
||||
final String act = args[0];
|
||||
final String name = args[1];
|
||||
final DataSource dataSource = plugin.getDataSource();
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PlayerAuth auth = plugin.database.getAuth(name);
|
||||
PlayerAuth auth = dataSource.getAuth(name);
|
||||
if (auth == null) {
|
||||
return;
|
||||
}
|
||||
if ("login".equals(act)) {
|
||||
PlayerCache.getInstance().updatePlayer(auth);
|
||||
plugin.database.setLogged(name);
|
||||
dataSource.setLogged(name);
|
||||
ConsoleLogger.info("Player " + auth.getNickname()
|
||||
+ " has logged in from one of your server!");
|
||||
} else if ("logout".equals(act)) {
|
||||
PlayerCache.getInstance().removePlayer(name);
|
||||
plugin.database.setUnlogged(name);
|
||||
dataSource.setUnlogged(name);
|
||||
ConsoleLogger.info("Player " + auth.getNickname()
|
||||
+ " has logged out from one of your server!");
|
||||
} else if ("register".equals(act)) {
|
||||
@ -72,11 +66,10 @@ 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);
|
||||
plugin.database.updatePassword(auth);
|
||||
dataSource.updatePassword(auth);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public class AuthMePlayerListener implements Listener {
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (plugin.database.isAuthAvailable(player.getName().toLowerCase())) {
|
||||
if (plugin.getDataSource().isAuthAvailable(player.getName().toLowerCase())) {
|
||||
m.send(player, MessageKey.LOGIN_MESSAGE);
|
||||
} else {
|
||||
if (Settings.emailRegistration) {
|
||||
@ -221,8 +221,9 @@ public class AuthMePlayerListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPreLogin(AsyncPlayerPreLoginEvent event) {
|
||||
PlayerAuth auth = plugin.database.getAuth(event.getName());
|
||||
if (auth != null && auth.getRealName() != null && !auth.getRealName().isEmpty() && !auth.getRealName().equals("Player") && !auth.getRealName().equals(event.getName())) {
|
||||
PlayerAuth auth = plugin.getDataSource().getAuth(event.getName());
|
||||
if (auth != null && auth.getRealName() != null && !auth.getRealName().isEmpty() &&
|
||||
!auth.getRealName().equals("Player") && !auth.getRealName().equals(event.getName())) {
|
||||
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
|
||||
event.setKickMessage("You should join using username: " + ChatColor.AQUA + auth.getRealName() +
|
||||
ChatColor.RESET + "\nnot: " + ChatColor.RED + event.getName()); // TODO: write a better message
|
||||
@ -231,7 +232,7 @@ public class AuthMePlayerListener implements Listener {
|
||||
|
||||
if (auth != null && auth.getRealName().equals("Player")) {
|
||||
auth.setRealName(event.getName());
|
||||
plugin.database.saveAuth(auth);
|
||||
plugin.getDataSource().saveAuth(auth);
|
||||
}
|
||||
|
||||
if (auth == null && Settings.enableProtection) {
|
||||
@ -302,7 +303,7 @@ public class AuthMePlayerListener implements Listener {
|
||||
}
|
||||
|
||||
final String name = player.getName().toLowerCase();
|
||||
boolean isAuthAvailable = plugin.database.isAuthAvailable(name);
|
||||
boolean isAuthAvailable = plugin.getDataSource().isAuthAvailable(name);
|
||||
|
||||
if (Settings.isKickNonRegisteredEnabled && !isAuthAvailable) {
|
||||
if (Settings.antiBotInAction) {
|
||||
@ -475,9 +476,13 @@ public class AuthMePlayerListener implements Listener {
|
||||
Player player = event.getPlayer();
|
||||
String name = player.getName().toLowerCase();
|
||||
Location spawn = plugin.getSpawnLocation(player);
|
||||
if (Settings.isSaveQuitLocationEnabled && plugin.database.isAuthAvailable(name)) {
|
||||
PlayerAuth auth = new PlayerAuth(name, spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getWorld().getName(), player.getName());
|
||||
plugin.database.updateQuitLoc(auth);
|
||||
if (Settings.isSaveQuitLocationEnabled && plugin.getDataSource().isAuthAvailable(name)) {
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(name)
|
||||
.realName(player.getName())
|
||||
.location(spawn)
|
||||
.build();
|
||||
plugin.getDataSource().updateQuitLoc(auth);
|
||||
}
|
||||
if (spawn != null && spawn.getWorld() != null) {
|
||||
event.setRespawnLocation(spawn);
|
||||
|
@ -33,7 +33,7 @@ public class Management {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new AsynchronousLogin(player, password, forceLogin, plugin, plugin.database).process();
|
||||
new AsynchronousLogin(player, password, forceLogin, plugin, plugin.getDataSource()).process();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -43,7 +43,7 @@ public class Management {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new AsynchronousLogout(player, plugin, plugin.database).process();
|
||||
new AsynchronousLogout(player, plugin, plugin.getDataSource()).process();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -53,7 +53,7 @@ public class Management {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new AsyncRegister(player, password, email, plugin, plugin.database).process();
|
||||
new AsyncRegister(player, password, email, plugin, plugin.getDataSource()).process();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -73,7 +73,7 @@ public class Management {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new AsynchronousJoin(player, plugin, plugin.database).process();
|
||||
new AsynchronousJoin(player, plugin, plugin.getDataSource()).process();
|
||||
}
|
||||
|
||||
});
|
||||
@ -84,7 +84,7 @@ public class Management {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new AsynchronousQuit(player, plugin, plugin.database, isKick).process();
|
||||
new AsynchronousQuit(player, plugin, plugin.getDataSource(), isKick).process();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -40,7 +40,7 @@ public class AsyncChangeEmail {
|
||||
|
||||
if (Settings.getmaxRegPerEmail > 0) {
|
||||
if (!plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS)
|
||||
&& plugin.database.getAllAuthsByEmail(newEmail).size() >= Settings.getmaxRegPerEmail) {
|
||||
&& plugin.getDataSource().getAllAuthsByEmail(newEmail).size() >= Settings.getmaxRegPerEmail) {
|
||||
m.send(player, MessageKey.MAX_REGISTER_EXCEEDED);
|
||||
return;
|
||||
}
|
||||
@ -68,7 +68,7 @@ public class AsyncChangeEmail {
|
||||
}
|
||||
String old = auth.getEmail();
|
||||
auth.setEmail(newEmail);
|
||||
if (!plugin.database.updateEmail(auth)) {
|
||||
if (!plugin.getDataSource().updateEmail(auth)) {
|
||||
m.send(player, MessageKey.ERROR);
|
||||
auth.setEmail(old);
|
||||
return;
|
||||
@ -81,7 +81,7 @@ public class AsyncChangeEmail {
|
||||
}
|
||||
m.send(player, MessageKey.EMAIL_CHANGED_SUCCESS);
|
||||
} else {
|
||||
if (plugin.database.isAuthAvailable(playerName)) {
|
||||
if (plugin.getDataSource().isAuthAvailable(playerName)) {
|
||||
m.send(player, MessageKey.LOGIN_MESSAGE);
|
||||
} else {
|
||||
if (Settings.emailRegistration) {
|
||||
|
@ -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;
|
||||
@ -26,12 +25,11 @@ import java.util.List;
|
||||
*/
|
||||
public class AsynchronousLogin {
|
||||
|
||||
private static final RandomString rdm = new RandomString(Settings.captchaLength);
|
||||
protected final Player player;
|
||||
protected final String name;
|
||||
protected final String realName;
|
||||
protected final String password;
|
||||
protected final boolean forceLogin;
|
||||
private final Player player;
|
||||
private final String name;
|
||||
private final String realName;
|
||||
private final String password;
|
||||
private final boolean forceLogin;
|
||||
private final AuthMe plugin;
|
||||
private final DataSource database;
|
||||
private final Messages m;
|
||||
@ -70,7 +68,7 @@ public class AsynchronousLogin {
|
||||
plugin.captcha.putIfAbsent(name, i);
|
||||
}
|
||||
if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) > Settings.maxLoginTry) {
|
||||
plugin.cap.putIfAbsent(name, rdm.nextString());
|
||||
plugin.cap.putIfAbsent(name, RandomString.generate(Settings.captchaLength));
|
||||
m.send(player, MessageKey.USAGE_CAPTCHA, plugin.cap.get(name));
|
||||
return true;
|
||||
}
|
||||
@ -120,8 +118,7 @@ public class AsynchronousLogin {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Settings.preventOtherCase && !player.getName().equals(pAuth.getRealName()))
|
||||
{
|
||||
if (Settings.preventOtherCase && !player.getName().equals(pAuth.getRealName())) {
|
||||
// TODO: Add a message like : MessageKey.INVALID_NAME_CASE
|
||||
m.send(player, MessageKey.USERNAME_ALREADY_ONLINE_ERROR);
|
||||
return null;
|
||||
@ -138,19 +135,19 @@ public class AsynchronousLogin {
|
||||
if (pAuth == null || needsCaptcha())
|
||||
return;
|
||||
|
||||
String hash = pAuth.getHash();
|
||||
String email = pAuth.getEmail();
|
||||
boolean passwordVerified = true;
|
||||
if (!forceLogin)
|
||||
try {
|
||||
passwordVerified = PasswordSecurity.comparePasswordWithHash(password, hash, realName);
|
||||
} catch (Exception ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
m.send(player, MessageKey.ERROR);
|
||||
return;
|
||||
}
|
||||
boolean passwordVerified = forceLogin || plugin.getPasswordSecurity()
|
||||
.comparePassword(password, pAuth.getPassword(), realName);
|
||||
|
||||
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)
|
||||
.password(pAuth.getPassword())
|
||||
.build();
|
||||
database.updateSession(auth);
|
||||
|
||||
if (Settings.useCaptcha) {
|
||||
|
@ -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.PasswordSecurity;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -44,7 +44,10 @@ public class AsyncRegister {
|
||||
} else if (!Settings.isRegistrationEnabled) {
|
||||
m.send(player, MessageKey.REGISTRATION_DISABLED);
|
||||
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);
|
||||
return false;
|
||||
} else if (passLow.equalsIgnoreCase(player.getName())) {
|
||||
@ -87,26 +90,21 @@ public class AsyncRegister {
|
||||
}
|
||||
}
|
||||
|
||||
private void emailRegister() throws Exception {
|
||||
private void emailRegister() {
|
||||
if (Settings.getmaxRegPerEmail > 0
|
||||
&& !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS)
|
||||
&& database.getAllAuthsByEmail(email).size() >= Settings.getmaxRegPerEmail) {
|
||||
m.send(player, MessageKey.MAX_REGISTER_EXCEEDED);
|
||||
return;
|
||||
}
|
||||
final String hashNew = PasswordSecurity.getHash(Settings.getPasswordHash, password, name);
|
||||
final String salt = PasswordSecurity.userSalt.get(name);
|
||||
final EncryptedPassword encryptedPassword = plugin.getPasswordSecurity().computeHash(password, name);
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(name)
|
||||
.realName(player.getName())
|
||||
.hash(hashNew)
|
||||
.password(encryptedPassword)
|
||||
.ip(ip)
|
||||
.locWorld(player.getLocation().getWorld().getName())
|
||||
.locX(player.getLocation().getX())
|
||||
.locY(player.getLocation().getY())
|
||||
.locZ(player.getLocation().getZ())
|
||||
.location(player.getLocation())
|
||||
.email(email)
|
||||
.salt(salt != null ? salt : "")
|
||||
.build();
|
||||
|
||||
if (!database.saveAuth(auth)) {
|
||||
@ -122,18 +120,13 @@ public class AsyncRegister {
|
||||
}
|
||||
|
||||
private void passwordRegister() throws Exception {
|
||||
final String hashNew = PasswordSecurity.getHash(Settings.getPasswordHash, password, name);
|
||||
final String salt = PasswordSecurity.userSalt.get(name);
|
||||
final EncryptedPassword encryptedPassword = plugin.getPasswordSecurity().computeHash(password, name);
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(name)
|
||||
.realName(player.getName())
|
||||
.hash(hashNew)
|
||||
.password(encryptedPassword)
|
||||
.ip(ip)
|
||||
.locWorld(player.getLocation().getWorld().getName())
|
||||
.locX(player.getLocation().getX())
|
||||
.locY(player.getLocation().getY())
|
||||
.locZ(player.getLocation().getZ())
|
||||
.salt(salt != null ? salt : "")
|
||||
.location(player.getLocation())
|
||||
.build();
|
||||
|
||||
if (!database.saveAuth(auth)) {
|
||||
|
@ -2,11 +2,11 @@ package fr.xephi.authme.process.unregister;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
import fr.xephi.authme.cache.backup.JsonCache;
|
||||
import fr.xephi.authme.cache.limbo.LimboCache;
|
||||
import fr.xephi.authme.cache.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
@ -20,16 +20,12 @@ import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class AsynchronousUnregister {
|
||||
|
||||
protected final Player player;
|
||||
protected final String name;
|
||||
protected final String password;
|
||||
protected final boolean force;
|
||||
private final Player player;
|
||||
private final String name;
|
||||
private final String password;
|
||||
private final boolean force;
|
||||
private final AuthMe plugin;
|
||||
private final Messages m;
|
||||
private final JsonCache playerCache;
|
||||
@ -52,65 +48,59 @@ public class AsynchronousUnregister {
|
||||
this.playerCache = new JsonCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getIp.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected String getIp() {
|
||||
return plugin.getIP(player);
|
||||
}
|
||||
|
||||
public void process() {
|
||||
try {
|
||||
if (force || PasswordSecurity.comparePasswordWithHash(password, PlayerCache.getInstance().getAuth(name).getHash(), player.getName())) {
|
||||
if (!plugin.database.removeAuth(name)) {
|
||||
m.send(player, MessageKey.ERROR);
|
||||
return;
|
||||
PlayerAuth cachedAuth = PlayerCache.getInstance().getAuth(name);
|
||||
if (force || plugin.getPasswordSecurity().comparePassword(
|
||||
password, cachedAuth.getPassword(), player.getName())) {
|
||||
if (!plugin.getDataSource().removeAuth(name)) {
|
||||
m.send(player, MessageKey.ERROR);
|
||||
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;
|
||||
if (Settings.isForcedRegistrationEnabled) {
|
||||
Utils.teleportToSpawn(player);
|
||||
player.saveData();
|
||||
PlayerCache.getInstance().removePlayer(player.getName().toLowerCase());
|
||||
if (!Settings.getRegisteredGroup.isEmpty()) {
|
||||
Utils.setGroup(player, GroupType.UNREGISTERED);
|
||||
}
|
||||
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));
|
||||
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");
|
||||
Utils.teleportToSpawn(player);
|
||||
} else {
|
||||
m.send(player, MessageKey.WRONG_PASSWORD);
|
||||
return;
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,40 +3,42 @@ package fr.xephi.authme.security;
|
||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
|
||||
/**
|
||||
* The list of hash algorithms supported by AuthMe. The implementing class must define a public
|
||||
* constructor which takes either no arguments, or a DataSource object (when the salt is stored
|
||||
* separately, writes to the database are necessary).
|
||||
*/
|
||||
public enum HashAlgorithm {
|
||||
|
||||
MD5(fr.xephi.authme.security.crypts.MD5.class),
|
||||
SHA1(fr.xephi.authme.security.crypts.SHA1.class),
|
||||
SHA256(fr.xephi.authme.security.crypts.SHA256.class),
|
||||
WHIRLPOOL(fr.xephi.authme.security.crypts.WHIRLPOOL.class),
|
||||
XAUTH(fr.xephi.authme.security.crypts.XAUTH.class),
|
||||
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
|
||||
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
|
||||
@Deprecated
|
||||
PLAINTEXT(fr.xephi.authme.security.crypts.PLAINTEXT.class),
|
||||
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
|
||||
IPB3(fr.xephi.authme.security.crypts.IPB3.class),
|
||||
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
|
||||
SMF(fr.xephi.authme.security.crypts.SMF.class),
|
||||
XENFORO(fr.xephi.authme.security.crypts.XF.class),
|
||||
SALTED2MD5(fr.xephi.authme.security.crypts.SALTED2MD5.class),
|
||||
JOOMLA(fr.xephi.authme.security.crypts.JOOMLA.class),
|
||||
BCRYPT(fr.xephi.authme.security.crypts.BCRYPT.class),
|
||||
WBB3(fr.xephi.authme.security.crypts.WBB3.class),
|
||||
WBB4(fr.xephi.authme.security.crypts.WBB4.class),
|
||||
SHA512(fr.xephi.authme.security.crypts.SHA512.class),
|
||||
BCRYPT2Y(fr.xephi.authme.security.crypts.BCRYPT2Y.class),
|
||||
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
|
||||
DOUBLEMD5(fr.xephi.authme.security.crypts.DOUBLEMD5.class),
|
||||
IPB3(fr.xephi.authme.security.crypts.IPB3.class),
|
||||
JOOMLA(fr.xephi.authme.security.crypts.JOOMLA.class),
|
||||
MD5(fr.xephi.authme.security.crypts.MD5.class),
|
||||
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
|
||||
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
|
||||
PBKDF2(fr.xephi.authme.security.crypts.CryptPBKDF2.class),
|
||||
PBKDF2DJANGO(fr.xephi.authme.security.crypts.CryptPBKDF2Django.class),
|
||||
WORDPRESS(fr.xephi.authme.security.crypts.WORDPRESS.class),
|
||||
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
|
||||
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
|
||||
@Deprecated
|
||||
PLAINTEXT(fr.xephi.authme.security.crypts.PLAINTEXT.class),
|
||||
ROYALAUTH(fr.xephi.authme.security.crypts.ROYALAUTH.class),
|
||||
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
|
||||
BCRYPT2Y(fr.xephi.authme.security.crypts.BCRYPT2Y.class),
|
||||
SALTED2MD5(fr.xephi.authme.security.crypts.SALTED2MD5.class),
|
||||
SALTEDSHA512(fr.xephi.authme.security.crypts.SALTEDSHA512.class),
|
||||
SHA1(fr.xephi.authme.security.crypts.SHA1.class),
|
||||
SHA256(fr.xephi.authme.security.crypts.SHA256.class),
|
||||
SHA512(fr.xephi.authme.security.crypts.SHA512.class),
|
||||
SMF(fr.xephi.authme.security.crypts.SMF.class),
|
||||
WBB3(fr.xephi.authme.security.crypts.WBB3.class),
|
||||
WBB4(fr.xephi.authme.security.crypts.WBB4.class),
|
||||
WHIRLPOOL(fr.xephi.authme.security.crypts.WHIRLPOOL.class),
|
||||
WORDPRESS(fr.xephi.authme.security.crypts.WORDPRESS.class),
|
||||
XAUTH(fr.xephi.authme.security.crypts.XAUTH.class),
|
||||
CUSTOM(null);
|
||||
|
||||
final Class<? extends EncryptionMethod> clazz;
|
||||
private final Class<? extends EncryptionMethod> clazz;
|
||||
|
||||
/**
|
||||
* Constructor for HashAlgorithm.
|
||||
|
85
src/main/java/fr/xephi/authme/security/HashUtils.java
Normal file
85
src/main/java/fr/xephi/authme/security/HashUtils.java
Normal file
@ -0,0 +1,85 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Hashing utilities (interface for common hashing algorithms).
|
||||
*/
|
||||
public final class HashUtils {
|
||||
|
||||
private HashUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SHA-1 digest of the given message.
|
||||
*
|
||||
* @param message The message to hash
|
||||
* @return The resulting SHA-1 digest
|
||||
*/
|
||||
public static String sha1(String message) {
|
||||
return hash(message, MessageDigestAlgorithm.SHA1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SHA-256 digest of the given message.
|
||||
*
|
||||
* @param message The message to hash
|
||||
* @return The resulting SHA-256 digest
|
||||
*/
|
||||
public static String sha256(String message) {
|
||||
return hash(message, MessageDigestAlgorithm.SHA256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SHA-512 digest of the given message.
|
||||
*
|
||||
* @param message The message to hash
|
||||
* @return The resulting SHA-512 digest
|
||||
*/
|
||||
public static String sha512(String message) {
|
||||
return hash(message, MessageDigestAlgorithm.SHA512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the MD5 digest of the given message.
|
||||
*
|
||||
* @param message The message to hash
|
||||
* @return The resulting MD5 digest
|
||||
*/
|
||||
public static String md5(String message) {
|
||||
return hash(message, MessageDigestAlgorithm.MD5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link MessageDigest} instance for the given algorithm.
|
||||
*
|
||||
* @param algorithm The desired algorithm
|
||||
* @return MessageDigest instance for the given algorithm
|
||||
*/
|
||||
public static MessageDigest getDigest(MessageDigestAlgorithm algorithm) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm.getKey());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new UnsupportedOperationException("Your system seems not to support the hash algorithm '"
|
||||
+ algorithm.getKey() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash the message with the given algorithm and return the hash in its hexadecimal notation.
|
||||
*
|
||||
* @param message The message to hash
|
||||
* @param algorithm The algorithm to hash the message with
|
||||
* @return The digest in its hexadecimal representation
|
||||
*/
|
||||
private static String hash(String message, MessageDigestAlgorithm algorithm) {
|
||||
MessageDigest md = getDigest(algorithm);
|
||||
md.reset();
|
||||
md.update(message.getBytes());
|
||||
byte[] digest = md.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* The Java-supported names to get a {@link MessageDigest} instance with.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html#AppA">
|
||||
* Crypto Spec Appendix A: Standard Names</a>
|
||||
*/
|
||||
public enum MessageDigestAlgorithm {
|
||||
|
||||
MD5("MD5"),
|
||||
|
||||
SHA1("SHA-1"),
|
||||
|
||||
SHA256("SHA-256"),
|
||||
|
||||
SHA512("SHA-512");
|
||||
|
||||
private final String key;
|
||||
|
||||
MessageDigestAlgorithm(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
@ -1,182 +1,126 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
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.BCRYPT;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
/**
|
||||
* Manager class for password-related operations.
|
||||
*/
|
||||
public class PasswordSecurity {
|
||||
|
||||
public static final HashMap<String, String> userSalt = new HashMap<>();
|
||||
private static final SecureRandom rnd = new SecureRandom();
|
||||
private final DataSource dataSource;
|
||||
private final HashAlgorithm algorithm;
|
||||
private final PluginManager pluginManager;
|
||||
private final boolean supportOldAlgorithm;
|
||||
|
||||
public static String createSalt(int length)
|
||||
throws NoSuchAlgorithmException {
|
||||
byte[] msg = new byte[40];
|
||||
rnd.nextBytes(msg);
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
|
||||
sha1.reset();
|
||||
byte[] digest = sha1.digest(msg);
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest)).substring(0, length);
|
||||
public PasswordSecurity(DataSource dataSource, HashAlgorithm algorithm,
|
||||
PluginManager pluginManager, boolean supportOldAlgorithm) {
|
||||
this.dataSource = dataSource;
|
||||
this.algorithm = algorithm;
|
||||
this.pluginManager = pluginManager;
|
||||
this.supportOldAlgorithm = supportOldAlgorithm;
|
||||
}
|
||||
|
||||
public static String getHash(HashAlgorithm alg, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
EncryptionMethod method;
|
||||
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 XENFORO:
|
||||
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);
|
||||
public EncryptedPassword computeHash(String password, String playerName) {
|
||||
return computeHash(algorithm, password, playerName);
|
||||
}
|
||||
|
||||
public static boolean comparePasswordWithHash(String password, String hash,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
HashAlgorithm algorithm = Settings.getPasswordHash;
|
||||
EncryptionMethod method;
|
||||
try {
|
||||
if (algorithm != HashAlgorithm.CUSTOM) {
|
||||
method = algorithm.getClazz().newInstance();
|
||||
} else {
|
||||
method = null;
|
||||
}
|
||||
public EncryptedPassword computeHash(HashAlgorithm algorithm, String password, String playerName) {
|
||||
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
|
||||
return method.computeHash(password, playerName);
|
||||
}
|
||||
|
||||
PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
method = event.getMethod();
|
||||
|
||||
if (method == null)
|
||||
throw new NoSuchAlgorithmException("Unknown hash algorithm");
|
||||
|
||||
if (method.comparePassword(hash, password, playerName))
|
||||
return true;
|
||||
|
||||
if (Settings.supportOldPassword) {
|
||||
if (compareWithAllEncryptionMethod(password, hash, playerName))
|
||||
return true;
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new NoSuchAlgorithmException("Problem with this hash algorithm");
|
||||
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(password, auth.getPassword(), playerName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean compareWithAllEncryptionMethod(String password,
|
||||
String hash, String playerName) {
|
||||
for (HashAlgorithm algo : HashAlgorithm.values()) {
|
||||
if (algo != HashAlgorithm.CUSTOM) {
|
||||
try {
|
||||
EncryptionMethod method = algo.getClazz().newInstance();
|
||||
if (method.comparePassword(hash, password, playerName)) {
|
||||
PlayerAuth nAuth = AuthMe.getInstance().database.getAuth(playerName);
|
||||
if (nAuth != null) {
|
||||
nAuth.setHash(getHash(Settings.getPasswordHash, password, playerName));
|
||||
nAuth.setSalt(userSalt.containsKey(playerName) ? userSalt.get(playerName) : "");
|
||||
AuthMe.getInstance().database.updatePassword(nAuth);
|
||||
AuthMe.getInstance().database.updateSalt(nAuth);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
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(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. 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 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, EncryptedPassword encryptedPassword,
|
||||
String playerName) {
|
||||
for (HashAlgorithm algorithm : HashAlgorithm.values()) {
|
||||
if (!HashAlgorithm.CUSTOM.equals(algorithm)) {
|
||||
EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm);
|
||||
if (method != null && method.comparePassword(password, encryptedPassword, playerName)) {
|
||||
hashPasswordForNewAlgorithm(password, playerName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param playerName The name of the player a password will be hashed for
|
||||
* @return The encryption method
|
||||
*/
|
||||
private EncryptionMethod initializeEncryptionMethod(HashAlgorithm algorithm, String playerName) {
|
||||
EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm);
|
||||
PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName);
|
||||
pluginManager.callEvent(event);
|
||||
return event.getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the encryption method corresponding to the given hash algorithm.
|
||||
*
|
||||
* @param algorithm The algorithm to retrieve the encryption method for
|
||||
* @return The associated encryption method
|
||||
*/
|
||||
private static EncryptionMethod initializeEncryptionMethodWithoutEvent(HashAlgorithm algorithm) {
|
||||
try {
|
||||
return HashAlgorithm.CUSTOM.equals(algorithm)
|
||||
? null
|
||||
: algorithm.getClazz().newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new UnsupportedOperationException("Constructor for '" + algorithm.getClazz().getSimpleName()
|
||||
+ "' could not be invoked. (Is there no default constructor?)", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void hashPasswordForNewAlgorithm(String password, String playerName) {
|
||||
PlayerAuth auth = dataSource.getAuth(playerName);
|
||||
if (auth != null) {
|
||||
EncryptedPassword encryptedPassword = initializeEncryptionMethod(algorithm, playerName)
|
||||
.computeHash(password, playerName);
|
||||
auth.setPassword(encryptedPassword);
|
||||
dataSource.updatePassword(auth);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Calendar;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomString {
|
||||
/**
|
||||
* Utility for generating random strings.
|
||||
*/
|
||||
public final class RandomString {
|
||||
|
||||
private static final char[] chars = new char[36];
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
private static final int HEX_MAX_INDEX = 16;
|
||||
|
||||
static {
|
||||
for (int idx = 0; idx < 10; ++idx) {
|
||||
@ -18,30 +21,37 @@ public class RandomString {
|
||||
}
|
||||
}
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
private final char[] buf;
|
||||
|
||||
public RandomString(int length) {
|
||||
if (length < 1)
|
||||
throw new IllegalArgumentException("length < 1: " + length);
|
||||
buf = new char[length];
|
||||
random.setSeed(Calendar.getInstance().getTimeInMillis());
|
||||
}
|
||||
|
||||
public String nextString() {
|
||||
for (int idx = 0; idx < buf.length; ++idx)
|
||||
buf[idx] = chars[random.nextInt(chars.length)];
|
||||
return new String(buf);
|
||||
private RandomString() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a string of the given length consisting of random characters within the range [0-9a-z].
|
||||
*
|
||||
* @param length The length of the random string to generate
|
||||
* @return The random string
|
||||
*/
|
||||
public static String generate(int length) {
|
||||
return generate(length, chars.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random hexadecimal string of the given length. In other words, the generated string
|
||||
* contains characters only within the range [0-9a-f].
|
||||
*
|
||||
* @param length The length of the random string to generate
|
||||
* @return The random hexadecimal string
|
||||
*/
|
||||
public static String generateHex(int length) {
|
||||
return generate(length, HEX_MAX_INDEX);
|
||||
}
|
||||
|
||||
private static String generate(int length, int maxIndex) {
|
||||
if (length < 0) {
|
||||
throw new IllegalArgumentException("Length must be positive but was " + length);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
sb.append(chars[RANDOM.nextInt(chars.length)]);
|
||||
sb.append(chars[RANDOM.nextInt(maxIndex)]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -13,8 +13,13 @@
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
@ -59,11 +64,13 @@ import java.security.SecureRandom;
|
||||
* @author Damien Miller
|
||||
* @version 0.2
|
||||
*/
|
||||
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
|
||||
@HasSalt(value = SaltType.TEXT) // length depends on Settings.bCryptLog2Rounds
|
||||
public class BCRYPT implements EncryptionMethod {
|
||||
|
||||
// BCrypt parameters
|
||||
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
||||
private static final int BCRYPT_SALT_LEN = 16;
|
||||
protected static final int BCRYPT_SALT_LEN = 16;
|
||||
|
||||
// Blowfish parameters
|
||||
private static final int BLOWFISH_NUM_ROUNDS = 16;
|
||||
@ -508,14 +515,28 @@ public class BCRYPT implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return hashpw(password, salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return checkpw(password, hash);
|
||||
public EncryptedPassword computeHash(String password, String name) {
|
||||
String salt = generateSalt();
|
||||
return new EncryptedPassword(hashpw(password, salt), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String password, EncryptedPassword hash, String name) {
|
||||
return checkpw(password, hash.getHash());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSalt() {
|
||||
return BCRYPT.gensalt(Settings.bCryptLog2Rounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeparateSalt() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,34 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class BCRYPT2Y implements EncryptionMethod {
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class BCRYPT2Y extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
if (salt.length() == 22)
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
if (salt.length() == 22) {
|
||||
salt = "$2y$10$" + salt;
|
||||
return (BCRYPT.hashpw(password, salt));
|
||||
}
|
||||
return BCRYPT.hashpw(password, salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String ok = hash.substring(0, 29);
|
||||
if (ok.length() != 29)
|
||||
public boolean comparePassword(String password, EncryptedPassword encrypted, String unusedName) {
|
||||
String hash = encrypted.getHash();
|
||||
if (hash.length() != 60) {
|
||||
return false;
|
||||
return hash.equals(computeHash(password, ok, playerName));
|
||||
}
|
||||
// The salt is the first 29 characters of the hash
|
||||
|
||||
String salt = hash.substring(0, 29);
|
||||
return hash.equals(computeHash(password, salt, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 22;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,24 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.MessageDigestAlgorithm;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class CRAZYCRYPT1 implements EncryptionMethod {
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.USERNAME)
|
||||
public class CRAZYCRYPT1 extends UsernameSaltMethod {
|
||||
|
||||
private static final char[] CRYPTCHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
protected final Charset charset = Charset.forName("UTF-8");
|
||||
private static final char[] CRYPTCHARS =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
private final Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
|
||||
public static String byteArrayToHexString(final byte... args) {
|
||||
private static String byteArrayToHexString(final byte... args) {
|
||||
final char[] chars = new char[args.length * 2];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
chars[i * 2] = CRYPTCHARS[(args[i] >> 4) & 0xF];
|
||||
@ -22,21 +28,11 @@ public class CRAZYCRYPT1 implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public EncryptedPassword computeHash(String password, String name) {
|
||||
final String text = "ÜÄaeut//&/=I " + password + "7421€547" + name + "__+IÄIH§%NK " + password;
|
||||
try {
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
md.update(text.getBytes(charset), 0, text.length());
|
||||
return byteArrayToHexString(md.digest());
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
final MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.SHA512);
|
||||
md.update(text.getBytes(charset), 0, text.length());
|
||||
return new EncryptedPassword(byteArrayToHexString(md.digest()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, null, playerName));
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class CryptPBKDF2 implements EncryptionMethod {
|
||||
@Recommendation(Usage.DOES_NOT_WORK)
|
||||
public class CryptPBKDF2 extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String result = "pbkdf2_sha256$10000$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
@ -21,9 +20,8 @@ public class CryptPBKDF2 implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
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());
|
||||
@ -31,4 +29,9 @@ public class CryptPBKDF2 implements EncryptionMethod {
|
||||
return engine.verifyKey(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class CryptPBKDF2Django implements EncryptionMethod {
|
||||
@AsciiRestricted
|
||||
public class CryptPBKDF2Django extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String result = "pbkdf2_sha256$15000$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
@ -21,9 +19,8 @@ public class CryptPBKDF2Django implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
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);
|
||||
@ -31,4 +28,9 @@ public class CryptPBKDF2Django implements EncryptionMethod {
|
||||
return engine.verifyKey(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,32 +1,12 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class DOUBLEMD5 implements EncryptionMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
public class DOUBLEMD5 extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(getMD5(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
public String computeHash(String password) {
|
||||
return md5(md5(password));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* The result of a hash computation. See {@link #salt} for details.
|
||||
*/
|
||||
public class EncryptedPassword {
|
||||
|
||||
/** The generated hash. */
|
||||
private final String hash;
|
||||
/**
|
||||
* The generated salt; may be null if no salt is used or if the salt is included
|
||||
* in the hash output. The salt is only not null if {@link EncryptionMethod#hasSeparateSalt()}
|
||||
* returns true for the associated encryption method.
|
||||
* <p>
|
||||
* When the field is not null, it must be stored into the salt column of the data source
|
||||
* and retrieved again to compare a password with the hash.
|
||||
*/
|
||||
private final String salt;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param hash The computed hash
|
||||
* @param salt The generated salt
|
||||
*/
|
||||
public EncryptedPassword(String hash, String salt) {
|
||||
this.hash = hash;
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a hash with no separate salt.
|
||||
*
|
||||
* @param hash The computed hash
|
||||
*/
|
||||
public EncryptedPassword(String hash) {
|
||||
this(hash, null);
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public String getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +1,59 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Public interface for custom password encryption methods.
|
||||
*/
|
||||
public interface EncryptionMethod {
|
||||
|
||||
/**
|
||||
* Hash the given password with the given salt for the given player.
|
||||
* Hash the given password for the given player name.
|
||||
*
|
||||
* @param password The clear-text password to hash
|
||||
* @param salt The salt to add to the hash
|
||||
* @param name The player's name (sometimes required for storing the salt separately in the database)
|
||||
* @param password The password to hash
|
||||
* @param name The name of the player (sometimes required to generate a salt with)
|
||||
*
|
||||
* @return The hashed password
|
||||
* @return The hash result for the password.
|
||||
* @see EncryptedPassword
|
||||
*/
|
||||
String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException;
|
||||
EncryptedPassword computeHash(String password, String name);
|
||||
|
||||
/**
|
||||
* Check whether a given hash matches the clear-text password.
|
||||
* Hash the given password with the given salt for the given player.
|
||||
*
|
||||
* @param hash The hash to verify
|
||||
* @param password The clear-text password to verify the hash against
|
||||
* @param playerName The player name to do the check for (sometimes required for retrieving
|
||||
* the salt from the database)
|
||||
* @param password The password to hash
|
||||
* @param salt The salt to add to the hash
|
||||
* @param name The player's name (sometimes required to generate a salt with)
|
||||
*
|
||||
* @return The hashed password
|
||||
* @see #hasSeparateSalt()
|
||||
*/
|
||||
String computeHash(String password, String salt, String name);
|
||||
|
||||
/**
|
||||
* Check whether the given hash matches the clear-text password.
|
||||
*
|
||||
* @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 playerName)
|
||||
throws NoSuchAlgorithmException;
|
||||
boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name);
|
||||
|
||||
/**
|
||||
* Generate a new salt to hash a password with.
|
||||
*
|
||||
* @return The generated salt, null if the method does not use a random text-based salt
|
||||
*/
|
||||
String generateSalt();
|
||||
|
||||
/**
|
||||
* Return whether the encryption method requires the salt to be stored separately and
|
||||
* 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.
|
||||
*
|
||||
* @return True if the salt has to be stored and retrieved separately, false otherwise
|
||||
*/
|
||||
boolean hasSeparateSalt();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
* Common type for encryption methods which use a random String of hexadecimal characters
|
||||
* and store the salt with the hash itself.
|
||||
*/
|
||||
@Recommendation(Usage.ACCEPTABLE)
|
||||
@HasSalt(SaltType.TEXT) // See saltLength() for length
|
||||
public abstract class HexSaltedMethod implements EncryptionMethod {
|
||||
|
||||
public abstract int getSaltLength();
|
||||
|
||||
@Override
|
||||
public abstract String computeHash(String password, String salt, String name);
|
||||
|
||||
@Override
|
||||
public EncryptedPassword computeHash(String password, String name) {
|
||||
String salt = generateSalt();
|
||||
return new EncryptedPassword(computeHash(password, salt, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name);
|
||||
|
||||
@Override
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(getSaltLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeparateSalt() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,34 +1,25 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class IPB3 implements EncryptionMethod {
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(value = SaltType.TEXT, length = 5)
|
||||
public class IPB3 extends SeparateSaltMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return md5(md5(salt) + md5(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(getMD5(salt) + getMD5(password));
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(computeHash(password, salt, playerName));
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,27 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class JOOMLA implements EncryptionMethod {
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class JOOMLA extends HexSaltedMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return HashUtils.md5(password + salt) + ":" + salt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(password + salt) + ":" + salt;
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = hash.split(":")[1];
|
||||
return hash.equals(getMD5(password + salt) + ":" + salt);
|
||||
public int getSaltLength() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,31 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class MD5 implements EncryptionMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
public class MD5 extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(password);
|
||||
public String computeHash(String password) {
|
||||
return HashUtils.md5(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,24 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class MD5VB implements EncryptionMethod {
|
||||
public class MD5VB extends HexSaltedMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return "$MD5vb$" + salt + "$" + md5(md5(password) + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return "$MD5vb$" + salt + "$" + getMD5(getMD5(password) + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
|
||||
String hash = encryptedPassword.getHash();
|
||||
String[] line = hash.split("\\$");
|
||||
return hash.equals(computeHash(password, line[2], ""));
|
||||
return line.length == 4 && hash.equals(computeHash(password, line[2], name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,34 +1,19 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class MYBB implements EncryptionMethod {
|
||||
public class MYBB extends SeparateSaltMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return md5(md5(salt) + md5(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(getMD5(salt) + getMD5(password));
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(computeHash(password, salt, playerName));
|
||||
}
|
||||
}
|
||||
|
@ -4,25 +4,26 @@
|
||||
*/
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.MessageDigestAlgorithm;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author stefano
|
||||
*/
|
||||
public class PHPBB implements EncryptionMethod {
|
||||
public class PHPBB extends HexSaltedMethod {
|
||||
|
||||
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
public static String md5(String data) {
|
||||
private static String md5(String data) {
|
||||
try {
|
||||
byte[] bytes = data.getBytes("ISO-8859-1");
|
||||
MessageDigest md5er = MessageDigest.getInstance("MD5");
|
||||
MessageDigest md5er = HashUtils.getDigest(MessageDigestAlgorithm.MD5);
|
||||
byte[] hash = md5er.digest(bytes);
|
||||
return bytes2hex(hash);
|
||||
} catch (GeneralSecurityException | UnsupportedEncodingException e) {
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@ -58,7 +59,7 @@ public class PHPBB implements EncryptionMethod {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String phpbb_hash(String password, String salt) {
|
||||
private String phpbb_hash(String password, String salt) {
|
||||
String random_state = salt;
|
||||
StringBuilder random = new StringBuilder();
|
||||
int count = 6;
|
||||
@ -109,7 +110,7 @@ public class PHPBB implements EncryptionMethod {
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
String _hash_crypt_private(String password, String setting) {
|
||||
private String _hash_crypt_private(String password, String setting) {
|
||||
String output = "*";
|
||||
if (!setting.substring(0, 3).equals("$H$"))
|
||||
return output;
|
||||
@ -130,21 +131,26 @@ public class PHPBB implements EncryptionMethod {
|
||||
return output;
|
||||
}
|
||||
|
||||
public boolean phpbb_check_hash(String password, String hash) {
|
||||
if (hash.length() == 34)
|
||||
private boolean phpbb_check_hash(String password, String hash) {
|
||||
if (hash.length() == 34) {
|
||||
return _hash_crypt_private(password, hash).equals(hash);
|
||||
else return md5(password).equals(hash);
|
||||
}
|
||||
return md5(password).equals(hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return phpbb_hash(password, salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return phpbb_check_hash(password, hash);
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
|
||||
return phpbb_check_hash(password, encryptedPassword.getHash());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,36 +1,27 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PHPFUSION implements EncryptionMethod {
|
||||
|
||||
private static String getSHA1(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
|
||||
sha1.reset();
|
||||
sha1.update(message.getBytes());
|
||||
byte[] digest = sha1.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@AsciiRestricted
|
||||
public class PHPFUSION extends SeparateSaltMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
String digest = null;
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String algo = "HmacSHA256";
|
||||
String keyString = getSHA1(salt);
|
||||
String keyString = HashUtils.sha1(salt);
|
||||
try {
|
||||
SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"), algo);
|
||||
SecretKeySpec key = new SecretKeySpec(keyString.getBytes("UTF-8"), algo);
|
||||
Mac mac = Mac.getInstance(algo);
|
||||
mac.init(key);
|
||||
byte[] bytes = mac.doFinal(password.getBytes("ASCII"));
|
||||
@ -42,19 +33,16 @@ public class PHPFUSION implements EncryptionMethod {
|
||||
}
|
||||
hash.append(hex);
|
||||
}
|
||||
digest = hash.toString();
|
||||
return hash.toString();
|
||||
} catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
|
||||
//ingore
|
||||
throw new UnsupportedOperationException("Cannot create PHPFUSION hash for " + name, e);
|
||||
}
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(computeHash(password, salt, ""));
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(12);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,21 +1,11 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class PLAINTEXT implements EncryptionMethod {
|
||||
@Deprecated
|
||||
public class PLAINTEXT extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password) {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(password);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,35 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ROYALAUTH implements EncryptionMethod {
|
||||
public class ROYALAUTH extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
for (int i = 0; i < 25; i++)
|
||||
password = hash(password, salt);
|
||||
public String computeHash(String password) {
|
||||
for (int i = 0; i < 25; i++) {
|
||||
// TODO ljacqu 20151228: HashUtils#sha512 gets a new message digest each time...
|
||||
password = HashUtils.sha512(password);
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
public String hash(String password, String salt)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
md.update(password.getBytes());
|
||||
byte byteData[] = md.digest();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte aByteData : byteData)
|
||||
sb.append(Integer.toString((aByteData & 0xff) + 0x100, 16).substring(1));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equalsIgnoreCase(computeHash(password, "", ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,34 +1,26 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SALTED2MD5 implements EncryptionMethod {
|
||||
@Recommendation(Usage.ACCEPTABLE) // presuming that length is something sensible (>= 8)
|
||||
@HasSalt(value = SaltType.TEXT) // length defined by Settings.saltLength
|
||||
public class SALTED2MD5 extends SeparateSaltMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return md5(md5(password) + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(getMD5(password) + salt);
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(Settings.saltLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(getMD5(getMD5(password) + salt));
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,20 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class SALTEDSHA512 extends SeparateSaltMethod {
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SALTEDSHA512 implements EncryptionMethod {
|
||||
|
||||
private static String getSHA512(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha512 = MessageDigest.getInstance("SHA-512");
|
||||
sha512.reset();
|
||||
sha512.update(message.getBytes());
|
||||
byte[] digest = sha512.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return HashUtils.sha512(password + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSHA512(password + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(computeHash(password, salt, ""));
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(32);
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,12 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SHA1 implements EncryptionMethod {
|
||||
|
||||
private static String getSHA1(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
|
||||
sha1.reset();
|
||||
sha1.update(message.getBytes());
|
||||
byte[] digest = sha1.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
public class SHA1 extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSHA1(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
public String computeHash(String password) {
|
||||
return HashUtils.sha1(password);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,33 +1,28 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SHA256 implements EncryptionMethod {
|
||||
import static fr.xephi.authme.security.HashUtils.sha256;
|
||||
|
||||
private static String getSHA256(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
|
||||
sha256.reset();
|
||||
sha256.update(message.getBytes());
|
||||
byte[] digest = sha256.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class SHA256 extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return "$SHA$" + salt + "$" + sha256(sha256(password) + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return "$SHA$" + salt + "$" + getSHA256(getSHA256(password) + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) {
|
||||
String hash = encryptedPassword.getHash();
|
||||
String[] line = hash.split("\\$");
|
||||
return hash.equals(computeHash(password, line[2], ""));
|
||||
return line.length == 4 && hash.equals(computeHash(password, line[2], ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,31 +1,12 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SHA512 implements EncryptionMethod {
|
||||
|
||||
private static String getSHA512(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha512 = MessageDigest.getInstance("SHA-512");
|
||||
sha512.reset();
|
||||
sha512.update(message.getBytes());
|
||||
byte[] digest = sha512.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
public class SHA512 extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSHA512(password);
|
||||
public String computeHash(String password) {
|
||||
return HashUtils.sha512(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,11 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SMF implements EncryptionMethod {
|
||||
public class SMF extends UsernameSaltMethod {
|
||||
|
||||
private static String getSHA1(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
|
||||
sha1.reset();
|
||||
sha1.update(message.getBytes());
|
||||
byte[] digest = sha1.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
public EncryptedPassword computeHash(String password, String name) {
|
||||
return new EncryptedPassword(HashUtils.sha1(name.toLowerCase() + password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSHA1(name.toLowerCase() + password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, null, playerName));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* Common supertype for encryption methods which store their salt separately from the hash.
|
||||
*/
|
||||
public abstract class SeparateSaltMethod implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
public abstract String computeHash(String password, String salt, String name);
|
||||
|
||||
@Override
|
||||
public abstract String generateSalt();
|
||||
|
||||
@Override
|
||||
public EncryptedPassword computeHash(String password, String name) {
|
||||
String salt = generateSalt();
|
||||
return new EncryptedPassword(computeHash(password, salt, name), salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
|
||||
return encryptedPassword.getHash().equals(computeHash(password, encryptedPassword.getSalt(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeparateSalt() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
* Common type for encryption methods which do not use any salt whatsoever.
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.NONE)
|
||||
public abstract class UnsaltedMethod implements EncryptionMethod {
|
||||
|
||||
public abstract String computeHash(String password);
|
||||
|
||||
@Override
|
||||
public EncryptedPassword computeHash(String password, String name) {
|
||||
return new EncryptedPassword(computeHash(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
|
||||
return encryptedPassword.getHash().equals(computeHash(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSalt() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeparateSalt() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
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 embedded salt.
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.USERNAME)
|
||||
public abstract class UsernameSaltMethod implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
public abstract EncryptedPassword computeHash(String password, String name);
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
|
||||
return encryptedPassword.getHash().equals(computeHash(password, name).getHash());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password, name).getHash();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSalt() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeparateSalt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +1,19 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import static fr.xephi.authme.security.HashUtils.sha1;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class WBB3 implements EncryptionMethod {
|
||||
public class WBB3 extends SeparateSaltMethod {
|
||||
|
||||
private static String getSHA1(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
|
||||
sha1.reset();
|
||||
sha1.update(message.getBytes());
|
||||
byte[] digest = sha1.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return sha1(salt.concat(sha1(salt.concat(sha1(password)))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSHA1(salt.concat(getSHA1(salt.concat(getSHA1(password)))));
|
||||
public String generateSalt() {
|
||||
return RandomString.generateHex(40);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(computeHash(password, salt, ""));
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,34 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class WBB4 implements EncryptionMethod {
|
||||
@Recommendation(Usage.DOES_NOT_WORK)
|
||||
public class WBB4 extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return BCRYPT.getDoubleHash(password, salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return BCRYPT.checkpw(password, hash, 2);
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) {
|
||||
return BCRYPT.checkpw(password, encryptedPassword.getHash(), 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSalt() {
|
||||
return BCRYPT.gensalt(8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that {@link #generateSalt()} is overridden for this class.
|
||||
*
|
||||
* @return The salt length
|
||||
*/
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,12 +59,9 @@ package fr.xephi.authme.security.crypts;
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class WHIRLPOOL implements EncryptionMethod {
|
||||
public class WHIRLPOOL extends UnsaltedMethod {
|
||||
|
||||
/**
|
||||
* The message digest size (in bits)
|
||||
@ -382,9 +379,7 @@ public class WHIRLPOOL implements EncryptionMethod {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password) {
|
||||
byte[] digest = new byte[DIGESTBYTES];
|
||||
NESSIEinit();
|
||||
NESSIEadd(password);
|
||||
@ -392,9 +387,4 @@ public class WHIRLPOOL implements EncryptionMethod {
|
||||
return display(digest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,22 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class WORDPRESS implements EncryptionMethod {
|
||||
// TODO #391: Wordpress algorithm fails sometimes. Fix it and change the Recommendation to "ACCEPTABLE" if appropriate
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(value = SaltType.TEXT, length = 9)
|
||||
// Note ljacqu 20151228: Wordpress is actually a salted algorithm but salt generation is handled internally
|
||||
// and isn't exposed to the outside, so we treat it as an unsalted implementation
|
||||
public class WORDPRESS extends UnsaltedMethod {
|
||||
|
||||
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
private final SecureRandom randomGen = new SecureRandom();
|
||||
@ -102,16 +110,15 @@ public class WORDPRESS implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password) {
|
||||
byte random[] = new byte[6];
|
||||
this.randomGen.nextBytes(random);
|
||||
randomGen.nextBytes(random);
|
||||
return crypt(password, gensaltPrivate(stringToUtf8(new String(random))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
|
||||
String hash = encryptedPassword.getHash();
|
||||
String comparedHash = crypt(password, hash);
|
||||
return comparedHash.equals(hash);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class XAUTH implements EncryptionMethod {
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class XAUTH extends HexSaltedMethod {
|
||||
|
||||
public static String getWhirlpool(String message) {
|
||||
private static String getWhirlpool(String message) {
|
||||
WHIRLPOOL w = new WHIRLPOOL();
|
||||
byte[] digest = new byte[WHIRLPOOL.DIGESTBYTES];
|
||||
w.NESSIEinit();
|
||||
@ -16,19 +16,23 @@ public class XAUTH implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String hash = getWhirlpool(salt + password).toLowerCase();
|
||||
int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length());
|
||||
return hash.substring(0, saltPos) + salt + hash.substring(saltPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
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 salt = hash.substring(saltPos, saltPos + 12);
|
||||
return hash.equals(computeHash(password, salt, ""));
|
||||
String saltFromHash = hash.substring(saltPos, saltPos + 12);
|
||||
return hash.equals(computeHash(password, saltFromHash, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSaltLength() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class XF implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSha256(getSha256(password) + regmatch("\"salt\";.:..:\"(.*)\";.:.:\"hashFunc\"", salt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
||||
return hash.equals(regmatch("\"hash\";.:..:\"(.*)\";.:.:\"salt\"", salt));
|
||||
}
|
||||
|
||||
private String getSha256(String password) throws NoSuchAlgorithmException {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.update(password.getBytes());
|
||||
byte byteData[] = md.digest();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte element : byteData) {
|
||||
sb.append(Integer.toString((element & 0xff) + 0x100, 16).substring(1));
|
||||
}
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte element : byteData) {
|
||||
String hex = Integer.toHexString(0xff & element);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
private String regmatch(String pattern, String line) {
|
||||
List<String> allMatches = new ArrayList<>();
|
||||
Matcher m = Pattern.compile(pattern).matcher(line);
|
||||
while (m.find()) {
|
||||
allMatches.add(m.group(1));
|
||||
}
|
||||
return allMatches.get(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes an encryption algorithm that is restricted to the ASCII charset.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AsciiRestricted {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Describes the type of salt the encryption algorithm uses. This is purely for documentation
|
||||
* purposes and is ignored by the code.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface HasSalt {
|
||||
|
||||
/** The type of the salt. */
|
||||
SaltType value();
|
||||
|
||||
/** For text salts, the length of the salt. */
|
||||
int length() default 0;
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to mark a hash algorithm with the usage recommendation, see {@link Usage}.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Recommendation {
|
||||
|
||||
/** The recommendation for using the hash algorithm. */
|
||||
Usage value();
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
/**
|
||||
* The type of salt used by an encryption algorithm.
|
||||
*/
|
||||
public enum SaltType {
|
||||
|
||||
/** Random, newly generated text. */
|
||||
TEXT,
|
||||
|
||||
/** Salt is based on the username, including variations and repetitions. */
|
||||
USERNAME,
|
||||
|
||||
/** No salt. */
|
||||
NONE
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
/**
|
||||
* Usage recommendation that can be provided for a hash algorithm.
|
||||
*/
|
||||
public enum Usage {
|
||||
|
||||
/** The hash algorithm appears to be cryptographically secure and is one of the algorithms recommended by AuthMe. */
|
||||
RECOMMENDED,
|
||||
|
||||
/** There are safer algorithms that can be chosen but using the algorithm is generally OK. */
|
||||
ACCEPTABLE,
|
||||
|
||||
/** Hash algorithm is not recommended to be used. Use only if required by another system. */
|
||||
DO_NOT_USE,
|
||||
|
||||
/** The algorithm does not work properly; do not use. */
|
||||
DOES_NOT_WORK
|
||||
|
||||
}
|
@ -1,20 +1,18 @@
|
||||
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.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
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 {
|
||||
|
||||
private final AuthMe plugin;
|
||||
@ -32,48 +30,40 @@ public class ChangePasswordTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
Messages m = plugin.getMessages();
|
||||
try {
|
||||
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(){
|
||||
PasswordSecurity passwordSecurity = plugin.getPasswordSecurity();
|
||||
|
||||
@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);
|
||||
final String name = player.getName().toLowerCase();
|
||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(name);
|
||||
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;
|
||||
}
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
m.send(player, MessageKey.ERROR);
|
||||
|
||||
PlayerCache.getInstance().updatePlayer(auth);
|
||||
m.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
|
||||
ConsoleLogger.info(player.getName() + " changed his password");
|
||||
if (Settings.bungee) {
|
||||
final String hash = encryptedPassword.getHash();
|
||||
final String salt = encryptedPassword.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,13 +143,9 @@ public final class Utils {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Settings.isForcedRegistrationEnabled) {
|
||||
// TODO ljacqu 20151123: Use a getter to retrieve things from AuthMe
|
||||
if (!plugin.database.isAuthAvailable(player.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (!Settings.isForcedRegistrationEnabled && !plugin.getDataSource().isAuthAvailable(player.getName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -159,15 +155,6 @@ public final class Utils {
|
||||
&& (Settings.getUnrestrictedName.contains(player.getName().toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method packCoords.
|
||||
*
|
||||
* @param x double
|
||||
* @param y double
|
||||
* @param z double
|
||||
* @param w String
|
||||
* @param pl Player
|
||||
*/
|
||||
public static void packCoords(double x, double y, double z, String w, final Player pl) {
|
||||
World theWorld;
|
||||
if (w.equals("unavailableworld")) {
|
||||
|
@ -181,7 +181,7 @@ settings:
|
||||
# Example unLoggedinGroup: NotLogged
|
||||
unLoggedinGroup: unLoggedinGroup
|
||||
# possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB,
|
||||
# MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,
|
||||
# MYBB, IPB3, PHPFUSION, SMF, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,
|
||||
# DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only)
|
||||
passwordHash: SHA256
|
||||
# salt length for the SALTED2MD5 MD5(MD5(password)+salt)
|
||||
|
@ -2,10 +2,12 @@ package fr.xephi.authme.command;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.command.help.HelpProvider;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.process.Management;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.Before;
|
||||
@ -32,6 +34,7 @@ public class CommandServiceTest {
|
||||
private CommandMapper commandMapper;
|
||||
private HelpProvider helpProvider;
|
||||
private Messages messages;
|
||||
private PasswordSecurity passwordSecurity;
|
||||
private CommandService commandService;
|
||||
|
||||
@Before
|
||||
@ -40,7 +43,8 @@ public class CommandServiceTest {
|
||||
commandMapper = mock(CommandMapper.class);
|
||||
helpProvider = mock(HelpProvider.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
|
||||
@ -110,9 +114,25 @@ public class CommandServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
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
|
||||
|
@ -0,0 +1,61 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import fr.xephi.authme.security.crypts.EncryptedPassword;
|
||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import fr.xephi.authme.util.WrapperMock;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Integration test for {@link HashAlgorithm}.
|
||||
*/
|
||||
public class HashAlgorithmIntegrationTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpWrapper() {
|
||||
WrapperMock.createInstance();
|
||||
Settings.bCryptLog2Rounds = 8;
|
||||
Settings.saltLength = 16;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHaveUniqueClassForEntries() {
|
||||
// given
|
||||
Set<Class<? extends EncryptionMethod>> classes = new HashSet<>();
|
||||
|
||||
// when / then
|
||||
for (HashAlgorithm algorithm : HashAlgorithm.values()) {
|
||||
if (!HashAlgorithm.CUSTOM.equals(algorithm)) {
|
||||
if (classes.contains(algorithm.getClazz())) {
|
||||
fail("Found class '" + algorithm.getClazz() + "' twice!");
|
||||
}
|
||||
classes.add(algorithm.getClazz());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToInstantiateEncryptionAlgorithms() throws InstantiationException, IllegalAccessException {
|
||||
// given / when / then
|
||||
for (HashAlgorithm algorithm : HashAlgorithm.values()) {
|
||||
if (!HashAlgorithm.CUSTOM.equals(algorithm)) {
|
||||
EncryptionMethod method = algorithm.getClazz().newInstance();
|
||||
EncryptedPassword encryptedPassword = method.computeHash("pwd", "name");
|
||||
assertThat("Salt should not be null if method.hasSeparateSalt(), and vice versa. Method: '"
|
||||
+ method + "'", StringUtils.isEmpty(encryptedPassword.getSalt()), equalTo(!method.hasSeparateSalt()));
|
||||
assertThat("Hash should not be empty for method '" + method + "'",
|
||||
StringUtils.isEmpty(encryptedPassword.getHash()), equalTo(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
116
src/test/java/fr/xephi/authme/security/HashUtilsTest.java
Normal file
116
src/test/java/fr/xephi/authme/security/HashUtilsTest.java
Normal file
@ -0,0 +1,116 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
/**
|
||||
* Test for {@link HashUtils}.
|
||||
*/
|
||||
public class HashUtilsTest {
|
||||
|
||||
/**
|
||||
* List of passwords whose hash is provided to the class to test against.
|
||||
*/
|
||||
public static final String[] GIVEN_PASSWORDS = {"", "password", "PassWord1", "&^%te$t?Pw@_"};
|
||||
|
||||
@Test
|
||||
public void shouldHashMd5() {
|
||||
// given
|
||||
String[] correctHashes = {
|
||||
"d41d8cd98f00b204e9800998ecf8427e", // empty string
|
||||
"5f4dcc3b5aa765d61d8327deb882cf99", // password
|
||||
"f2126d405f46ed603ff5b2950f062c96", // PassWord1
|
||||
"0833dcd2bc741f90c46bbac5498fd08f" // &^%te$t?Pw@_
|
||||
};
|
||||
|
||||
// when
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String password : GIVEN_PASSWORDS) {
|
||||
result.add(HashUtils.md5(password));
|
||||
}
|
||||
|
||||
// then
|
||||
assertThat(result, contains(correctHashes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHashSha1() {
|
||||
// given
|
||||
String[] correctHashes = {
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709", // empty string
|
||||
"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", // password
|
||||
"285d0c707f9644b75e1a87a62f25d0efb56800f0", // PassWord1
|
||||
"a42ef8e61e890af80461ca5dcded25cbfcf407a4" // &^%te$t?Pw@_
|
||||
};
|
||||
|
||||
// when
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String password : GIVEN_PASSWORDS) {
|
||||
result.add(HashUtils.sha1(password));
|
||||
}
|
||||
|
||||
// then
|
||||
assertThat(result, contains(correctHashes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHashSha256() {
|
||||
// given
|
||||
String[] correctHashes = {
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // empty string
|
||||
"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8", // password
|
||||
"c04265d72b749debd67451c083785aa572742e3222e86884de16485fa14b55e7", // PassWord1
|
||||
"005e3d7439d3e9a60a9d74aa1c763b36bfebec8e434ab6c5efab3df37eb2dae6" // &^%te$t?Pw@_
|
||||
};
|
||||
|
||||
// when
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String password : GIVEN_PASSWORDS) {
|
||||
result.add(HashUtils.sha256(password));
|
||||
}
|
||||
|
||||
// then
|
||||
assertThat(result, contains(correctHashes));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldHashSha512() {
|
||||
// given
|
||||
String[] correctHashes = {
|
||||
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", // empty string
|
||||
"b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86", // password
|
||||
"ae9942149995a8171391625b36da134d5e288c721650d7c8d2d464fb49a49f3f551e4916ab1e097d9dd1201b01d69b1dccdefa3d2524a66092fb61b3df6e7e71", // PassWord1
|
||||
"8c4f3df78db191142d819a72c16058b9e1ea41ae9b1649e1184eb89e30344c51c9c71039c483cf2f1b76b51480d8459d7eb3cfbaa24b07f2041d1551af4ead75" // &^%te$t?Pw@_
|
||||
};
|
||||
|
||||
// when
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String password : GIVEN_PASSWORDS) {
|
||||
result.add(HashUtils.sha512(password));
|
||||
}
|
||||
|
||||
// then
|
||||
assertThat(result, contains(correctHashes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRetrieveMd5Instance() {
|
||||
// given
|
||||
MessageDigestAlgorithm algorithm = MessageDigestAlgorithm.MD5;
|
||||
|
||||
// when
|
||||
MessageDigest digest = HashUtils.getDigest(algorithm);
|
||||
|
||||
// then
|
||||
assertThat(digest.getAlgorithm(), equalTo("MD5"));
|
||||
}
|
||||
|
||||
}
|
224
src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java
Normal file
224
src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java
Normal file
@ -0,0 +1,224 @@
|
||||
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.JOOMLA;
|
||||
import fr.xephi.authme.security.crypts.PHPBB;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Test for {@link PasswordSecurity}.
|
||||
*/
|
||||
public class PasswordSecurityTest {
|
||||
|
||||
private PluginManager pluginManager;
|
||||
private DataSource dataSource;
|
||||
private EncryptionMethod method;
|
||||
private Class<?> caughtClassInEvent;
|
||||
|
||||
@Before
|
||||
public void setUpMocks() {
|
||||
pluginManager = mock(PluginManager.class);
|
||||
dataSource = mock(DataSource.class);
|
||||
method = mock(EncryptionMethod.class);
|
||||
caughtClassInEvent = null;
|
||||
|
||||
// When the password encryption event is emitted, replace the encryption method with our mock.
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
Object[] arguments = invocation.getArguments();
|
||||
if (arguments[0] instanceof PasswordEncryptionEvent) {
|
||||
PasswordEncryptionEvent event = (PasswordEncryptionEvent) arguments[0];
|
||||
caughtClassInEvent = event.getMethod() != null ? event.getMethod().getClass() : null;
|
||||
event.setMethod(method);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}).when(pluginManager).callEvent(any(Event.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnPasswordMatch() {
|
||||
// given
|
||||
EncryptedPassword password = new EncryptedPassword("$TEST$10$SOME_HASH", null);
|
||||
String playerName = "Tester";
|
||||
String clearTextPass = "myPassTest";
|
||||
|
||||
PlayerAuth auth = mock(PlayerAuth.class);
|
||||
given(auth.getPassword()).willReturn(password);
|
||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
||||
given(method.comparePassword(clearTextPass, password, playerName)).willReturn(true);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.BCRYPT, pluginManager, false);
|
||||
|
||||
// when
|
||||
boolean result = security.comparePassword(clearTextPass, playerName);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(true));
|
||||
verify(dataSource).getAuth(playerName);
|
||||
verify(pluginManager).callEvent(any(PasswordEncryptionEvent.class));
|
||||
verify(method).comparePassword(clearTextPass, password, playerName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnPasswordMismatch() {
|
||||
// given
|
||||
EncryptedPassword password = new EncryptedPassword("$TEST$10$SOME_HASH", null);
|
||||
String playerName = "My_PLayer";
|
||||
String clearTextPass = "passw0Rd1";
|
||||
|
||||
PlayerAuth auth = mock(PlayerAuth.class);
|
||||
given(auth.getPassword()).willReturn(password);
|
||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
||||
given(method.comparePassword(clearTextPass, password, playerName)).willReturn(false);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.CUSTOM, pluginManager, false);
|
||||
|
||||
// when
|
||||
boolean result = security.comparePassword(clearTextPass, playerName);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(false));
|
||||
verify(dataSource).getAuth(playerName);
|
||||
verify(pluginManager).callEvent(any(PasswordEncryptionEvent.class));
|
||||
verify(method).comparePassword(clearTextPass, password, playerName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfPlayerDoesNotExist() {
|
||||
// given
|
||||
String playerName = "bobby";
|
||||
String clearTextPass = "tables";
|
||||
|
||||
given(dataSource.getAuth(playerName)).willReturn(null);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.MD5, pluginManager, false);
|
||||
|
||||
// when
|
||||
boolean result = security.comparePassword(clearTextPass, playerName);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(false));
|
||||
verify(dataSource).getAuth(playerName);
|
||||
verify(pluginManager, never()).callEvent(any(Event.class));
|
||||
verify(method, never()).comparePassword(anyString(), any(EncryptedPassword.class), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTryOtherMethodsForFailedPassword() {
|
||||
// given
|
||||
// BCRYPT2Y hash for "Test"
|
||||
EncryptedPassword password =
|
||||
new EncryptedPassword("$2y$10$2e6d2193f43501c926e25elvWlPmWczmrfrnbZV0dUZGITjYjnkkW");
|
||||
String playerName = "somePlayer";
|
||||
String clearTextPass = "Test";
|
||||
// MD5 hash for "Test"
|
||||
EncryptedPassword newPassword = new EncryptedPassword("0cbc6611f5540bd0809a388dc95a615b");
|
||||
|
||||
PlayerAuth auth = mock(PlayerAuth.class);
|
||||
doCallRealMethod().when(auth).getPassword();
|
||||
doCallRealMethod().when(auth).setPassword(any(EncryptedPassword.class));
|
||||
auth.setPassword(password);
|
||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
||||
given(method.comparePassword(clearTextPass, password, playerName)).willReturn(false);
|
||||
given(method.computeHash(clearTextPass, playerName)).willReturn(newPassword);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.MD5, pluginManager, true);
|
||||
|
||||
// when
|
||||
boolean result = security.comparePassword(clearTextPass, playerName);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(true));
|
||||
verify(dataSource, times(2)).getAuth(playerName);
|
||||
verify(pluginManager, times(2)).callEvent(any(PasswordEncryptionEvent.class));
|
||||
verify(method).comparePassword(clearTextPass, password, playerName);
|
||||
verify(auth).setPassword(newPassword);
|
||||
|
||||
ArgumentCaptor<PlayerAuth> captor = ArgumentCaptor.forClass(PlayerAuth.class);
|
||||
verify(dataSource).updatePassword(captor.capture());
|
||||
assertThat(captor.getValue().getPassword(), equalTo(newPassword));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHashPassword() {
|
||||
// given
|
||||
String password = "MyP@ssword";
|
||||
String username = "theUserInTest";
|
||||
EncryptedPassword encryptedPassword = new EncryptedPassword("$T$est#Hash", "__someSalt__");
|
||||
given(method.computeHash(password, username)).willReturn(encryptedPassword);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.JOOMLA, pluginManager, true);
|
||||
|
||||
// when
|
||||
EncryptedPassword result = security.computeHash(password, username);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(encryptedPassword));
|
||||
ArgumentCaptor<PasswordEncryptionEvent> captor = ArgumentCaptor.forClass(PasswordEncryptionEvent.class);
|
||||
verify(pluginManager).callEvent(captor.capture());
|
||||
PasswordEncryptionEvent event = captor.getValue();
|
||||
assertThat(JOOMLA.class.equals(caughtClassInEvent), equalTo(true));
|
||||
assertThat(event.getPlayerName(), equalTo(username));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHashPasswordWithGivenAlgorithm() {
|
||||
// given
|
||||
String password = "TopSecretPass#112525";
|
||||
String username = "someone12";
|
||||
EncryptedPassword encryptedPassword = new EncryptedPassword("~T!est#Hash", "__someSalt__");
|
||||
given(method.computeHash(password, username)).willReturn(encryptedPassword);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.JOOMLA, pluginManager, true);
|
||||
|
||||
// when
|
||||
EncryptedPassword result = security.computeHash(HashAlgorithm.PHPBB, password, username);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(encryptedPassword));
|
||||
ArgumentCaptor<PasswordEncryptionEvent> captor = ArgumentCaptor.forClass(PasswordEncryptionEvent.class);
|
||||
verify(pluginManager).callEvent(captor.capture());
|
||||
PasswordEncryptionEvent event = captor.getValue();
|
||||
assertThat(PHPBB.class.equals(caughtClassInEvent), equalTo(true));
|
||||
assertThat(event.getPlayerName(), equalTo(username));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSkipCheckIfMandatorySaltIsUnavailable() {
|
||||
// given
|
||||
String password = "?topSecretPass\\";
|
||||
String username = "someone12";
|
||||
EncryptedPassword encryptedPassword = new EncryptedPassword("~T!est#Hash");
|
||||
given(method.computeHash(password, username)).willReturn(encryptedPassword);
|
||||
given(method.hasSeparateSalt()).willReturn(true);
|
||||
PasswordSecurity security = new PasswordSecurity(dataSource, HashAlgorithm.XAUTH, pluginManager, true);
|
||||
|
||||
// when
|
||||
boolean result = security.comparePassword(password, encryptedPassword, username);
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(false));
|
||||
verify(dataSource, never()).getAuth(anyString());
|
||||
verify(pluginManager).callEvent(any(PasswordEncryptionEvent.class));
|
||||
verify(method, never()).comparePassword(anyString(), any(EncryptedPassword.class), anyString());
|
||||
}
|
||||
|
||||
}
|
55
src/test/java/fr/xephi/authme/security/RandomStringTest.java
Normal file
55
src/test/java/fr/xephi/authme/security/RandomStringTest.java
Normal file
@ -0,0 +1,55 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
/**
|
||||
* Test for {@link RandomString}.
|
||||
*/
|
||||
public class RandomStringTest {
|
||||
|
||||
@Test
|
||||
public void shouldGenerateRandomStrings() {
|
||||
// given
|
||||
int[] lengths = {0, 1, 19, 142, 1872};
|
||||
Pattern badChars = Pattern.compile(".*[^0-9a-z].*");
|
||||
|
||||
// when / then
|
||||
for (int length : lengths) {
|
||||
String result = RandomString.generate(length);
|
||||
assertThat("Result '" + result + "' should have length " + length,
|
||||
result.length(), equalTo(length));
|
||||
assertThat("Result '" + result + "' should only have characters a-z, 0-9",
|
||||
badChars.matcher(result).matches(), equalTo(false));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateRandomHexString() {
|
||||
// given
|
||||
int[] lengths = {0, 1, 21, 160, 1784};
|
||||
Pattern badChars = Pattern.compile(".*[^0-9a-f].*");
|
||||
|
||||
// when / then
|
||||
for (int length : lengths) {
|
||||
String result = RandomString.generateHex(length);
|
||||
assertThat("Result '" + result + "' should have length " + length,
|
||||
result.length(), equalTo(length));
|
||||
assertThat("Result '" + result + "' should only have characters a-f, 0-9",
|
||||
badChars.matcher(result).matches(), equalTo(false));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowForInvalidLength() {
|
||||
// given/when
|
||||
RandomString.generate(-3);
|
||||
|
||||
// then - throw exception
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
@ -27,30 +30,48 @@ public abstract class AbstractEncryptionMethodTest {
|
||||
* List of passwords that are hashed at runtime and then tested against; this verifies that hashes that are
|
||||
* generated are valid.
|
||||
*/
|
||||
private static final String[] INTERNAL_PASSWORDS = {"test1234", "Ab_C73", "(!#&$~`_-Aa0", "Ûïé1&?+A"};
|
||||
private static final List<String> INTERNAL_PASSWORDS =
|
||||
ImmutableList.of("test1234", "Ab_C73", "(!#&$~`_-Aa0", "Ûïé1&?+A");
|
||||
|
||||
/** The encryption method to test. */
|
||||
private EncryptionMethod method;
|
||||
/** Map with the hashes against which the entries in GIVEN_PASSWORDS are tested. */
|
||||
private Map<String, String> hashes;
|
||||
private Map<String, EncryptedPassword> 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) {
|
||||
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);
|
||||
for (int i = 0; i < GIVEN_PASSWORDS.length; ++i) {
|
||||
hashes.put(GIVEN_PASSWORDS[i], new EncryptedPassword(computedHashes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
hashes.put(GIVEN_PASSWORDS[1], result1);
|
||||
hashes.put(GIVEN_PASSWORDS[2], result2);
|
||||
hashes.put(GIVEN_PASSWORDS[3], result3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -75,31 +96,36 @@ public abstract class AbstractEncryptionMethodTest {
|
||||
|
||||
@Test
|
||||
public void testPasswordEquality() {
|
||||
for (String password : INTERNAL_PASSWORDS) {
|
||||
try {
|
||||
String hash = method.computeHash(password, getSalt(method), USERNAME);
|
||||
assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')",
|
||||
method.comparePassword(hash, password, USERNAME));
|
||||
if (!password.equals(password.toLowerCase())) {
|
||||
assertFalse("Lower-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||
method.comparePassword(hash, password.toLowerCase(), USERNAME));
|
||||
}
|
||||
if (!password.equals(password.toUpperCase())) {
|
||||
assertFalse("Upper-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||
method.comparePassword(hash, password.toUpperCase(), USERNAME));
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("EncryptionMethod '" + method + "' threw exception", e);
|
||||
List<String> internalPasswords = method.getClass().isAnnotationPresent(AsciiRestricted.class)
|
||||
? INTERNAL_PASSWORDS.subList(0, INTERNAL_PASSWORDS.size() - 1)
|
||||
: INTERNAL_PASSWORDS;
|
||||
|
||||
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()) {
|
||||
assertThat("Computing a hash with the same salt will generate the same hash",
|
||||
hash, equalTo(method.computeHash(password, salt, USERNAME)));
|
||||
}
|
||||
|
||||
assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')",
|
||||
method.comparePassword(password, encryptedPassword, USERNAME));
|
||||
if (!password.equals(password.toLowerCase())) {
|
||||
assertFalse("Lower-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||
method.comparePassword(password.toLowerCase(), encryptedPassword, USERNAME));
|
||||
}
|
||||
if (!password.equals(password.toUpperCase())) {
|
||||
assertFalse("Upper-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||
method.comparePassword(password.toUpperCase(), encryptedPassword, USERNAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doesGivenHashMatch(String password, EncryptionMethod method) {
|
||||
try {
|
||||
return method.comparePassword(hashes.get(password), password, USERNAME);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("EncryptionMethod '" + method + "' threw exception", e);
|
||||
}
|
||||
return method.comparePassword(password, hashes.get(password), USERNAME);
|
||||
}
|
||||
|
||||
// @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); }
|
||||
@ -116,43 +142,30 @@ public abstract class AbstractEncryptionMethodTest {
|
||||
if (password.equals(GIVEN_PASSWORDS[GIVEN_PASSWORDS.length - 1])) {
|
||||
delim = "); ";
|
||||
}
|
||||
try {
|
||||
System.out.println("\t\t\"" + method.computeHash(password, getSalt(method), USERNAME)
|
||||
|
||||
if (method.hasSeparateSalt()) {
|
||||
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);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("Could not generate hash", e);
|
||||
}
|
||||
}
|
||||
System.out.println("\t}");
|
||||
System.out.println("\n}");
|
||||
}
|
||||
|
||||
// TODO #358: Remove this method and use the new salt method on the interface
|
||||
private static String getSalt(EncryptionMethod method) {
|
||||
try {
|
||||
if (method instanceof BCRYPT) {
|
||||
return BCRYPT.gensalt();
|
||||
} else if (method instanceof MD5 || method instanceof WORDPRESS || method instanceof SMF
|
||||
|| method instanceof SHA512 || method instanceof SHA1 || method instanceof ROYALAUTH
|
||||
|| method instanceof DOUBLEMD5) {
|
||||
return "";
|
||||
} else if (method instanceof JOOMLA || method instanceof SALTEDSHA512) {
|
||||
return PasswordSecurity.createSalt(32);
|
||||
} else if (method instanceof SHA256 || method instanceof PHPBB || method instanceof WHIRLPOOL
|
||||
|| method instanceof MD5VB || method instanceof BCRYPT2Y) {
|
||||
return PasswordSecurity.createSalt(16);
|
||||
} else if (method instanceof WBB3) {
|
||||
return PasswordSecurity.createSalt(40);
|
||||
} else if (method instanceof XAUTH || method instanceof CryptPBKDF2Django
|
||||
|| method instanceof CryptPBKDF2) {
|
||||
return PasswordSecurity.createSalt(12);
|
||||
} else if (method instanceof WBB4) {
|
||||
return BCRYPT.gensalt(8);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
throw new IllegalStateException("Unknown EncryptionMethod for salt generation");
|
||||
/**
|
||||
* Return whether an encryption algorithm should be tested that it generates the same
|
||||
* hash for the same salt. If {@code true}, we call {@link EncryptionMethod#computeHash(String, String)}
|
||||
* and verify that {@link EncryptionMethod#computeHash(String, String, String)} generates
|
||||
* the same hash for the salt returned in the first call.
|
||||
*
|
||||
* @return Whether or not to test that the hash is the same for the same salt
|
||||
*/
|
||||
protected boolean testHashEqualityForSameSalt() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,23 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Test for {@link BCRYPT2Y}.
|
||||
*/
|
||||
@Ignore
|
||||
// TODO #369: Fix hash & add standard test
|
||||
public class BCRYPT2YTest {
|
||||
public class BCRYPT2YTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
@Test
|
||||
public void shouldCreateHash() throws NoSuchAlgorithmException {
|
||||
String salt = PasswordSecurity.createSalt(16); // As defined in PasswordSecurity
|
||||
EncryptionMethod method = new BCRYPT2Y();
|
||||
System.out.println(method.computeHash("password", salt, "testPlayer"));
|
||||
public BCRYPT2YTest() {
|
||||
super(new BCRYPT2Y(),
|
||||
"$2y$10$da641e404b982edf1c7c0uTU9BcKzfA2vWKV05q6r.dCvm/93wqVK", // password
|
||||
"$2y$10$e52c48a76f5b86f5da899uiK/HYocyPsfQXESNbP278rIz08LKEP2", // PassWord1
|
||||
"$2y$10$be6f11548dc5fb4088410ONdC0dXnJ04y1RHcJh5fVF3XK5d.qgqK", // &^%te$t?Pw@_
|
||||
"$2y$10$a8097db1fa4423b93f1b2eF6rMAGFkSX178fpROf/OvCFtrDebp6K"); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,20 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.util.WrapperMock;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Test for {@link BCRYPT}.
|
||||
*/
|
||||
public class BcryptTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
@Before
|
||||
public void setUpSettings() {
|
||||
WrapperMock.createInstance();
|
||||
Settings.bCryptLog2Rounds = 8;
|
||||
}
|
||||
|
||||
public BcryptTest() {
|
||||
super(new BCRYPT(),
|
||||
"$2a$10$6iATmYgwJVc3YONhVcZFve3Cfb5GnwvKhJ20r.hMjmcNkIT9.Uh9K", // password
|
||||
|
@ -0,0 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* Test for {@link CRAZYCRYPT1}.
|
||||
*/
|
||||
public class CRAZYCRYPT1Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public CRAZYCRYPT1Test() {
|
||||
super(new CRAZYCRYPT1(),
|
||||
"d5c76eb36417d4e97ec62609619e40a9e549a2598d0dab5a7194fd997a9305af78de2b93f958e150d19dd1e7f821043379ddf5f9c7f352bf27df91ae4913f3e8", // password
|
||||
"49c63f827c88196871e344e589bd46cc4fa6db3c27801bbad5374c0d216381977627c1d76f2114667d5dd117e046f7493eb06e4f461f4f848aa08f6f40a3e934", // PassWord1
|
||||
"6fefb0233bab6e6efb9c16f82cb0d8f569488905e2dae0e7c9dde700e7363da67213d37c44bc15f4a05854c9c21e5688389d416413c7309398aa96cb1f341d08", // &^%te$t?Pw@_
|
||||
"46f51cde7657fdec9848bad0fd8e7fb97783cf5335f94dbb5260899ab0b04022a52d651b1c45345328850178e7165308c8c213040b0864de66018a0b769d37cb"); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import org.junit.Ignore;
|
||||
|
||||
/**
|
||||
* Test for {@link CryptPBKDF2Django}.
|
||||
*/
|
||||
@Ignore
|
||||
// TODO ljacqu 20151220: testPasswordEquality fails - password matches hash for uppercase password...?
|
||||
public class CryptPBKDF2DjangoTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
public CryptPBKDF2DjangoTest() {
|
||||
|
16
src/test/java/fr/xephi/authme/security/crypts/IPB3Test.java
Normal file
16
src/test/java/fr/xephi/authme/security/crypts/IPB3Test.java
Normal file
@ -0,0 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* Test for {@link IPB3}.
|
||||
*/
|
||||
public class IPB3Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public IPB3Test() {
|
||||
super(new IPB3(),
|
||||
new EncryptedPassword("f8ecea1ce42b5babef369ff7692dbe3f", "1715b"), //password
|
||||
new EncryptedPassword("40a93731a931352e0619cdf09b975040", "ba91c"), //PassWord1
|
||||
new EncryptedPassword("a77ca982373946d5800430bd2947ba11", "a7725"), //&^%te$t?Pw@_
|
||||
new EncryptedPassword("383d7b9e2b707d6e894ec7b30e3032c3", "fa9fd")); //âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
16
src/test/java/fr/xephi/authme/security/crypts/MYBBTest.java
Normal file
16
src/test/java/fr/xephi/authme/security/crypts/MYBBTest.java
Normal file
@ -0,0 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* Test for {@link MYBB}.
|
||||
*/
|
||||
public class MYBBTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
public MYBBTest() {
|
||||
super(new MYBB(),
|
||||
new EncryptedPassword("57c7a16d860833db5030738f5a465d2b", "acdc14e6"), //password
|
||||
new EncryptedPassword("08fbdf721f2c42d9780b7d66df0ba830", "792fd7fb"), //PassWord1
|
||||
new EncryptedPassword("d602f38fb59ad9e185d5604f5d4ddb36", "4b5534a4"), //&^%te$t?Pw@_
|
||||
new EncryptedPassword("b3c39410d0ab8ae2a65c257820797fad", "e5a6cb14")); //âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
@ -7,11 +7,10 @@ public class Md5Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public Md5Test() {
|
||||
super(new MD5(),
|
||||
"5f4dcc3b5aa765d61d8327deb882cf99", // password
|
||||
"f2126d405f46ed603ff5b2950f062c96", // PassWord1
|
||||
"0833dcd2bc741f90c46bbac5498fd08f", // &^%te$t?Pw@_
|
||||
"d1accd961cb7b688c87278191c1dfed3" // âË_3(íù*
|
||||
);
|
||||
"5f4dcc3b5aa765d61d8327deb882cf99", // password
|
||||
"f2126d405f46ed603ff5b2950f062c96", // PassWord1
|
||||
"0833dcd2bc741f90c46bbac5498fd08f", // &^%te$t?Pw@_
|
||||
"d1accd961cb7b688c87278191c1dfed3"); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* Test for {@link PHPFUSION}.
|
||||
*/
|
||||
public class PHPFUSIONTest extends AbstractEncryptionMethodTest {
|
||||
|
||||
public PHPFUSIONTest() {
|
||||
super(new PHPFUSION(),
|
||||
new EncryptedPassword("f7a606c4eb3fcfbc382906476e05b06f21234a77d1a4eacc0f93f503deb69e70", "6cd1c97c55cb"), // password
|
||||
new EncryptedPassword("8a9b7bb706a3347e5f684a7cb905bfb26b9a0d099358064139ab3ed1a66aeb2b", "d6012370b73f"), // PassWord1
|
||||
new EncryptedPassword("43f2f23f44c8f89e2dbf06050bc8c77dbcdf71a7b5d28c87ec657d474e63d62d", "f75400a209a4"), // &^%te$t?Pw@_
|
||||
new EncryptedPassword("4e7f4eb7e3653d7460f1cf590def4153c6fcdf8b8e16fb95538fdf9e54a95245", "d552e0f5b23a")); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.util.WrapperMock;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Test for {@link SALTED2MD5}.
|
||||
*/
|
||||
public class SALTED2MD5Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
@Before
|
||||
public void setUpAlgorithm() {
|
||||
WrapperMock.createInstance();
|
||||
Settings.saltLength = 8;
|
||||
}
|
||||
|
||||
public SALTED2MD5Test() {
|
||||
super(new SALTED2MD5(),
|
||||
new EncryptedPassword("9f3d13dc01a6fe61fd669954174399f3", "9b5f5749"), // password
|
||||
new EncryptedPassword("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"), // PassWord1
|
||||
new EncryptedPassword("38dcb83cc68424afe3cda012700c2bb1", "eb2c3394"), // &^%te$t?Pw@_
|
||||
new EncryptedPassword("ad25606eae5b760c8a2469d65578ac39", "04eee598")); // âË_3(íù*)
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import org.junit.Ignore;
|
||||
|
||||
/**
|
||||
* Test for {@link SALTEDSHA512}.
|
||||
*/
|
||||
@Ignore
|
||||
// TODO ljacqu 20151220: Currently cannot test because of closely coupled database call inside of class
|
||||
public class SALTEDSHA512Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public SALTEDSHA512Test() {
|
||||
super(new SALTEDSHA512(),
|
||||
"c8efe95e1ab02d9a0e7c7d11d4ac3cc068a8405b5810aac3a1b8b01927ab059563438131dc995156739daf74db40ffdc79b78f6aec9b2a468fe106b88c66c204", // password
|
||||
"74c61af1bcbb3293cdc0959c7323d50be28c167eddc7a1b7eb029e38263c2cfb6eb090f41370a65249752aa316fa851091c2bd8420302e87d383529beea735b4", // PassWord1
|
||||
"08eefcca4a17876441ebe61a02e8bc62cab7502dd87f8ec3b7f82edb2adace791b8dad31e74c5513cf99be502b732f5c5efffb239f4590d5c600d066a7037908", // &^%te$t?Pw@_
|
||||
"a122490c4c7c18ad665b5ac9617c948741468a787a2ba42c6fd2530ea1d7874681b8575ee9a8907c42ff65dac69e4ada2852789759c17d51865ca915b259a65a"); // âË_3(íù*
|
||||
new EncryptedPassword("dea7a37cecf5384ae8e347fd1411efb51364b6ba1b328695de3b354612c1d7010807e8b7051c40f740e498490e1f133e2c2408327d13fbdd68e1b1f6d548e624", "29f8a3c52147f987fee7ba3e0fb311bd"), // password
|
||||
new EncryptedPassword("7c06225aac574d2dc7c81a2ed306637adf025715f52083e05bdab014faaa234e24a97d0e69ea0108dfa77cc9228e58be319ee677e679b5d1ad168d40e50a42f6", "8ea37b85d020b98f60c0fe9b8ec9296c"), // PassWord1
|
||||
new EncryptedPassword("55711adbe03c9616f3505f0d57077fdd528c32243eb6f9840c1a6ff9e553940d6b89790750ebd52ebda63ca793fbe9980d54057af40836820c648750fe22d49c", "9f58079631ef21d32b4710694f1f461b"), // &^%te$t?Pw@_
|
||||
new EncryptedPassword("29dc5be8702975ea4563ed3de5b145e2d2f1c37ae661bbe0d3e94d964402cf09d539d65f3b90ff6921ea3d40727f76fb38fb34d1e5c2d62238c4e0203efc372f", "048bb76168265d906f1fd1f81d0616a9")); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,20 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import org.junit.Ignore;
|
||||
|
||||
/**
|
||||
* Test for {@link WBB3}.
|
||||
*/
|
||||
@Ignore
|
||||
// TODO #364 ljacqu 20151220: Unignore test after fixing closely coupled DB dependency
|
||||
public class WBB3Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public WBB3Test() {
|
||||
super(new WBB3(),
|
||||
"ca426c4d20a82cd24c7bb07d94d69f3757e3d07d", // password
|
||||
"72d59d27674a3cace2600ff152ba8b46274e27e9", // PassWord1
|
||||
"23daf26602e52591156968a14c2a6592b5be4743", // &^%te$t?Pw@_
|
||||
"d3908efe4a15314066391dd8572883c70b16fd8a"); // âË_3(íù*
|
||||
new EncryptedPassword("8df818ef7d56075ab2744f74b98ad68a375ccac4", "b7415b355492ea60314f259a35733a3092c03e3f"), // password
|
||||
new EncryptedPassword("106da5cf5df92cb845e12cf62cbdb5235b6dc693", "6110f19b2b52910dccf592a19c59126873f42e69"), // PassWord1
|
||||
new EncryptedPassword("940a9fb7acec0178c6691e8b3c14bd7d789078b1", "f9dd501ff3d1bf74904f9e89649e378429af56e7"), // &^%te$t?Pw@_
|
||||
new EncryptedPassword("0fa12e8d96c9e95f73aa91f3b76f8cdc815ec8a5", "736be8669f6159ddb2d5b47a3e6428cdb8b324de")); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,4 +12,10 @@ public class WORDPRESSTest extends AbstractEncryptionMethodTest {
|
||||
"$P$BjzPjjzPjrAOyB1V0WFdpisgCTFx.N/", // &^%te$t?Pw@_
|
||||
"$P$BjzPjxxyjp2QdKcab/oTW8l/W0AgE21"); // âË_3(íù*
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean testHashEqualityForSameSalt() {
|
||||
// We need to skip the test because Wordpress uses an "internal salt" that is not exposed to the outside
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user