#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:
ljacqu
2018-05-13 18:49:40 +02:00
parent 6f2f7a73af
commit 729c567dd5
8 changed files with 244 additions and 35 deletions
@@ -1,7 +1,7 @@
package fr.xephi.authme.command.executable.totp;
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.Messages;
import fr.xephi.authme.security.totp.GenerateTotpService;
@@ -32,21 +32,21 @@ public class AddTotpCommandTest {
@Mock
private GenerateTotpService generateTotpService;
@Mock
private DataSource dataSource;
private PlayerCache playerCache;
@Mock
private Messages messages;
@Test
public void shouldHandleNonExistentUser() {
public void shouldHandleNonLoggedInUser() {
// given
Player player = mockPlayerWithName("bob");
given(dataSource.getAuth("bob")).willReturn(null);
given(playerCache.getAuth("bob")).willReturn(null);
// when
addTotpCommand.runCommand(player, Collections.emptyList());
// then
verify(messages).send(player, MessageKey.REGISTER_MESSAGE);
verify(messages).send(player, MessageKey.NOT_LOGGED_IN);
verifyZeroInteractions(generateTotpService);
}
@@ -56,7 +56,7 @@ public class AddTotpCommandTest {
Player player = mockPlayerWithName("arend");
PlayerAuth auth = PlayerAuth.builder().name("arend")
.totpKey("TOTP2345").build();
given(dataSource.getAuth("arend")).willReturn(auth);
given(playerCache.getAuth("arend")).willReturn(auth);
// when
addTotpCommand.runCommand(player, Collections.emptyList());
@@ -71,7 +71,7 @@ public class AddTotpCommandTest {
// given
Player player = mockPlayerWithName("charles");
PlayerAuth auth = PlayerAuth.builder().name("charles").build();
given(dataSource.getAuth("charles")).willReturn(auth);
given(playerCache.getAuth("charles")).willReturn(auth);
TotpGenerationResult generationResult = new TotpGenerationResult(
"777Key214", "http://example.org/qr-code/link");
@@ -1,12 +1,15 @@
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.GenerateTotpService;
import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult;
import org.bukkit.entity.Player;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -15,7 +18,10 @@ import org.mockito.junit.MockitoJUnitRunner;
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.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -37,8 +43,15 @@ public class ConfirmTotpCommandTest {
@Mock
private DataSource dataSource;
@Mock
private PlayerCache playerCache;
@Mock
private Messages messages;
@BeforeClass
public static void setUpLogger() {
TestHelper.setupLogger();
}
@Test
public void shouldAddTotpCodeToUserAfterSuccessfulConfirmation() {
// given
@@ -46,10 +59,12 @@ public class ConfirmTotpCommandTest {
String playerName = "George";
given(player.getName()).willReturn(playerName);
PlayerAuth auth = PlayerAuth.builder().name(playerName).build();
given(dataSource.getAuth(playerName)).willReturn(auth);
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(new TotpGenerationResult("totp-key", "url-not-relevant"));
given(playerCache.getAuth(playerName)).willReturn(auth);
String generatedTotpKey = "totp-key";
given(generateTotpService.getGeneratedTotpKey(player)).willReturn(new TotpGenerationResult(generatedTotpKey, "url-not-relevant"));
String totpCode = "954321";
given(generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, totpCode)).willReturn(true);
given(dataSource.setTotpKey(anyString(), anyString())).willReturn(true);
// when
command.runCommand(player, Collections.singletonList(totpCode));
@@ -57,8 +72,10 @@ public class ConfirmTotpCommandTest {
// then
verify(generateTotpService).isTotpCodeCorrectForGeneratedTotpKey(player, totpCode);
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);
assertThat(auth.getTotpKey(), equalTo(generatedTotpKey));
}
@Test
@@ -68,7 +85,7 @@ public class ConfirmTotpCommandTest {
String playerName = "George";
given(player.getName()).willReturn(playerName);
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 totpCode = "754321";
given(generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, totpCode)).willReturn(false);
@@ -79,8 +96,9 @@ public class ConfirmTotpCommandTest {
// then
verify(generateTotpService).isTotpCodeCorrectForGeneratedTotpKey(player, totpCode);
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);
verifyZeroInteractions(dataSource);
}
@Test
@@ -90,7 +108,7 @@ public class ConfirmTotpCommandTest {
String playerName = "George";
given(player.getName()).willReturn(playerName);
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);
// when
@@ -98,8 +116,9 @@ public class ConfirmTotpCommandTest {
// then
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);
verifyZeroInteractions(dataSource);
}
@Test
@@ -109,14 +128,14 @@ public class ConfirmTotpCommandTest {
String playerName = "George";
given(player.getName()).willReturn(playerName);
PlayerAuth auth = PlayerAuth.builder().name(playerName).totpKey("A987234").build();
given(dataSource.getAuth(playerName)).willReturn(auth);
given(playerCache.getAuth(playerName)).willReturn(auth);
// when
command.runCommand(player, Collections.singletonList("871634"));
// then
verify(dataSource, only()).getAuth(playerName);
verifyZeroInteractions(generateTotpService);
verify(playerCache, only()).getAuth(playerName);
verifyZeroInteractions(generateTotpService, dataSource);
verify(messages).send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
}
@@ -126,14 +145,14 @@ public class ConfirmTotpCommandTest {
Player player = mock(Player.class);
String playerName = "George";
given(player.getName()).willReturn(playerName);
given(dataSource.getAuth(playerName)).willReturn(null);
given(playerCache.getAuth(playerName)).willReturn(null);
// when
command.runCommand(player, Collections.singletonList("984685"));
// then
verify(dataSource, only()).getAuth(playerName);
verifyZeroInteractions(generateTotpService);
verify(messages).send(player, MessageKey.REGISTER_MESSAGE);
verify(playerCache, only()).getAuth(playerName);
verifyZeroInteractions(generateTotpService, dataSource);
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);
}
}