Check valid password via service

- Create validation service; fixes same code being duplicated in four places
   - Goal is to remove Utils class, by moving methods to validation service or other services
 - Remove unused properties in legacy settings
This commit is contained in:
ljacqu
2016-04-02 22:44:20 +02:00
parent 73161de808
commit 4f86604699
15 changed files with 263 additions and 246 deletions
+7 -4
View File
@@ -62,6 +62,7 @@ import fr.xephi.authme.util.GeoLiteAPI;
import fr.xephi.authme.util.MigrationService;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.ValidationService;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -260,8 +261,9 @@ public class AuthMe extends JavaPlugin {
// Set up the permissions manager and command handler
permsMan = initializePermissionsManager();
ValidationService validationService = new ValidationService(newSettings);
commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, ipAddressManager,
pluginHooks, spawnLoader, antiBot);
pluginHooks, spawnLoader, antiBot, validationService);
// AntiBot delay
BukkitService bukkitService = new BukkitService(this);
@@ -299,7 +301,7 @@ public class AuthMe extends JavaPlugin {
// Set up the management
ProcessService processService = new ProcessService(newSettings, messages, this, database, ipAddressManager,
passwordSecurity, pluginHooks, spawnLoader);
passwordSecurity, pluginHooks, spawnLoader, validationService);
management = new Management(this, processService, database, PlayerCache.getInstance());
// Set up the BungeeCord hook
@@ -432,12 +434,13 @@ public class AuthMe extends JavaPlugin {
private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages,
PasswordSecurity passwordSecurity, NewSetting settings,
IpAddressManager ipAddressManager, PluginHooks pluginHooks,
SpawnLoader spawnLoader, AntiBot antiBot) {
SpawnLoader spawnLoader, AntiBot antiBot,
ValidationService validationService) {
HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER));
Set<CommandDescription> baseCommands = CommandInitializer.buildCommands();
CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager);
CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity,
permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot);
permissionsManager, settings, ipAddressManager, pluginHooks, spawnLoader, antiBot, validationService);
return new CommandHandler(commandService);
}
@@ -15,6 +15,7 @@ import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
import java.util.List;
@@ -36,6 +37,7 @@ public class CommandService {
private final PluginHooks pluginHooks;
private final SpawnLoader spawnLoader;
private final AntiBot antiBot;
private final ValidationService validationService;
/**
* Constructor.
@@ -54,7 +56,7 @@ public class CommandService {
public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages,
PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings,
IpAddressManager ipAddressManager, PluginHooks pluginHooks, SpawnLoader spawnLoader,
AntiBot antiBot) {
AntiBot antiBot, ValidationService validationService) {
this.authMe = authMe;
this.messages = messages;
this.helpProvider = helpProvider;
@@ -66,6 +68,7 @@ public class CommandService {
this.pluginHooks = pluginHooks;
this.spawnLoader = spawnLoader;
this.antiBot = antiBot;
this.validationService = validationService;
}
/**
@@ -219,4 +222,15 @@ public class CommandService {
return antiBot;
}
/**
* Verifies whether a password is valid according to the plugin settings.
*
* @param password the password to verify
* @param username the username the password is associated with
* @return message key with the password error, or {@code null} if password is valid
*/
public MessageKey validatePassword(String password, String username) {
return validationService.validatePassword(password, username);
}
}
@@ -7,8 +7,6 @@ import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.command.CommandSender;
import java.util.List;
@@ -22,30 +20,16 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
public void executeCommand(final CommandSender sender, List<String> arguments,
final CommandService commandService) {
// Get the player and password
String playerName = arguments.get(0);
final String playerName = arguments.get(0);
final String playerPass = arguments.get(1);
// Validate the password
String playerPassLowerCase = playerPass.toLowerCase();
if (!playerPassLowerCase.matches(commandService.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX))) {
commandService.send(sender, MessageKey.PASSWORD_MATCH_ERROR);
return;
}
if (playerPassLowerCase.equalsIgnoreCase(playerName)) {
commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR);
return;
}
if (playerPassLowerCase.length() < commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)
|| playerPassLowerCase.length() > commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) {
commandService.send(sender, MessageKey.INVALID_PASSWORD_LENGTH);
return;
}
// TODO #602 20160312: The UNSAFE_PASSWORDS should be all lowercase
// -> introduce a lowercase String list property type
if (commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(playerPassLowerCase)) {
commandService.send(sender, MessageKey.PASSWORD_UNSAFE_ERROR);
MessageKey passwordError = commandService.validatePassword(playerPass, playerName);
if (passwordError != null) {
commandService.send(sender, passwordError);
return;
}
// Set the password
final String playerNameLowerCase = playerName.toLowerCase();
commandService.runTaskAsynchronously(new Runnable() {
@@ -6,8 +6,6 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
@@ -25,26 +23,14 @@ public class RegisterAdminCommand implements ExecutableCommand {
final String playerName = arguments.get(0);
final String playerPass = arguments.get(1);
final String playerNameLowerCase = playerName.toLowerCase();
final String playerPassLowerCase = playerPass.toLowerCase();
// Command logic
if (!playerPassLowerCase.matches(Settings.getPassRegex)) {
commandService.send(sender, MessageKey.PASSWORD_MATCH_ERROR);
return;
}
if (playerPassLowerCase.equalsIgnoreCase(playerName)) {
commandService.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR);
return;
}
if (playerPassLowerCase.length() < commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)
|| playerPassLowerCase.length() > commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) {
commandService.send(sender, MessageKey.INVALID_PASSWORD_LENGTH);
return;
}
if (!Settings.unsafePasswords.isEmpty() && Settings.unsafePasswords.contains(playerPassLowerCase)) {
commandService.send(sender, MessageKey.PASSWORD_UNSAFE_ERROR);
MessageKey passwordError = commandService.validatePassword(playerPass, playerName);
if (passwordError != null) {
commandService.send(sender, passwordError);
return;
}
commandService.runTaskAsynchronously(new Runnable() {
@Override
@@ -5,8 +5,6 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.ChangePasswordTask;
import org.bukkit.entity.Player;
@@ -30,22 +28,9 @@ public class ChangePasswordCommand extends PlayerCommand {
}
// Make sure the password is allowed
String playerPassLowerCase = newPassword.toLowerCase();
if (!playerPassLowerCase.matches(commandService.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX))) {
commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR);
return;
}
if (playerPassLowerCase.equalsIgnoreCase(name)) {
commandService.send(player, MessageKey.PASSWORD_IS_USERNAME_ERROR);
return;
}
if (playerPassLowerCase.length() < commandService.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)
|| playerPassLowerCase.length() > commandService.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) {
commandService.send(player, MessageKey.INVALID_PASSWORD_LENGTH);
return;
}
if (commandService.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(playerPassLowerCase)) {
commandService.send(player, MessageKey.PASSWORD_UNSAFE_ERROR);
MessageKey passwordError = commandService.validatePassword(newPassword, name);
if (passwordError != null) {
commandService.send(player, passwordError);
return;
}
@@ -41,7 +41,7 @@ public class Management {
}
public void performRegister(final Player player, final String password, final String email) {
runTask(new AsyncRegister(player, password, email, plugin, dataSource, processService));
runTask(new AsyncRegister(player, password, email, plugin, dataSource, playerCache, processService));
}
public void performUnregister(final Player player, final String password, final boolean force) {
@@ -11,6 +11,7 @@ import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Event;
import org.bukkit.scheduler.BukkitTask;
@@ -28,10 +29,11 @@ public class ProcessService {
private final PasswordSecurity passwordSecurity;
private final PluginHooks pluginHooks;
private final SpawnLoader spawnLoader;
private final ValidationService validationService;
public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource,
IpAddressManager ipAddressManager, PasswordSecurity passwordSecurity, PluginHooks pluginHooks,
SpawnLoader spawnLoader) {
SpawnLoader spawnLoader, ValidationService validationService) {
this.settings = settings;
this.messages = messages;
this.authMe = authMe;
@@ -40,6 +42,7 @@ public class ProcessService {
this.passwordSecurity = passwordSecurity;
this.pluginHooks = pluginHooks;
this.spawnLoader = spawnLoader;
this.validationService = validationService;
}
/**
@@ -199,4 +202,15 @@ public class ProcessService {
return dataSource;
}
/**
* Verifies whether a password is valid according to the plugin settings.
*
* @param password the password to verify
* @param username the username the password is associated with
* @return message key with the password error, or {@code null} if password is valid
*/
public MessageKey validatePassword(String password, String username) {
return validationService.validatePassword(password, username);
}
}
@@ -12,6 +12,8 @@ import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.TwoFactor;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.Bukkit;
@@ -30,10 +32,11 @@ public class AsyncRegister implements Process {
private final String email;
private final AuthMe plugin;
private final DataSource database;
private final PlayerCache playerCache;
private final ProcessService service;
public AsyncRegister(Player player, String password, String email, AuthMe plugin, DataSource data,
ProcessService service) {
PlayerCache playerCache, ProcessService service) {
this.player = player;
this.password = password;
this.name = player.getName().toLowerCase();
@@ -41,32 +44,24 @@ public class AsyncRegister implements Process {
this.plugin = plugin;
this.database = data;
this.ip = service.getIpAddressManager().getPlayerIp(player);
this.playerCache = playerCache;
this.service = service;
}
private boolean preRegisterCheck() {
String passLow = password.toLowerCase();
if (PlayerCache.getInstance().isAuthenticated(name)) {
if (playerCache.isAuthenticated(name)) {
service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return false;
} else if (!Settings.isRegistrationEnabled) {
} else if (!service.getProperty(RegistrationSettings.IS_ENABLED)) {
service.send(player, MessageKey.REGISTRATION_DISABLED);
return false;
}
//check the password safety only if it's not a automatically generated password
if (service.getProperty(SecuritySettings.PASSWORD_HASH) != HashAlgorithm.TWO_FACTOR) {
if (!passLow.matches(Settings.getPassRegex)) {
service.send(player, MessageKey.PASSWORD_MATCH_ERROR);
return false;
} else if (passLow.equalsIgnoreCase(player.getName())) {
service.send(player, MessageKey.PASSWORD_IS_USERNAME_ERROR);
return false;
} else if (password.length() < Settings.getPasswordMinLen || password.length() > Settings.passwordMaxLength) {
service.send(player, MessageKey.INVALID_PASSWORD_LENGTH);
return false;
} else if (!Settings.unsafePasswords.isEmpty() && Settings.unsafePasswords.contains(password.toLowerCase())) {
service.send(player, MessageKey.PASSWORD_UNSAFE_ERROR);
MessageKey passwordError = service.validatePassword(password, player.getName());
if (passwordError != null) {
service.send(player, passwordError);
return false;
}
}
@@ -75,15 +70,17 @@ public class AsyncRegister implements Process {
if (database.isAuthAvailable(name)) {
service.send(player, MessageKey.NAME_ALREADY_REGISTERED);
return false;
} else if(Settings.getmaxRegPerIp > 0
&& !ip.equalsIgnoreCase("127.0.0.1")
&& !ip.equalsIgnoreCase("localhost")
}
final int maxRegPerIp = service.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP);
if (maxRegPerIp > 0
&& !"127.0.0.1".equalsIgnoreCase(ip)
&& !"localhost".equalsIgnoreCase(ip)
&& !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)) {
int maxReg = Settings.getmaxRegPerIp;
List<String> otherAccounts = database.getAllAuthsByIp(ip);
if (otherAccounts.size() >= maxReg) {
service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxReg),
Integer.toString(otherAccounts.size()), StringUtils.join(", ", otherAccounts.toString()));
if (otherAccounts.size() >= maxRegPerIp) {
service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerIp),
Integer.toString(otherAccounts.size()), StringUtils.join(", ", otherAccounts));
return false;
}
}
@@ -38,11 +38,10 @@ public final class Settings {
public static List<String> forceCommandsAsConsole;
public static List<String> forceRegisterCommands;
public static List<String> forceRegisterCommandsAsConsole;
public static List<String> unsafePasswords;
public static HashAlgorithm getPasswordHash;
public static Pattern nickPattern;
public static boolean useLogging = false;
public static boolean isChatAllowed, isPermissionCheckEnabled, isRegistrationEnabled,
public static boolean isChatAllowed, isPermissionCheckEnabled,
isForcedRegistrationEnabled, isTeleportToSpawnEnabled,
isSessionsEnabled, isAllowRestrictedIp,
isMovementAllowed, isKickNonRegisteredEnabled,
@@ -64,10 +63,10 @@ public final class Settings {
unRegisteredGroup,
backupWindowsPath, getRegisteredGroup,
rakamakUsers, rakamakUsersIp, getmailAccount, defaultWorld,
spawnPriority, crazyloginFileName, getPassRegex, sendPlayerTo;
spawnPriority, crazyloginFileName, sendPlayerTo;
public static int getWarnMessageInterval, getSessionTimeout,
getRegistrationTimeout, getMaxNickLength, getMinNickLength,
getPasswordMinLen, getMovementRadius, getmaxRegPerIp,
getPasswordMinLen, getMovementRadius,
getNonActivatedGroup, passwordMaxLength, getRecoveryPassLength,
getMailPort, maxLoginTry, captchaLength, saltLength,
getmaxRegPerEmail, bCryptLog2Rounds, getMaxLoginPerIp, getMaxJoinPerIp;
@@ -86,7 +85,6 @@ public final class Settings {
private static void loadVariables() {
isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK);
isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true);
isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true);
isTeleportToSpawnEnabled = load(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN);
getWarnMessageInterval = load(RegistrationSettings.MESSAGE_INTERVAL);
isSessionsEnabled = load(PluginSettings.SESSIONS_ENABLED);
@@ -110,7 +108,6 @@ public final class Settings {
isForceSpawnLocOnJoinEnabled = configFile.getBoolean("settings.restrictions.ForceSpawnLocOnJoinEnabled", false);
isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation", false);
isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode", false);
getmaxRegPerIp = configFile.getInt("settings.restrictions.maxRegPerIp", 1);
getPasswordHash = load(SecuritySettings.PASSWORD_HASH);
getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP);
getNonActivatedGroup = configFile.getInt("ExternalBoardOptions.nonActivedUserGroup", -1);
@@ -174,7 +171,6 @@ public final class Settings {
forceCommandsAsConsole = configFile.getStringList("settings.forceCommandsAsConsole");
recallEmail = configFile.getBoolean("Email.recallPlayers", false);
useWelcomeMessage = load(RegistrationSettings.USE_WELCOME_MESSAGE);
unsafePasswords = configFile.getStringList("settings.security.unsafePasswords");
countriesBlacklist = configFile.getStringList("Protection.countriesBlacklist");
broadcastWelcomeMessage = load(RegistrationSettings.BROADCAST_WELCOME_MESSAGE);
forceRegKick = configFile.getBoolean("settings.registration.forceKickAfterRegister", false);
@@ -188,7 +184,6 @@ public final class Settings {
delayJoinMessage = load(RegistrationSettings.DELAY_JOIN_MESSAGE);
noTeleport = load(RestrictionSettings.NO_TELEPORT);
crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db");
getPassRegex = configFile.getString("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*");
forceRegisterCommands = configFile.getStringList("settings.forceRegisterCommands");
forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole");
customAttributes = configFile.getBoolean("Hooks.customAttributes");
@@ -198,21 +193,6 @@ public final class Settings {
keepCollisionsDisabled = configFile.getBoolean("settings.keepCollisionsDisabled");
}
/**
* Method switchAntiBotMod.
*
* @param mode boolean
*/
public static void switchAntiBotMod(boolean mode) {
if (mode) {
isKickNonRegisteredEnabled = true;
antiBotInAction = true;
} else {
isKickNonRegisteredEnabled = configFile.getBoolean("settings.restrictions.kickNonRegistered", false);
antiBotInAction = false;
}
}
/**
* Load the value via the new Property setup for temporary support within this old settings manager.
*
@@ -0,0 +1,42 @@
package fr.xephi.authme.util;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
/**
* Validation service.
*/
public class ValidationService {
private final NewSetting settings;
public ValidationService(NewSetting settings) {
this.settings = settings;
}
/**
* Verifies whether a password is valid according to the plugin settings.
*
* @param password the password to verify
* @param username the username the password is associated with
* @return message key with the password error, or {@code null} if password is valid
*/
public MessageKey validatePassword(String password, String username) {
String passLow = password.toLowerCase();
if (!passLow.matches(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX))) {
return MessageKey.PASSWORD_MATCH_ERROR;
} else if (passLow.equalsIgnoreCase(username)) {
return MessageKey.PASSWORD_IS_USERNAME_ERROR;
} else if (password.length() < settings.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH)
|| password.length() > settings.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) {
return MessageKey.INVALID_PASSWORD_LENGTH;
} else if (settings.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(passLow)) {
// TODO #602 20160312: The UNSAFE_PASSWORDS should be all lowercase
// -> introduce a lowercase String list property type
return MessageKey.PASSWORD_UNSAFE_ERROR;
}
return null;
}
}