#1141 Require TOTP code to be passed with /login (temporary)

- Temporarily require the TOTP code to be provided with /login
- Future implementation should require it as a second step
This commit is contained in:
ljacqu
2018-03-09 18:37:01 +01:00
parent c3cf9e3ee0
commit e72d5d5e81
7 changed files with 147 additions and 9 deletions
@@ -89,6 +89,7 @@ public class CommandInitializer {
.description("Login command")
.detailedDescription("Command to log in using AuthMeReloaded.")
.withArgument("password", "Login password", false)
.withArgument("2facode", "TOTP code", true)
.permission(PlayerPermission.LOGIN)
.executableCommand(LoginCommand.class)
.register();
@@ -77,6 +77,7 @@ class PlayerAuthViewer implements DebugSection {
HashedPassword hashedPass = auth.getPassword();
sender.sendMessage("Hash / salt (partial): '" + safeSubstring(hashedPass.getHash(), 6)
+ "' / '" + safeSubstring(hashedPass.getSalt(), 4) + "'");
sender.sendMessage("TOTP code (partial): '" + safeSubstring(auth.getTotpKey(), 3) + "'");
}
/**
@@ -18,8 +18,9 @@ public class LoginCommand extends PlayerCommand {
@Override
public void runCommand(Player player, List<String> arguments) {
final String password = arguments.get(0);
management.performLogin(player, password);
String password = arguments.get(0);
String totpCode = arguments.size() > 1 ? arguments.get(1) : null;
management.performLogin(player, password, totpCode);
}
@Override
@@ -49,8 +49,8 @@ public class Management {
}
public void performLogin(Player player, String password) {
runTask(() -> asynchronousLogin.login(player, password));
public void performLogin(Player player, String password, String totpCode) {
runTask(() -> asynchronousLogin.login(player, password, totpCode));
}
public void forceLogin(Player player) {
@@ -18,6 +18,7 @@ import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.TotpService;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.SessionService;
@@ -78,6 +79,9 @@ public class AsynchronousLogin implements AsynchronousProcess {
@Inject
private BungeeSender bungeeSender;
@Inject
private TotpService totpService;
AsynchronousLogin() {
}
@@ -86,10 +90,11 @@ public class AsynchronousLogin implements AsynchronousProcess {
*
* @param player the player to log in
* @param password the password to log in with
* @param totpCode the totp code (nullable)
*/
public void login(Player player, String password) {
public void login(Player player, String password, String totpCode) {
PlayerAuth auth = getPlayerAuth(player);
if (auth != null && checkPlayerInfo(player, auth, password)) {
if (auth != null && checkPlayerInfo(player, auth, password, totpCode)) {
performLogin(player, auth);
}
}
@@ -156,10 +161,11 @@ public class AsynchronousLogin implements AsynchronousProcess {
* @param player the player requesting to log in
* @param auth the PlayerAuth object of the player
* @param password the password supplied by the player
* @param totpCode the input totp code (nullable)
* @return true if the password matches and all other conditions are met (e.g. no captcha required),
* false otherwise
*/
private boolean checkPlayerInfo(Player player, PlayerAuth auth, String password) {
private boolean checkPlayerInfo(Player player, PlayerAuth auth, String password, String totpCode) {
final String name = player.getName().toLowerCase();
// If captcha is required send a message to the player and deny to log in
@@ -174,6 +180,17 @@ public class AsynchronousLogin implements AsynchronousProcess {
loginCaptchaManager.increaseLoginFailureCount(name);
tempbanManager.increaseCount(ip, name);
if (auth.getTotpKey() != null) {
if (totpCode == null) {
player.sendMessage(
"You have two-factor authentication enabled. Please provide it: /login <password> <2faCode>");
return false;
} else if (!totpService.verifyCode(auth, totpCode)) {
player.sendMessage("Invalid code for two-factor authentication. Please try again");
return false;
}
}
if (passwordSecurity.comparePassword(password, auth.getPassword(), player.getName())) {
return true;
} else {