#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:
ljacqu 2017-12-01 21:12:35 +01:00
parent 67a6a42dfe
commit 33904c09e9
11 changed files with 220 additions and 69 deletions

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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 &lt;theCaptcha&gt; */
CAPTCHA_FOR_REGISTRATION_REQUIRED("captcha_for_registration", "<theCaptcha>"),
/** A VIP player has joined the server when it was full! */
KICK_FOR_VIP("kick_forvip"),

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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();

View File

@ -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));
}
}