mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-19 07:07:55 +01:00
#1141 Check that user is logged in before changing TOTP key
- Use PlayerCache to check that user is logged in where appropriate - Add log statements
This commit is contained in:
parent
6f2f7a73af
commit
729c567dd5
@ -2,7 +2,7 @@ package fr.xephi.authme.command.executable.totp;
|
|||||||
|
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
import fr.xephi.authme.security.totp.GenerateTotpService;
|
import fr.xephi.authme.security.totp.GenerateTotpService;
|
||||||
@ -21,16 +21,16 @@ public class AddTotpCommand extends PlayerCommand {
|
|||||||
private GenerateTotpService generateTotpService;
|
private GenerateTotpService generateTotpService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Messages messages;
|
private Messages messages;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runCommand(Player player, List<String> arguments) {
|
protected void runCommand(Player player, List<String> arguments) {
|
||||||
PlayerAuth auth = dataSource.getAuth(player.getName());
|
PlayerAuth auth = playerCache.getAuth(player.getName());
|
||||||
if (auth == null) {
|
if (auth == null) {
|
||||||
messages.send(player, MessageKey.REGISTER_MESSAGE);
|
messages.send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
} else if (auth.getTotpKey() == null) {
|
} else if (auth.getTotpKey() == null) {
|
||||||
TotpGenerationResult createdTotpInfo = generateTotpService.generateTotpKey(player);
|
TotpGenerationResult createdTotpInfo = generateTotpService.generateTotpKey(player);
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_CREATE,
|
messages.send(player, MessageKey.TWO_FACTOR_CREATE,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package fr.xephi.authme.command.executable.totp;
|
package fr.xephi.authme.command.executable.totp;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
@ -20,6 +22,9 @@ public class ConfirmTotpCommand extends PlayerCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private GenerateTotpService generateTotpService;
|
private GenerateTotpService generateTotpService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private DataSource dataSource;
|
||||||
|
|
||||||
@ -28,17 +33,17 @@ public class ConfirmTotpCommand extends PlayerCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runCommand(Player player, List<String> arguments) {
|
protected void runCommand(Player player, List<String> arguments) {
|
||||||
PlayerAuth auth = dataSource.getAuth(player.getName());
|
PlayerAuth auth = playerCache.getAuth(player.getName());
|
||||||
if (auth == null) {
|
if (auth == null) {
|
||||||
messages.send(player, MessageKey.REGISTER_MESSAGE);
|
messages.send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
} else if (auth.getTotpKey() != null) {
|
} else if (auth.getTotpKey() != null) {
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
|
messages.send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
|
||||||
} else {
|
} else {
|
||||||
verifyTotpCodeConfirmation(player, arguments.get(0));
|
verifyTotpCodeConfirmation(player, auth, arguments.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyTotpCodeConfirmation(Player player, String inputTotpCode) {
|
private void verifyTotpCodeConfirmation(Player player, PlayerAuth auth, String inputTotpCode) {
|
||||||
final TotpGenerationResult totpDetails = generateTotpService.getGeneratedTotpKey(player);
|
final TotpGenerationResult totpDetails = generateTotpService.getGeneratedTotpKey(player);
|
||||||
if (totpDetails == null) {
|
if (totpDetails == null) {
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_NO_CODE);
|
messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_NO_CODE);
|
||||||
@ -46,11 +51,21 @@ public class ConfirmTotpCommand extends PlayerCommand {
|
|||||||
boolean isCodeValid = generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, inputTotpCode);
|
boolean isCodeValid = generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, inputTotpCode);
|
||||||
if (isCodeValid) {
|
if (isCodeValid) {
|
||||||
generateTotpService.removeGenerateTotpKey(player);
|
generateTotpService.removeGenerateTotpKey(player);
|
||||||
dataSource.setTotpKey(player.getName(), totpDetails.getTotpKey());
|
insertTotpKeyIntoDatabase(player, auth, totpDetails);
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_ENABLE_SUCCESS);
|
|
||||||
} else {
|
} else {
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_WRONG_CODE);
|
messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_WRONG_CODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void insertTotpKeyIntoDatabase(Player player, PlayerAuth auth, TotpGenerationResult totpDetails) {
|
||||||
|
if (dataSource.setTotpKey(player.getName(), totpDetails.getTotpKey())) {
|
||||||
|
messages.send(player, MessageKey.TWO_FACTOR_ENABLE_SUCCESS);
|
||||||
|
auth.setTotpKey(totpDetails.getTotpKey());
|
||||||
|
playerCache.updatePlayer(auth);
|
||||||
|
ConsoleLogger.info("Player '" + player.getName() + "' has successfully added a TOTP key to their account");
|
||||||
|
} else {
|
||||||
|
messages.send(player, MessageKey.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package fr.xephi.authme.command.executable.totp;
|
package fr.xephi.authme.command.executable.totp;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
@ -19,6 +21,9 @@ public class RemoveTotpCommand extends PlayerCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private TotpAuthenticator totpAuthenticator;
|
private TotpAuthenticator totpAuthenticator;
|
||||||
|
|
||||||
@ -27,16 +32,28 @@ public class RemoveTotpCommand extends PlayerCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runCommand(Player player, List<String> arguments) {
|
protected void runCommand(Player player, List<String> arguments) {
|
||||||
PlayerAuth auth = dataSource.getAuth(player.getName());
|
PlayerAuth auth = playerCache.getAuth(player.getName());
|
||||||
if (auth.getTotpKey() == null) {
|
if (auth == null) {
|
||||||
|
messages.send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
|
} else if (auth.getTotpKey() == null) {
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_NOT_ENABLED_ERROR);
|
messages.send(player, MessageKey.TWO_FACTOR_NOT_ENABLED_ERROR);
|
||||||
} else {
|
} else {
|
||||||
if (totpAuthenticator.checkCode(auth, arguments.get(0))) {
|
if (totpAuthenticator.checkCode(auth, arguments.get(0))) {
|
||||||
dataSource.removeTotpKey(auth.getNickname());
|
removeTotpKeyFromDatabase(player, auth);
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_REMOVED_SUCCESS);
|
|
||||||
} else {
|
} else {
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
|
messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeTotpKeyFromDatabase(Player player, PlayerAuth auth) {
|
||||||
|
if (dataSource.removeTotpKey(auth.getNickname())) {
|
||||||
|
auth.setTotpKey(null);
|
||||||
|
playerCache.updatePlayer(auth);
|
||||||
|
messages.send(player, MessageKey.TWO_FACTOR_REMOVED_SUCCESS);
|
||||||
|
ConsoleLogger.info("Player '" + player.getName() + "' removed their TOTP key");
|
||||||
|
} else {
|
||||||
|
messages.send(player, MessageKey.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package fr.xephi.authme.command.executable.totp;
|
package fr.xephi.authme.command.executable.totp;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.data.auth.PlayerCache;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
@ -56,6 +57,8 @@ public class TotpCodeCommand extends PlayerCommand {
|
|||||||
if (limbo != null && limbo.getState() == LimboPlayerState.TOTP_REQUIRED) {
|
if (limbo != null && limbo.getState() == LimboPlayerState.TOTP_REQUIRED) {
|
||||||
processCode(player, auth, arguments.get(0));
|
processCode(player, auth, arguments.get(0));
|
||||||
} else {
|
} else {
|
||||||
|
ConsoleLogger.debug(() -> "Aborting TOTP check for player '" + player.getName()
|
||||||
|
+ "'. Invalid limbo state: " + (limbo == null ? "no limbo" : limbo.getState()));
|
||||||
messages.send(player, MessageKey.LOGIN_MESSAGE);
|
messages.send(player, MessageKey.LOGIN_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,8 +66,10 @@ public class TotpCodeCommand extends PlayerCommand {
|
|||||||
private void processCode(Player player, PlayerAuth auth, String inputCode) {
|
private void processCode(Player player, PlayerAuth auth, String inputCode) {
|
||||||
boolean isCodeValid = totpAuthenticator.checkCode(auth, inputCode);
|
boolean isCodeValid = totpAuthenticator.checkCode(auth, inputCode);
|
||||||
if (isCodeValid) {
|
if (isCodeValid) {
|
||||||
|
ConsoleLogger.debug("Successfully checked TOTP code for `{0}`", player.getName());
|
||||||
asynchronousLogin.performLogin(player, auth);
|
asynchronousLogin.performLogin(player, auth);
|
||||||
} else {
|
} else {
|
||||||
|
ConsoleLogger.debug("Input TOTP code was invalid for player `{0}`", player.getName());
|
||||||
messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
|
messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,10 @@ public class PlayerAuth {
|
|||||||
return totpKey;
|
return totpKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTotpKey(String totpKey) {
|
||||||
|
this.totpKey = totpKey;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof PlayerAuth)) {
|
if (!(obj instanceof PlayerAuth)) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package fr.xephi.authme.command.executable.totp;
|
package fr.xephi.authme.command.executable.totp;
|
||||||
|
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
import fr.xephi.authme.security.totp.GenerateTotpService;
|
import fr.xephi.authme.security.totp.GenerateTotpService;
|
||||||
@ -32,21 +32,21 @@ public class AddTotpCommandTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private GenerateTotpService generateTotpService;
|
private GenerateTotpService generateTotpService;
|
||||||
@Mock
|
@Mock
|
||||||
private DataSource dataSource;
|
private PlayerCache playerCache;
|
||||||
@Mock
|
@Mock
|
||||||
private Messages messages;
|
private Messages messages;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldHandleNonExistentUser() {
|
public void shouldHandleNonLoggedInUser() {
|
||||||
// given
|
// given
|
||||||
Player player = mockPlayerWithName("bob");
|
Player player = mockPlayerWithName("bob");
|
||||||
given(dataSource.getAuth("bob")).willReturn(null);
|
given(playerCache.getAuth("bob")).willReturn(null);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
addTotpCommand.runCommand(player, Collections.emptyList());
|
addTotpCommand.runCommand(player, Collections.emptyList());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(messages).send(player, MessageKey.REGISTER_MESSAGE);
|
verify(messages).send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
verifyZeroInteractions(generateTotpService);
|
verifyZeroInteractions(generateTotpService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ public class AddTotpCommandTest {
|
|||||||
Player player = mockPlayerWithName("arend");
|
Player player = mockPlayerWithName("arend");
|
||||||
PlayerAuth auth = PlayerAuth.builder().name("arend")
|
PlayerAuth auth = PlayerAuth.builder().name("arend")
|
||||||
.totpKey("TOTP2345").build();
|
.totpKey("TOTP2345").build();
|
||||||
given(dataSource.getAuth("arend")).willReturn(auth);
|
given(playerCache.getAuth("arend")).willReturn(auth);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
addTotpCommand.runCommand(player, Collections.emptyList());
|
addTotpCommand.runCommand(player, Collections.emptyList());
|
||||||
@ -71,7 +71,7 @@ public class AddTotpCommandTest {
|
|||||||
// given
|
// given
|
||||||
Player player = mockPlayerWithName("charles");
|
Player player = mockPlayerWithName("charles");
|
||||||
PlayerAuth auth = PlayerAuth.builder().name("charles").build();
|
PlayerAuth auth = PlayerAuth.builder().name("charles").build();
|
||||||
given(dataSource.getAuth("charles")).willReturn(auth);
|
given(playerCache.getAuth("charles")).willReturn(auth);
|
||||||
|
|
||||||
TotpGenerationResult generationResult = new TotpGenerationResult(
|
TotpGenerationResult generationResult = new TotpGenerationResult(
|
||||||
"777Key214", "http://example.org/qr-code/link");
|
"777Key214", "http://example.org/qr-code/link");
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package fr.xephi.authme.command.executable.totp;
|
package fr.xephi.authme.command.executable.totp;
|
||||||
|
|
||||||
|
import fr.xephi.authme.TestHelper;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
import fr.xephi.authme.security.totp.GenerateTotpService;
|
import fr.xephi.authme.security.totp.GenerateTotpService;
|
||||||
import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult;
|
import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
@ -15,7 +18,10 @@ import org.mockito.junit.MockitoJUnitRunner;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@ -37,8 +43,15 @@ public class ConfirmTotpCommandTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private DataSource dataSource;
|
private DataSource dataSource;
|
||||||
@Mock
|
@Mock
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
@Mock
|
||||||
private Messages messages;
|
private Messages messages;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpLogger() {
|
||||||
|
TestHelper.setupLogger();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldAddTotpCodeToUserAfterSuccessfulConfirmation() {
|
public void shouldAddTotpCodeToUserAfterSuccessfulConfirmation() {
|
||||||
// given
|
// given
|
||||||
@ -46,10 +59,12 @@ public class ConfirmTotpCommandTest {
|
|||||||
String playerName = "George";
|
String playerName = "George";
|
||||||
given(player.getName()).willReturn(playerName);
|
given(player.getName()).willReturn(playerName);
|
||||||
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
|
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
|
||||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
given(playerCache.getAuth(playerName)).willReturn(auth);
|
||||||
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(new TotpGenerationResult("totp-key", "url-not-relevant"));
|
String generatedTotpKey = "totp-key";
|
||||||
|
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(new TotpGenerationResult(generatedTotpKey, "url-not-relevant"));
|
||||||
String totpCode = "954321";
|
String totpCode = "954321";
|
||||||
given(generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, totpCode)).willReturn(true);
|
given(generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, totpCode)).willReturn(true);
|
||||||
|
given(dataSource.setTotpKey(anyString(), anyString())).willReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
command.runCommand(player, Collections.singletonList(totpCode));
|
command.runCommand(player, Collections.singletonList(totpCode));
|
||||||
@ -57,8 +72,10 @@ public class ConfirmTotpCommandTest {
|
|||||||
// then
|
// then
|
||||||
verify(generateTotpService).isTotpCodeCorrectForGeneratedTotpKey(player, totpCode);
|
verify(generateTotpService).isTotpCodeCorrectForGeneratedTotpKey(player, totpCode);
|
||||||
verify(generateTotpService).removeGenerateTotpKey(player);
|
verify(generateTotpService).removeGenerateTotpKey(player);
|
||||||
verify(dataSource).setTotpKey(playerName, "totp-key");
|
verify(dataSource).setTotpKey(playerName, generatedTotpKey);
|
||||||
|
verify(playerCache).updatePlayer(auth);
|
||||||
verify(messages).send(player, MessageKey.TWO_FACTOR_ENABLE_SUCCESS);
|
verify(messages).send(player, MessageKey.TWO_FACTOR_ENABLE_SUCCESS);
|
||||||
|
assertThat(auth.getTotpKey(), equalTo(generatedTotpKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -68,7 +85,7 @@ public class ConfirmTotpCommandTest {
|
|||||||
String playerName = "George";
|
String playerName = "George";
|
||||||
given(player.getName()).willReturn(playerName);
|
given(player.getName()).willReturn(playerName);
|
||||||
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
|
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
|
||||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
given(playerCache.getAuth(playerName)).willReturn(auth);
|
||||||
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(new TotpGenerationResult("totp-key", "url-not-relevant"));
|
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(new TotpGenerationResult("totp-key", "url-not-relevant"));
|
||||||
String totpCode = "754321";
|
String totpCode = "754321";
|
||||||
given(generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, totpCode)).willReturn(false);
|
given(generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, totpCode)).willReturn(false);
|
||||||
@ -79,8 +96,9 @@ public class ConfirmTotpCommandTest {
|
|||||||
// then
|
// then
|
||||||
verify(generateTotpService).isTotpCodeCorrectForGeneratedTotpKey(player, totpCode);
|
verify(generateTotpService).isTotpCodeCorrectForGeneratedTotpKey(player, totpCode);
|
||||||
verify(generateTotpService, never()).removeGenerateTotpKey(any(Player.class));
|
verify(generateTotpService, never()).removeGenerateTotpKey(any(Player.class));
|
||||||
verify(dataSource, only()).getAuth(playerName);
|
verify(playerCache, only()).getAuth(playerName);
|
||||||
verify(messages).send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_WRONG_CODE);
|
verify(messages).send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_WRONG_CODE);
|
||||||
|
verifyZeroInteractions(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -90,7 +108,7 @@ public class ConfirmTotpCommandTest {
|
|||||||
String playerName = "George";
|
String playerName = "George";
|
||||||
given(player.getName()).willReturn(playerName);
|
given(player.getName()).willReturn(playerName);
|
||||||
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
|
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
|
||||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
given(playerCache.getAuth(playerName)).willReturn(auth);
|
||||||
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(null);
|
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(null);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -98,8 +116,9 @@ public class ConfirmTotpCommandTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
verify(generateTotpService, only()).getGeneratedTotpKey(player);
|
verify(generateTotpService, only()).getGeneratedTotpKey(player);
|
||||||
verify(dataSource, only()).getAuth(playerName);
|
verify(playerCache, only()).getAuth(playerName);
|
||||||
verify(messages).send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_NO_CODE);
|
verify(messages).send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_NO_CODE);
|
||||||
|
verifyZeroInteractions(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -109,14 +128,14 @@ public class ConfirmTotpCommandTest {
|
|||||||
String playerName = "George";
|
String playerName = "George";
|
||||||
given(player.getName()).willReturn(playerName);
|
given(player.getName()).willReturn(playerName);
|
||||||
PlayerAuth auth = PlayerAuth.builder().name(playerName).totpKey("A987234").build();
|
PlayerAuth auth = PlayerAuth.builder().name(playerName).totpKey("A987234").build();
|
||||||
given(dataSource.getAuth(playerName)).willReturn(auth);
|
given(playerCache.getAuth(playerName)).willReturn(auth);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
command.runCommand(player, Collections.singletonList("871634"));
|
command.runCommand(player, Collections.singletonList("871634"));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(dataSource, only()).getAuth(playerName);
|
verify(playerCache, only()).getAuth(playerName);
|
||||||
verifyZeroInteractions(generateTotpService);
|
verifyZeroInteractions(generateTotpService, dataSource);
|
||||||
verify(messages).send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
|
verify(messages).send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,14 +145,14 @@ public class ConfirmTotpCommandTest {
|
|||||||
Player player = mock(Player.class);
|
Player player = mock(Player.class);
|
||||||
String playerName = "George";
|
String playerName = "George";
|
||||||
given(player.getName()).willReturn(playerName);
|
given(player.getName()).willReturn(playerName);
|
||||||
given(dataSource.getAuth(playerName)).willReturn(null);
|
given(playerCache.getAuth(playerName)).willReturn(null);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
command.runCommand(player, Collections.singletonList("984685"));
|
command.runCommand(player, Collections.singletonList("984685"));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(dataSource, only()).getAuth(playerName);
|
verify(playerCache, only()).getAuth(playerName);
|
||||||
verifyZeroInteractions(generateTotpService);
|
verifyZeroInteractions(generateTotpService, dataSource);
|
||||||
verify(messages).send(player, MessageKey.REGISTER_MESSAGE);
|
verify(messages).send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,149 @@
|
|||||||
|
package fr.xephi.authme.command.executable.totp;
|
||||||
|
|
||||||
|
import fr.xephi.authme.TestHelper;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.message.MessageKey;
|
||||||
|
import fr.xephi.authme.message.Messages;
|
||||||
|
import fr.xephi.authme.security.totp.TotpAuthenticator;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.only;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link RemoveTotpCommand}.
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class RemoveTotpCommandTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private RemoveTotpCommand command;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSource dataSource;
|
||||||
|
@Mock
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
@Mock
|
||||||
|
private TotpAuthenticator totpAuthenticator;
|
||||||
|
@Mock
|
||||||
|
private Messages messages;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpLogger() {
|
||||||
|
TestHelper.setupLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldRemoveTotpKey() {
|
||||||
|
// given
|
||||||
|
String name = "aws";
|
||||||
|
PlayerAuth auth = PlayerAuth.builder().name(name).totpKey("some-totp-key").build();
|
||||||
|
given(playerCache.getAuth(name)).willReturn(auth);
|
||||||
|
String inputCode = "93847";
|
||||||
|
given(totpAuthenticator.checkCode(auth, inputCode)).willReturn(true);
|
||||||
|
given(dataSource.removeTotpKey(name)).willReturn(true);
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
given(player.getName()).willReturn(name);
|
||||||
|
|
||||||
|
// when
|
||||||
|
command.runCommand(player, singletonList(inputCode));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verify(dataSource).removeTotpKey(name);
|
||||||
|
verify(messages, only()).send(player, MessageKey.TWO_FACTOR_REMOVED_SUCCESS);
|
||||||
|
verify(playerCache).updatePlayer(auth);
|
||||||
|
assertThat(auth.getTotpKey(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleDatabaseError() {
|
||||||
|
// given
|
||||||
|
String name = "aws";
|
||||||
|
PlayerAuth auth = PlayerAuth.builder().name(name).totpKey("some-totp-key").build();
|
||||||
|
given(playerCache.getAuth(name)).willReturn(auth);
|
||||||
|
String inputCode = "93847";
|
||||||
|
given(totpAuthenticator.checkCode(auth, inputCode)).willReturn(true);
|
||||||
|
given(dataSource.removeTotpKey(name)).willReturn(false);
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
given(player.getName()).willReturn(name);
|
||||||
|
|
||||||
|
// when
|
||||||
|
command.runCommand(player, singletonList(inputCode));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verify(dataSource).removeTotpKey(name);
|
||||||
|
verify(messages, only()).send(player, MessageKey.ERROR);
|
||||||
|
verify(playerCache, only()).getAuth(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleInvalidCode() {
|
||||||
|
// given
|
||||||
|
String name = "cesar";
|
||||||
|
PlayerAuth auth = PlayerAuth.builder().name(name).totpKey("some-totp-key").build();
|
||||||
|
given(playerCache.getAuth(name)).willReturn(auth);
|
||||||
|
String inputCode = "93847";
|
||||||
|
given(totpAuthenticator.checkCode(auth, inputCode)).willReturn(false);
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
given(player.getName()).willReturn(name);
|
||||||
|
|
||||||
|
// when
|
||||||
|
command.runCommand(player, singletonList(inputCode));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verifyZeroInteractions(dataSource);
|
||||||
|
verify(messages, only()).send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
|
||||||
|
verify(playerCache, only()).getAuth(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleUserWithoutTotpKey() {
|
||||||
|
// given
|
||||||
|
String name = "cesar";
|
||||||
|
PlayerAuth auth = PlayerAuth.builder().name(name).build();
|
||||||
|
given(playerCache.getAuth(name)).willReturn(auth);
|
||||||
|
String inputCode = "654684";
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
given(player.getName()).willReturn(name);
|
||||||
|
|
||||||
|
// when
|
||||||
|
command.runCommand(player, singletonList(inputCode));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verifyZeroInteractions(dataSource, totpAuthenticator);
|
||||||
|
verify(messages, only()).send(player, MessageKey.TWO_FACTOR_NOT_ENABLED_ERROR);
|
||||||
|
verify(playerCache, only()).getAuth(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleNonLoggedInUser() {
|
||||||
|
// given
|
||||||
|
String name = "cesar";
|
||||||
|
given(playerCache.getAuth(name)).willReturn(null);
|
||||||
|
String inputCode = "654684";
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
given(player.getName()).willReturn(name);
|
||||||
|
|
||||||
|
// when
|
||||||
|
command.runCommand(player, singletonList(inputCode));
|
||||||
|
|
||||||
|
// then
|
||||||
|
verifyZeroInteractions(dataSource, totpAuthenticator);
|
||||||
|
verify(messages, only()).send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
|
verify(playerCache, only()).getAuth(name);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user