mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-24 17:47:38 +01:00
#930 Create registration captcha manager
- Introduce registration captcha manager, rename login captcha manager accordingly - Integrate reg. captcha manager into /register command Open points: - Refactor common captcha functionality into abstract superclass - If captcha before /register necessary, show appropriate message to player immediately - Unit tests
This commit is contained in:
parent
67a6a42dfe
commit
33904c09e9
@ -1,7 +1,8 @@
|
||||
package fr.xephi.authme.command.executable.captcha;
|
||||
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.data.CaptchaManager;
|
||||
import fr.xephi.authme.data.LoginCaptchaManager;
|
||||
import fr.xephi.authme.data.RegistrationCaptchaManager;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
@ -17,7 +18,10 @@ public class CaptchaCommand extends PlayerCommand {
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private CaptchaManager captchaManager;
|
||||
private LoginCaptchaManager loginCaptchaManager;
|
||||
|
||||
@Inject
|
||||
private RegistrationCaptchaManager registrationCaptchaManager;
|
||||
|
||||
@Inject
|
||||
private CommonService commonService;
|
||||
@ -27,25 +31,40 @@ public class CaptchaCommand extends PlayerCommand {
|
||||
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
final String playerName = player.getName().toLowerCase();
|
||||
final String name = player.getName();
|
||||
|
||||
if (playerCache.isAuthenticated(playerName)) {
|
||||
if (playerCache.isAuthenticated(name)) {
|
||||
commonService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
|
||||
} else if (!captchaManager.isCaptchaRequired(playerName)) {
|
||||
commonService.send(player, MessageKey.USAGE_LOGIN);
|
||||
} else if (loginCaptchaManager.isCaptchaRequired(name)) {
|
||||
checkLoginCaptcha(player, arguments.get(0));
|
||||
} else if (registrationCaptchaManager.isCaptchaRequired(name)) {
|
||||
checkRegisterCaptcha(player, arguments.get(0));
|
||||
} else {
|
||||
checkCaptcha(player, arguments.get(0));
|
||||
MessageKey errorMessage = playerCache.isAuthenticated(name)
|
||||
? MessageKey.ALREADY_LOGGED_IN_ERROR : MessageKey.USAGE_LOGIN;
|
||||
commonService.send(player, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCaptcha(Player player, String captchaCode) {
|
||||
final boolean isCorrectCode = captchaManager.checkCode(player.getName(), captchaCode);
|
||||
private void checkLoginCaptcha(Player player, String captchaCode) {
|
||||
final boolean isCorrectCode = loginCaptchaManager.checkCode(player.getName(), captchaCode);
|
||||
if (isCorrectCode) {
|
||||
commonService.send(player, MessageKey.CAPTCHA_SUCCESS);
|
||||
commonService.send(player, MessageKey.LOGIN_MESSAGE);
|
||||
limboService.unmuteMessageTask(player);
|
||||
} else {
|
||||
String newCode = captchaManager.generateCode(player.getName());
|
||||
String newCode = loginCaptchaManager.generateCode(player.getName());
|
||||
commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegisterCaptcha(Player player, String captchaCode) {
|
||||
final boolean isCorrectCode = registrationCaptchaManager.checkCode(player.getName(), captchaCode);
|
||||
if (isCorrectCode) {
|
||||
commonService.send(player, MessageKey.CAPTCHA_SUCCESS);
|
||||
commonService.send(player, MessageKey.REGISTER_MESSAGE);
|
||||
} else {
|
||||
String newCode = registrationCaptchaManager.generateCode(player.getName());
|
||||
commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.register;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.data.RegistrationCaptchaManager;
|
||||
import fr.xephi.authme.mail.EmailService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.process.Management;
|
||||
@ -45,8 +46,15 @@ public class RegisterCommand extends PlayerCommand {
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
@Inject
|
||||
private RegistrationCaptchaManager registrationCaptchaManager;
|
||||
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
if (!isCaptchaFulfilled(player)) {
|
||||
return; // isCaptchaFulfilled handles informing the player on failure
|
||||
}
|
||||
|
||||
if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
|
||||
//for two factor auth we don't need to check the usage
|
||||
management.performRegister(RegistrationMethod.TWO_FACTOR_REGISTRATION,
|
||||
@ -74,7 +82,16 @@ public class RegisterCommand extends PlayerCommand {
|
||||
|
||||
@Override
|
||||
public MessageKey getArgumentsMismatchMessage() {
|
||||
return MessageKey.USAGE_LOGIN;
|
||||
return MessageKey.USAGE_REGISTER;
|
||||
}
|
||||
|
||||
private boolean isCaptchaFulfilled(Player player) {
|
||||
if (registrationCaptchaManager.isCaptchaRequired(player.getName())) {
|
||||
String code = registrationCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName());
|
||||
commonService.send(player, MessageKey.CAPTCHA_FOR_REGISTRATION_REQUIRED, code);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handlePasswordRegistration(Player player, List<String> arguments) {
|
||||
|
@ -12,9 +12,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Manager for the handling of captchas.
|
||||
* Manager for the handling of captchas after too many failed login attempts.
|
||||
*/
|
||||
public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
public class LoginCaptchaManager implements SettingsDependent, HasCleanup {
|
||||
|
||||
private final TimedCounter<String> playerCounts;
|
||||
private final ConcurrentHashMap<String, String> captchaCodes;
|
||||
@ -24,7 +24,7 @@ public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
private int captchaLength;
|
||||
|
||||
@Inject
|
||||
CaptchaManager(Settings settings) {
|
||||
LoginCaptchaManager(Settings settings) {
|
||||
this.captchaCodes = new ConcurrentHashMap<>();
|
||||
long countTimeout = settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET);
|
||||
this.playerCounts = new TimedCounter<>(countTimeout, TimeUnit.MINUTES);
|
||||
@ -36,7 +36,7 @@ public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
*
|
||||
* @param name the player's name
|
||||
*/
|
||||
public void increaseCount(String name) {
|
||||
public void increaseLoginFailureCount(String name) {
|
||||
if (isEnabled) {
|
||||
String playerLower = name.toLowerCase();
|
||||
playerCounts.increment(playerLower);
|
||||
@ -44,7 +44,7 @@ public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given player is required to solve a captcha.
|
||||
* Returns whether the given player is required to solve a captcha before he can use /login again.
|
||||
*
|
||||
* @param name the name of the player to verify
|
||||
* @return true if the player has to solve a captcha, false otherwise
|
||||
@ -84,12 +84,13 @@ public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
* @return true if the code matches or if no captcha is required for the player, false otherwise
|
||||
*/
|
||||
public boolean checkCode(String name, String code) {
|
||||
String savedCode = captchaCodes.get(name.toLowerCase());
|
||||
final String nameLowerCase = name.toLowerCase();
|
||||
String savedCode = captchaCodes.get(nameLowerCase);
|
||||
if (savedCode == null) {
|
||||
return true;
|
||||
} else if (savedCode.equalsIgnoreCase(code)) {
|
||||
captchaCodes.remove(name.toLowerCase());
|
||||
playerCounts.remove(name.toLowerCase());
|
||||
captchaCodes.remove(nameLowerCase);
|
||||
playerCounts.remove(nameLowerCase);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -100,7 +101,7 @@ public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
*
|
||||
* @param name the player's name
|
||||
*/
|
||||
public void resetCounts(String name) {
|
||||
public void resetLoginFailureCount(String name) {
|
||||
if (isEnabled) {
|
||||
captchaCodes.remove(name.toLowerCase());
|
||||
playerCounts.remove(name.toLowerCase());
|
||||
@ -109,7 +110,7 @@ public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||
|
||||
@Override
|
||||
public void reload(Settings settings) {
|
||||
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
|
||||
this.isEnabled = settings.getProperty(SecuritySettings.ENABLE_LOGIN_FAILURE_CAPTCHA);
|
||||
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
|
||||
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
|
||||
long countTimeout = settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET);
|
@ -0,0 +1,98 @@
|
||||
package fr.xephi.authme.data;
|
||||
|
||||
import fr.xephi.authme.initialization.HasCleanup;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.RandomStringUtils;
|
||||
import fr.xephi.authme.util.expiring.ExpiringSet;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Captcha handler for registration.
|
||||
*/
|
||||
public class RegistrationCaptchaManager implements SettingsDependent, HasCleanup {
|
||||
|
||||
private static final int MINUTES_VALID_FOR_REGISTRATION = 30;
|
||||
|
||||
private final Map<String, String> captchaCodes;
|
||||
private final ExpiringSet<String> verifiedNamesForRegistration;
|
||||
|
||||
private boolean isEnabledForRegistration;
|
||||
private int captchaLength;
|
||||
|
||||
@Inject
|
||||
RegistrationCaptchaManager(Settings settings) {
|
||||
this.captchaCodes = new ConcurrentHashMap<>();
|
||||
this.verifiedNamesForRegistration = new ExpiringSet<>(MINUTES_VALID_FOR_REGISTRATION, TimeUnit.MINUTES);
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given player is required to solve a captcha before he can register.
|
||||
*
|
||||
* @param name the name of the player to verify
|
||||
* @return true if the player has to solve a captcha, false otherwise
|
||||
*/
|
||||
public boolean isCaptchaRequired(String name) {
|
||||
return isEnabledForRegistration && !verifiedNamesForRegistration.contains(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stored captcha for the player or generates and saves a new one.
|
||||
*
|
||||
* @param name the player's name
|
||||
* @return the code the player is required to enter
|
||||
*/
|
||||
public String getCaptchaCodeOrGenerateNew(String name) {
|
||||
String code = captchaCodes.get(name.toLowerCase());
|
||||
return code == null ? generateCode(name) : code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a code for the player and returns it.
|
||||
*
|
||||
* @param name the name of the player to generate a code for
|
||||
* @return the generated code
|
||||
*/
|
||||
public String generateCode(String name) {
|
||||
String code = RandomStringUtils.generate(captchaLength);
|
||||
captchaCodes.put(name.toLowerCase(), code);
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given code against the existing one and resets the player's auth failure count upon success.
|
||||
*
|
||||
* @param name the name of the player to check
|
||||
* @param code the supplied code
|
||||
* @return true if the code matches or if no captcha is required for the player, false otherwise
|
||||
*/
|
||||
public boolean checkCode(String name, String code) {
|
||||
final String nameLowerCase = name.toLowerCase();
|
||||
String savedCode = captchaCodes.get(nameLowerCase);
|
||||
if (savedCode == null) {
|
||||
return true;
|
||||
} else if (savedCode.equalsIgnoreCase(code)) {
|
||||
captchaCodes.remove(nameLowerCase);
|
||||
verifiedNamesForRegistration.add(nameLowerCase);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Settings settings) {
|
||||
this.isEnabledForRegistration = settings.getProperty(SecuritySettings.ENABLE_CAPTCHA_FOR_REGISTRATION);
|
||||
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performCleanup() {
|
||||
verifiedNamesForRegistration.removeExpiredEntries();
|
||||
}
|
||||
}
|
@ -134,6 +134,9 @@ public enum MessageKey {
|
||||
/** Captcha code solved correctly! */
|
||||
CAPTCHA_SUCCESS("valid_captcha"),
|
||||
|
||||
/** To register you have to solve a captcha code first, please use the command: /captcha <theCaptcha> */
|
||||
CAPTCHA_FOR_REGISTRATION_REQUIRED("captcha_for_registration", "<theCaptcha>"),
|
||||
|
||||
/** A VIP player has joined the server when it was full! */
|
||||
KICK_FOR_VIP("kick_forvip"),
|
||||
|
||||
|
@ -2,7 +2,7 @@ package fr.xephi.authme.process.login;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.CaptchaManager;
|
||||
import fr.xephi.authme.data.LoginCaptchaManager;
|
||||
import fr.xephi.authme.data.TempbanManager;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
@ -61,7 +61,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
private PasswordSecurity passwordSecurity;
|
||||
|
||||
@Inject
|
||||
private CaptchaManager captchaManager;
|
||||
private LoginCaptchaManager loginCaptchaManager;
|
||||
|
||||
@Inject
|
||||
private TempbanManager tempbanManager;
|
||||
@ -163,15 +163,15 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
final String name = player.getName().toLowerCase();
|
||||
|
||||
// If captcha is required send a message to the player and deny to log in
|
||||
if (captchaManager.isCaptchaRequired(name)) {
|
||||
service.send(player, MessageKey.USAGE_CAPTCHA, captchaManager.getCaptchaCodeOrGenerateNew(name));
|
||||
if (loginCaptchaManager.isCaptchaRequired(name)) {
|
||||
service.send(player, MessageKey.USAGE_CAPTCHA, loginCaptchaManager.getCaptchaCodeOrGenerateNew(name));
|
||||
return false;
|
||||
}
|
||||
|
||||
final String ip = PlayerUtils.getPlayerIp(player);
|
||||
|
||||
// Increase the counts here before knowing the result of the login.
|
||||
captchaManager.increaseCount(name);
|
||||
loginCaptchaManager.increaseLoginFailureCount(name);
|
||||
tempbanManager.increaseCount(ip, name);
|
||||
|
||||
if (passwordSecurity.comparePassword(password, auth.getPassword(), player.getName())) {
|
||||
@ -202,10 +202,10 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
service.send(player, MessageKey.WRONG_PASSWORD);
|
||||
|
||||
// If the authentication fails check if Captcha is required and send a message to the player
|
||||
if (captchaManager.isCaptchaRequired(player.getName())) {
|
||||
if (loginCaptchaManager.isCaptchaRequired(player.getName())) {
|
||||
limboService.muteMessageTask(player);
|
||||
service.send(player, MessageKey.USAGE_CAPTCHA,
|
||||
captchaManager.getCaptchaCodeOrGenerateNew(player.getName()));
|
||||
loginCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName()));
|
||||
} else if (emailService.hasAllInformation() && !Utils.isEmailEmpty(auth.getEmail())) {
|
||||
service.send(player, MessageKey.FORGOT_PASSWORD_MESSAGE);
|
||||
}
|
||||
@ -232,7 +232,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
|
||||
// Successful login, so reset the captcha & temp ban count
|
||||
final String name = player.getName();
|
||||
captchaManager.resetCounts(name);
|
||||
loginCaptchaManager.resetLoginFailureCount(name);
|
||||
tempbanManager.resetCount(ip, name);
|
||||
player.setNoDamageTicks(0);
|
||||
|
||||
|
@ -29,7 +29,7 @@ public final class SecuritySettings implements SettingsHolder {
|
||||
newProperty("Security.console.logConsole", true);
|
||||
|
||||
@Comment("Enable captcha when a player uses wrong password too many times")
|
||||
public static final Property<Boolean> USE_CAPTCHA =
|
||||
public static final Property<Boolean> ENABLE_LOGIN_FAILURE_CAPTCHA =
|
||||
newProperty("Security.captcha.useCaptcha", false);
|
||||
|
||||
@Comment("Max allowed tries before a captcha is required")
|
||||
@ -44,6 +44,10 @@ public final class SecuritySettings implements SettingsHolder {
|
||||
public static final Property<Integer> CAPTCHA_COUNT_MINUTES_BEFORE_RESET =
|
||||
newProperty("Security.captcha.captchaCountReset", 60);
|
||||
|
||||
@Comment("Require captcha before a player may register?")
|
||||
public static final Property<Boolean> ENABLE_CAPTCHA_FOR_REGISTRATION =
|
||||
newProperty("Security.captcha.requireForRegistration", false);
|
||||
|
||||
@Comment("Minimum length of password")
|
||||
public static final Property<Integer> MIN_PASSWORD_LENGTH =
|
||||
newProperty("settings.security.minPasswordLength", 5);
|
||||
|
@ -91,9 +91,10 @@ change_password_expired: 'You cannot change your password using this command any
|
||||
email_cooldown_error: '&cAn email was already sent recently. You must wait %time before you can send a new one.'
|
||||
|
||||
# Captcha
|
||||
usage_captcha: '&3To login you have to solve a captcha code, please use the command: /captcha <theCaptcha>'
|
||||
usage_captcha: '&3To log in you have to solve a captcha code, please use the command: /captcha <theCaptcha>'
|
||||
wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!'
|
||||
valid_captcha: '&2Captcha code solved correctly!'
|
||||
captcha_for_registration: 'To register you have to solve a captcha first, please use the command: /captcha <theCaptcha>'
|
||||
|
||||
# Verification code
|
||||
verification_code_required: '&3This command is sensitive and requires an email verification! Check your inbox and follow the email''s instructions.'
|
||||
@ -101,7 +102,7 @@ usage_verification_code: '&cUsage: /verification <code>'
|
||||
incorrect_verification_code: '&cIncorrect code, please type "/verification <code>" into the chat, using the code you received by email'
|
||||
verification_code_verified: '&2Your identity has been verified! You can now execute all commands within the current session!'
|
||||
verification_code_already_verified: '&2You can already execute every sensitive command within the current session!'
|
||||
verification_code_expired: '&3Your code has expired! Execute an other sensitive command to get a new code!'
|
||||
verification_code_expired: '&3Your code has expired! Execute another sensitive command to get a new code!'
|
||||
verification_code_email_needed: '&3To verify your identity you need to link an email address with your account!!'
|
||||
|
||||
# Time units
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.xephi.authme.command.executable.captcha;
|
||||
|
||||
import fr.xephi.authme.data.CaptchaManager;
|
||||
import fr.xephi.authme.data.LoginCaptchaManager;
|
||||
import fr.xephi.authme.data.RegistrationCaptchaManager;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
@ -29,7 +30,10 @@ public class CaptchaCommandTest {
|
||||
private CaptchaCommand command;
|
||||
|
||||
@Mock
|
||||
private CaptchaManager captchaManager;
|
||||
private LoginCaptchaManager loginCaptchaManager;
|
||||
|
||||
@Mock
|
||||
private RegistrationCaptchaManager registrationCaptchaManager;
|
||||
|
||||
@Mock
|
||||
private PlayerCache playerCache;
|
||||
@ -60,15 +64,15 @@ public class CaptchaCommandTest {
|
||||
String name = "bobby";
|
||||
Player player = mockPlayerWithName(name);
|
||||
given(playerCache.isAuthenticated(name)).willReturn(false);
|
||||
given(captchaManager.isCaptchaRequired(name)).willReturn(false);
|
||||
given(loginCaptchaManager.isCaptchaRequired(name)).willReturn(false);
|
||||
|
||||
// when
|
||||
command.executeCommand(player, Collections.singletonList("1234"));
|
||||
|
||||
// then
|
||||
verify(commandService).send(player, MessageKey.USAGE_LOGIN);
|
||||
verify(captchaManager).isCaptchaRequired(name);
|
||||
verifyNoMoreInteractions(captchaManager);
|
||||
verify(loginCaptchaManager).isCaptchaRequired(name);
|
||||
verifyNoMoreInteractions(loginCaptchaManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -77,17 +81,17 @@ public class CaptchaCommandTest {
|
||||
String name = "smith";
|
||||
Player player = mockPlayerWithName(name);
|
||||
given(playerCache.isAuthenticated(name)).willReturn(false);
|
||||
given(captchaManager.isCaptchaRequired(name)).willReturn(true);
|
||||
given(loginCaptchaManager.isCaptchaRequired(name)).willReturn(true);
|
||||
String captchaCode = "3991";
|
||||
given(captchaManager.checkCode(name, captchaCode)).willReturn(true);
|
||||
given(loginCaptchaManager.checkCode(name, captchaCode)).willReturn(true);
|
||||
|
||||
// when
|
||||
command.executeCommand(player, Collections.singletonList(captchaCode));
|
||||
|
||||
// then
|
||||
verify(captchaManager).isCaptchaRequired(name);
|
||||
verify(captchaManager).checkCode(name, captchaCode);
|
||||
verifyNoMoreInteractions(captchaManager);
|
||||
verify(loginCaptchaManager).isCaptchaRequired(name);
|
||||
verify(loginCaptchaManager).checkCode(name, captchaCode);
|
||||
verifyNoMoreInteractions(loginCaptchaManager);
|
||||
verify(commandService).send(player, MessageKey.CAPTCHA_SUCCESS);
|
||||
verify(commandService).send(player, MessageKey.LOGIN_MESSAGE);
|
||||
verify(limboService).unmuteMessageTask(player);
|
||||
@ -100,20 +104,20 @@ public class CaptchaCommandTest {
|
||||
String name = "smith";
|
||||
Player player = mockPlayerWithName(name);
|
||||
given(playerCache.isAuthenticated(name)).willReturn(false);
|
||||
given(captchaManager.isCaptchaRequired(name)).willReturn(true);
|
||||
given(loginCaptchaManager.isCaptchaRequired(name)).willReturn(true);
|
||||
String captchaCode = "2468";
|
||||
given(captchaManager.checkCode(name, captchaCode)).willReturn(false);
|
||||
given(loginCaptchaManager.checkCode(name, captchaCode)).willReturn(false);
|
||||
String newCode = "1337";
|
||||
given(captchaManager.generateCode(name)).willReturn(newCode);
|
||||
given(loginCaptchaManager.generateCode(name)).willReturn(newCode);
|
||||
|
||||
// when
|
||||
command.executeCommand(player, Collections.singletonList(captchaCode));
|
||||
|
||||
// then
|
||||
verify(captchaManager).isCaptchaRequired(name);
|
||||
verify(captchaManager).checkCode(name, captchaCode);
|
||||
verify(captchaManager).generateCode(name);
|
||||
verifyNoMoreInteractions(captchaManager);
|
||||
verify(loginCaptchaManager).isCaptchaRequired(name);
|
||||
verify(loginCaptchaManager).checkCode(name, captchaCode);
|
||||
verify(loginCaptchaManager).generateCode(name);
|
||||
verifyNoMoreInteractions(loginCaptchaManager);
|
||||
verify(commandService).send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
|
||||
verifyNoMoreInteractions(commandService);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.xephi.authme.command.executable.register;
|
||||
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import fr.xephi.authme.data.RegistrationCaptchaManager;
|
||||
import fr.xephi.authme.mail.EmailService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.process.Management;
|
||||
@ -60,6 +61,9 @@ public class RegisterCommandTest {
|
||||
@Mock
|
||||
private ValidationService validationService;
|
||||
|
||||
@Mock
|
||||
private RegistrationCaptchaManager registrationCaptchaManager;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
TestHelper.setupLogger();
|
||||
|
@ -12,25 +12,25 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Test for {@link CaptchaManager}.
|
||||
* Test for {@link LoginCaptchaManager}.
|
||||
*/
|
||||
public class CaptchaManagerTest {
|
||||
public class LoginCaptchaManagerTest {
|
||||
|
||||
@Test
|
||||
public void shouldAddCounts() {
|
||||
// given
|
||||
Settings settings = mockSettings(3, 4);
|
||||
CaptchaManager manager = new CaptchaManager(settings);
|
||||
LoginCaptchaManager manager = new LoginCaptchaManager(settings);
|
||||
String player = "tester";
|
||||
|
||||
// when
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
manager.increaseCount(player);
|
||||
manager.increaseLoginFailureCount(player);
|
||||
}
|
||||
|
||||
// then
|
||||
assertThat(manager.isCaptchaRequired(player), equalTo(false));
|
||||
manager.increaseCount(player);
|
||||
manager.increaseLoginFailureCount(player);
|
||||
assertThat(manager.isCaptchaRequired(player.toUpperCase()), equalTo(true));
|
||||
assertThat(manager.isCaptchaRequired("otherPlayer"), equalTo(false));
|
||||
}
|
||||
@ -40,7 +40,7 @@ public class CaptchaManagerTest {
|
||||
// given
|
||||
String player = "Miner";
|
||||
Settings settings = mockSettings(1, 4);
|
||||
CaptchaManager manager = new CaptchaManager(settings);
|
||||
LoginCaptchaManager manager = new LoginCaptchaManager(settings);
|
||||
String captchaCode = manager.getCaptchaCodeOrGenerateNew(player);
|
||||
|
||||
// when
|
||||
@ -60,7 +60,7 @@ public class CaptchaManagerTest {
|
||||
// given
|
||||
String player = "Tester";
|
||||
Settings settings = mockSettings(1, 5);
|
||||
CaptchaManager manager = new CaptchaManager(settings);
|
||||
LoginCaptchaManager manager = new LoginCaptchaManager(settings);
|
||||
|
||||
// when
|
||||
String code1 = manager.getCaptchaCodeOrGenerateNew(player);
|
||||
@ -78,18 +78,18 @@ public class CaptchaManagerTest {
|
||||
// given
|
||||
String player = "plaYer";
|
||||
Settings settings = mockSettings(2, 3);
|
||||
CaptchaManager manager = new CaptchaManager(settings);
|
||||
LoginCaptchaManager manager = new LoginCaptchaManager(settings);
|
||||
|
||||
// when
|
||||
manager.increaseCount(player);
|
||||
manager.increaseCount(player);
|
||||
manager.increaseLoginFailureCount(player);
|
||||
manager.increaseLoginFailureCount(player);
|
||||
|
||||
// then
|
||||
assertThat(manager.isCaptchaRequired(player), equalTo(true));
|
||||
assertHasCount(manager, player, 2);
|
||||
|
||||
// when 2
|
||||
manager.resetCounts(player);
|
||||
manager.resetLoginFailureCount(player);
|
||||
|
||||
// then 2
|
||||
assertThat(manager.isCaptchaRequired(player), equalTo(false));
|
||||
@ -101,11 +101,11 @@ public class CaptchaManagerTest {
|
||||
// given
|
||||
String player = "someone_";
|
||||
Settings settings = mockSettings(1, 3);
|
||||
given(settings.getProperty(SecuritySettings.USE_CAPTCHA)).willReturn(false);
|
||||
CaptchaManager manager = new CaptchaManager(settings);
|
||||
given(settings.getProperty(SecuritySettings.ENABLE_LOGIN_FAILURE_CAPTCHA)).willReturn(false);
|
||||
LoginCaptchaManager manager = new LoginCaptchaManager(settings);
|
||||
|
||||
// when
|
||||
manager.increaseCount(player);
|
||||
manager.increaseLoginFailureCount(player);
|
||||
|
||||
// then
|
||||
assertThat(manager.isCaptchaRequired(player), equalTo(false));
|
||||
@ -117,11 +117,11 @@ public class CaptchaManagerTest {
|
||||
// given
|
||||
String player = "Robert001";
|
||||
Settings settings = mockSettings(1, 5);
|
||||
CaptchaManager manager = new CaptchaManager(settings);
|
||||
given(settings.getProperty(SecuritySettings.USE_CAPTCHA)).willReturn(false);
|
||||
LoginCaptchaManager manager = new LoginCaptchaManager(settings);
|
||||
given(settings.getProperty(SecuritySettings.ENABLE_LOGIN_FAILURE_CAPTCHA)).willReturn(false);
|
||||
|
||||
// when
|
||||
manager.increaseCount(player);
|
||||
manager.increaseLoginFailureCount(player);
|
||||
// assumptions
|
||||
assertThat(manager.isCaptchaRequired(player), equalTo(true));
|
||||
assertHasCount(manager, player, 1);
|
||||
@ -135,16 +135,16 @@ public class CaptchaManagerTest {
|
||||
|
||||
private static Settings mockSettings(int maxTries, int captchaLength) {
|
||||
Settings settings = mock(Settings.class);
|
||||
given(settings.getProperty(SecuritySettings.USE_CAPTCHA)).willReturn(true);
|
||||
given(settings.getProperty(SecuritySettings.ENABLE_LOGIN_FAILURE_CAPTCHA)).willReturn(true);
|
||||
given(settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA)).willReturn(maxTries);
|
||||
given(settings.getProperty(SecuritySettings.CAPTCHA_LENGTH)).willReturn(captchaLength);
|
||||
given(settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET)).willReturn(30);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static void assertHasCount(CaptchaManager manager, String player, Integer count) {
|
||||
private static void assertHasCount(LoginCaptchaManager manager, String player, Integer count) {
|
||||
TimedCounter<String> playerCounts = ReflectionTestUtils
|
||||
.getFieldValue(CaptchaManager.class, manager, "playerCounts");
|
||||
.getFieldValue(LoginCaptchaManager.class, manager, "playerCounts");
|
||||
assertThat(playerCounts.get(player.toLowerCase()), equalTo(count));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user