#1141 Move TOTP code during login as separate step: /2fa code

Rough version.
- Introduces a limbo player state on the LimboPlayer, allowing us to add further mandatory actions between successful (password) authentication and the ability to play on the server
This commit is contained in:
ljacqu
2018-03-20 23:06:08 +01:00
parent af6bee59bd
commit 495cfc69a9
18 changed files with 162 additions and 62 deletions
@@ -44,6 +44,7 @@ import fr.xephi.authme.command.executable.totp.AddTotpCommand;
import fr.xephi.authme.command.executable.totp.ConfirmTotpCommand;
import fr.xephi.authme.command.executable.totp.RemoveTotpCommand;
import fr.xephi.authme.command.executable.totp.TotpBaseCommand;
import fr.xephi.authme.command.executable.totp.TotpCodeCommand;
import fr.xephi.authme.command.executable.unregister.UnregisterCommand;
import fr.xephi.authme.command.executable.verification.VerificationCommand;
import fr.xephi.authme.permission.AdminPermission;
@@ -92,7 +93,6 @@ public class CommandInitializer {
.description("Login command")
.detailedDescription("Command to log in using AuthMeReloaded.")
.withArgument("password", "Login password", MANDATORY)
.withArgument("2facode", "TOTP code", OPTIONAL)
.permission(PlayerPermission.LOGIN)
.executableCommand(LoginCommand.class)
.register();
@@ -561,6 +561,15 @@ public class CommandInitializer {
.executableCommand(TotpBaseCommand.class)
.register();
// Register the base totp code
CommandDescription.builder()
.parent(null)
.labels("code", "c")
.description("Command for logging in")
.detailedDescription("Processes the two-factor authentication code during login.")
.executableCommand(TotpCodeCommand.class)
.register();
// Register totp add
CommandDescription.builder()
.parent(totpBase)
@@ -4,6 +4,7 @@ import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.captcha.LoginCaptchaManager;
import fr.xephi.authme.data.captcha.RegistrationCaptchaManager;
import fr.xephi.authme.data.limbo.LimboMessageType;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
@@ -80,6 +81,6 @@ public class CaptchaCommand extends PlayerCommand {
String newCode = registrationCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName());
commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
}
limboService.resetMessageTask(player, false);
limboService.resetMessageTask(player, LimboMessageType.REGISTER);
}
}
@@ -19,8 +19,7 @@ public class LoginCommand extends PlayerCommand {
@Override
public void runCommand(Player player, List<String> arguments) {
String password = arguments.get(0);
String totpCode = arguments.size() > 1 ? arguments.get(1) : null;
management.performLogin(player, password, totpCode);
management.performLogin(player, password);
}
@Override
@@ -0,0 +1,72 @@
package fr.xephi.authme.command.executable.totp;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.limbo.LimboPlayer;
import fr.xephi.authme.data.limbo.LimboPlayerState;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.totp.TotpService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List;
/**
* TOTP code command for processing the 2FA code during the login process.
*/
public class TotpCodeCommand extends PlayerCommand {
@Inject
private LimboService limboService;
@Inject
private PlayerCache playerCache;
@Inject
private Messages messages;
@Inject
private TotpService totpService;
@Inject
private DataSource dataSource;
@Inject
private AsynchronousLogin asynchronousLogin;
@Override
protected void runCommand(Player player, List<String> arguments) {
if (playerCache.isAuthenticated(player.getName())) {
messages.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return;
}
PlayerAuth auth = dataSource.getAuth(player.getName());
if (auth == null) {
messages.send(player, MessageKey.REGISTER_MESSAGE);
return;
}
LimboPlayer limbo = limboService.getLimboPlayer(player.getName());
if (limbo.getState() == LimboPlayerState.TOTP_REQUIRED) {
processCode(player, limbo, auth, arguments.get(0));
} else {
messages.send(player, MessageKey.LOGIN_MESSAGE);
}
}
private void processCode(Player player, LimboPlayer limbo, PlayerAuth auth, String inputCode) {
boolean isCodeValid = totpService.verifyCode(auth, inputCode);
if (isCodeValid) {
limbo.setState(LimboPlayerState.FINISHED);
asynchronousLogin.performLogin(player, auth);
} else {
player.sendMessage("Invalid code!");
}
}
}