mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 19:48:01 +01:00
test classes moved to same packages with components they test
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2013 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.auth;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.whispersystems.textsecuregcm.util.HmacUtils.hmac256TruncatedToHexString;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.util.MockUtils;
|
||||
import org.whispersystems.textsecuregcm.util.MutableClock;
|
||||
|
||||
class ExternalServiceCredentialsGeneratorTest {
|
||||
private static final String PREFIX = "prefix";
|
||||
|
||||
private static final String E164 = "+14152222222";
|
||||
|
||||
private static final long TIME_SECONDS = 12345;
|
||||
|
||||
private static final long TIME_MILLIS = TimeUnit.SECONDS.toMillis(TIME_SECONDS);
|
||||
|
||||
private static final String TIME_SECONDS_STRING = Long.toString(TIME_SECONDS);
|
||||
|
||||
private static final String USERNAME_TIMESTAMP = PREFIX + ":" + Instant.ofEpochSecond(TIME_SECONDS).truncatedTo(ChronoUnit.DAYS).getEpochSecond();
|
||||
|
||||
private static final MutableClock clock = MockUtils.mutableClock(TIME_MILLIS);
|
||||
|
||||
private static final ExternalServiceCredentialsGenerator standardGenerator = ExternalServiceCredentialsGenerator
|
||||
.builder(new byte[32])
|
||||
.withClock(clock)
|
||||
.build();
|
||||
|
||||
private static final ExternalServiceCredentials standardCredentials = standardGenerator.generateFor(E164);
|
||||
|
||||
private static final ExternalServiceCredentialsGenerator usernameIsTimestampGenerator = ExternalServiceCredentialsGenerator
|
||||
.builder(new byte[32])
|
||||
.withUsernameTimestampTruncatorAndPrefix(timestamp -> timestamp.truncatedTo(ChronoUnit.DAYS), PREFIX)
|
||||
.withClock(clock)
|
||||
.build();
|
||||
|
||||
private static final ExternalServiceCredentials usernameIsTimestampCredentials = usernameIsTimestampGenerator.generateWithTimestampAsUsername();
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception {
|
||||
clock.setTimeMillis(TIME_MILLIS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvalidConstructor() {
|
||||
assertThrows(RuntimeException.class, () -> ExternalServiceCredentialsGenerator
|
||||
.builder(new byte[32])
|
||||
.withUsernameTimestampTruncatorAndPrefix(null, PREFIX)
|
||||
.build());
|
||||
|
||||
assertThrows(RuntimeException.class, () -> ExternalServiceCredentialsGenerator
|
||||
.builder(new byte[32])
|
||||
.withUsernameTimestampTruncatorAndPrefix(timestamp -> timestamp.truncatedTo(ChronoUnit.DAYS), null)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateDerivedUsername() {
|
||||
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator
|
||||
.builder(new byte[32])
|
||||
.withUserDerivationKey(new byte[32])
|
||||
.build();
|
||||
final ExternalServiceCredentials credentials = generator.generateFor(E164);
|
||||
assertNotEquals(credentials.username(), E164);
|
||||
assertFalse(credentials.password().startsWith(E164));
|
||||
assertEquals(credentials.password().split(":").length, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGenerateNoDerivedUsername() {
|
||||
assertEquals(standardCredentials.username(), E164);
|
||||
assertTrue(standardCredentials.password().startsWith(E164));
|
||||
assertEquals(standardCredentials.password().split(":").length, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotPrependUsername() throws Exception {
|
||||
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator
|
||||
.builder(new byte[32])
|
||||
.prependUsername(false)
|
||||
.withClock(clock)
|
||||
.build();
|
||||
final ExternalServiceCredentials credentials = generator.generateFor(E164);
|
||||
assertEquals(credentials.username(), E164);
|
||||
assertTrue(credentials.password().startsWith(TIME_SECONDS_STRING));
|
||||
assertEquals(credentials.password().split(":").length, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithUsernameIsTimestamp() {
|
||||
assertEquals(USERNAME_TIMESTAMP, usernameIsTimestampCredentials.username());
|
||||
|
||||
final String[] passwordComponents = usernameIsTimestampCredentials.password().split(":");
|
||||
assertEquals(USERNAME_TIMESTAMP, passwordComponents[0] + ":" + passwordComponents[1]);
|
||||
assertEquals(hmac256TruncatedToHexString(new byte[32], USERNAME_TIMESTAMP, 10), passwordComponents[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateValid() throws Exception {
|
||||
assertEquals(standardGenerator.validateAndGetTimestamp(standardCredentials).orElseThrow(), TIME_SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateValidWithUsernameIsTimestamp() {
|
||||
final long expectedTimestamp = Instant.ofEpochSecond(TIME_SECONDS).truncatedTo(ChronoUnit.DAYS).getEpochSecond();
|
||||
assertEquals(expectedTimestamp, usernameIsTimestampGenerator.validateAndGetTimestamp(usernameIsTimestampCredentials).orElseThrow());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateInvalid() throws Exception {
|
||||
final ExternalServiceCredentials corruptedStandardUsername = new ExternalServiceCredentials(
|
||||
standardCredentials.username(), standardCredentials.password().replace(E164, E164 + "0"));
|
||||
final ExternalServiceCredentials corruptedStandardTimestamp = new ExternalServiceCredentials(
|
||||
standardCredentials.username(), standardCredentials.password().replace(TIME_SECONDS_STRING, TIME_SECONDS_STRING + "0"));
|
||||
final ExternalServiceCredentials corruptedStandardPassword = new ExternalServiceCredentials(
|
||||
standardCredentials.username(), standardCredentials.password() + "0");
|
||||
|
||||
final ExternalServiceCredentials corruptedUsernameTimestamp = new ExternalServiceCredentials(
|
||||
usernameIsTimestampCredentials.username(), usernameIsTimestampCredentials.password().replace(USERNAME_TIMESTAMP, USERNAME_TIMESTAMP
|
||||
+ "0"));
|
||||
final ExternalServiceCredentials corruptedUsernameTimestampPassword = new ExternalServiceCredentials(
|
||||
usernameIsTimestampCredentials.username(), usernameIsTimestampCredentials.password() + "0");
|
||||
|
||||
assertTrue(standardGenerator.validateAndGetTimestamp(corruptedStandardUsername).isEmpty());
|
||||
assertTrue(standardGenerator.validateAndGetTimestamp(corruptedStandardTimestamp).isEmpty());
|
||||
assertTrue(standardGenerator.validateAndGetTimestamp(corruptedStandardPassword).isEmpty());
|
||||
|
||||
assertTrue(usernameIsTimestampGenerator.validateAndGetTimestamp(corruptedUsernameTimestamp).isEmpty());
|
||||
assertTrue(usernameIsTimestampGenerator.validateAndGetTimestamp(corruptedUsernameTimestampPassword).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateWithExpiration() throws Exception {
|
||||
final long elapsedSeconds = 10000;
|
||||
clock.incrementSeconds(elapsedSeconds);
|
||||
|
||||
assertEquals(standardGenerator.validateAndGetTimestamp(standardCredentials, elapsedSeconds + 1).orElseThrow(), TIME_SECONDS);
|
||||
assertTrue(standardGenerator.validateAndGetTimestamp(standardCredentials, elapsedSeconds - 1).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIdentityFromSignature() {
|
||||
final String identity = standardGenerator.identityFromSignature(standardCredentials.password()).orElseThrow();
|
||||
assertEquals(E164, identity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIdentityFromSignatureIsTimestamp() {
|
||||
final String identity = usernameIsTimestampGenerator.identityFromSignature(usernameIsTimestampCredentials.password()).orElseThrow();
|
||||
assertEquals(USERNAME_TIMESTAMP, identity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateLength() throws Exception {
|
||||
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator.builder(new byte[32])
|
||||
.withUserDerivationKey(new byte[32])
|
||||
.withDerivedUsernameTruncateLength(14)
|
||||
.build();
|
||||
final ExternalServiceCredentials creds = generator.generateFor(E164);
|
||||
assertEquals(14*2 /* 2 chars per byte, because hex */, creds.username().length());
|
||||
assertEquals("805b84df7eff1e8fe1baf0c6e838", creds.username());
|
||||
generator.validateAndGetTimestamp(creds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.auth;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsSelector.CredentialInfo;
|
||||
import org.whispersystems.textsecuregcm.util.MockUtils;
|
||||
import org.whispersystems.textsecuregcm.util.MutableClock;
|
||||
|
||||
public class ExternalServiceCredentialsSelectorTest {
|
||||
|
||||
private static final UUID UUID1 = UUID.randomUUID();
|
||||
private static final UUID UUID2 = UUID.randomUUID();
|
||||
private static final MutableClock CLOCK = MockUtils.mutableClock(TimeUnit.DAYS.toSeconds(1));
|
||||
|
||||
private static final ExternalServiceCredentialsGenerator GEN1 =
|
||||
ExternalServiceCredentialsGenerator
|
||||
.builder(RandomUtils.nextBytes(32))
|
||||
.prependUsername(true)
|
||||
.withClock(CLOCK)
|
||||
.build();
|
||||
|
||||
private static final ExternalServiceCredentialsGenerator GEN2 =
|
||||
ExternalServiceCredentialsGenerator
|
||||
.builder(RandomUtils.nextBytes(32))
|
||||
.withUserDerivationKey(RandomUtils.nextBytes(32))
|
||||
.prependUsername(false)
|
||||
.withDerivedUsernameTruncateLength(16)
|
||||
.withClock(CLOCK)
|
||||
.build();
|
||||
|
||||
private static ExternalServiceCredentials atTime(
|
||||
final ExternalServiceCredentialsGenerator gen,
|
||||
final long deltaMillis,
|
||||
final UUID identity) {
|
||||
final Instant old = CLOCK.instant();
|
||||
try {
|
||||
CLOCK.incrementMillis(deltaMillis);
|
||||
return gen.generateForUuid(identity);
|
||||
} finally {
|
||||
CLOCK.setTimeInstant(old);
|
||||
}
|
||||
}
|
||||
|
||||
private static String token(final ExternalServiceCredentials cred) {
|
||||
return cred.username() + ":" + cred.password();
|
||||
}
|
||||
|
||||
@Test
|
||||
void single() {
|
||||
final ExternalServiceCredentials cred = GEN1.generateForUuid(UUID1);
|
||||
var result = ExternalServiceCredentialsSelector.check(
|
||||
List.of(token(cred)), GEN1, TimeUnit.MINUTES.toSeconds(1));
|
||||
assertThat(result).singleElement()
|
||||
.matches(CredentialInfo::valid)
|
||||
.matches(info -> info.credentials().equals(cred));
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleUsernames() {
|
||||
final ExternalServiceCredentials cred1New = GEN1.generateForUuid(UUID1);
|
||||
final ExternalServiceCredentials cred1Old = atTime(GEN1, -1, UUID1);
|
||||
|
||||
final ExternalServiceCredentials cred2New = GEN1.generateForUuid(UUID2);
|
||||
final ExternalServiceCredentials cred2Old = atTime(GEN1, -1, UUID2);
|
||||
|
||||
final List<String> tokens = Stream.of(cred1New, cred1Old, cred2New, cred2Old)
|
||||
.map(ExternalServiceCredentialsSelectorTest::token)
|
||||
.toList();
|
||||
|
||||
final List<CredentialInfo> result = ExternalServiceCredentialsSelector.check(tokens, GEN1,
|
||||
TimeUnit.MINUTES.toSeconds(1));
|
||||
assertThat(result).hasSize(4);
|
||||
assertThat(result).filteredOn(CredentialInfo::valid)
|
||||
.hasSize(2)
|
||||
.map(CredentialInfo::credentials)
|
||||
.containsExactlyInAnyOrder(cred1New, cred2New);
|
||||
assertThat(result).filteredOn(info -> !info.valid())
|
||||
.map(CredentialInfo::token)
|
||||
.containsExactlyInAnyOrder(token(cred1Old), token(cred2Old));
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleGenerators() {
|
||||
final ExternalServiceCredentials gen1Cred = GEN1.generateForUuid(UUID1);
|
||||
final ExternalServiceCredentials gen2Cred = GEN2.generateForUuid(UUID1);
|
||||
|
||||
final List<CredentialInfo> result = ExternalServiceCredentialsSelector.check(
|
||||
List.of(token(gen1Cred), token(gen2Cred)),
|
||||
GEN2,
|
||||
TimeUnit.MINUTES.toSeconds(1));
|
||||
|
||||
assertThat(result)
|
||||
.hasSize(2)
|
||||
.filteredOn(CredentialInfo::valid)
|
||||
.singleElement()
|
||||
.matches(info -> info.credentials().equals(gen2Cred));
|
||||
|
||||
assertThat(result)
|
||||
.filteredOn(info -> !info.valid())
|
||||
.singleElement()
|
||||
.matches(info -> info.token().equals(token(gen1Cred)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void invalidCredentials(final String invalidCredential) {
|
||||
final ExternalServiceCredentials validCredential = GEN1.generateForUuid(UUID1);
|
||||
var result = ExternalServiceCredentialsSelector.check(
|
||||
List.of(invalidCredential, token(validCredential)), GEN1, TimeUnit.MINUTES.toSeconds(1));
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result).filteredOn(CredentialInfo::valid).singleElement()
|
||||
.matches(info -> info.credentials().equals(validCredential));
|
||||
assertThat(result).filteredOn(info -> !info.valid()).singleElement()
|
||||
.matches(info -> info.token().equals(invalidCredential));
|
||||
}
|
||||
|
||||
static Stream<String> invalidCredentials() {
|
||||
return Stream.of(
|
||||
"blah:blah",
|
||||
token(atTime(GEN1, -TimeUnit.MINUTES.toSeconds(2), UUID1)), // too old
|
||||
"nocolon",
|
||||
"nothingaftercolon:",
|
||||
":nothingbeforecolon",
|
||||
token(GEN2.generateForUuid(UUID1))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2013 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.auth;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Optional;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
|
||||
class OptionalAccessTest {
|
||||
|
||||
@Test
|
||||
void testUnidentifiedMissingTarget() {
|
||||
try {
|
||||
OptionalAccess.verify(Optional.empty(), Optional.empty(), Optional.empty());
|
||||
throw new AssertionError("should fail");
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnidentifiedMissingTargetDevice() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
when(account.getDevice(eq(10))).thenReturn(Optional.empty());
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||
|
||||
try {
|
||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.getEncoder().encodeToString("1234".getBytes()))), Optional.of(account), "10");
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnidentifiedBadTargetDevice() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
when(account.getDevice(eq(10))).thenReturn(Optional.empty());
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||
|
||||
try {
|
||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.getEncoder().encodeToString("1234".getBytes()))), Optional.of(account), "$$");
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 422);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUnidentifiedBadCode() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||
|
||||
try {
|
||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.getEncoder().encodeToString("5678".getBytes()))), Optional.of(account));
|
||||
throw new AssertionError("should fail");
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIdentifiedMissingTarget() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
|
||||
try {
|
||||
OptionalAccess.verify(Optional.of(account), Optional.empty(), Optional.empty());
|
||||
throw new AssertionError("should fail");
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 404);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnsolicitedBadTarget() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(false);
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
|
||||
try {
|
||||
OptionalAccess.verify(Optional.empty(), Optional.empty(), Optional.of(account));
|
||||
throw new AssertionError("should fail");
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnsolicitedGoodTarget() {
|
||||
Account account = mock(Account.class);
|
||||
Anonymous random = mock(Anonymous.class);
|
||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(true);
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
OptionalAccess.verify(Optional.empty(), Optional.of(random), Optional.of(account));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnidentifiedGoodTarget() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||
when(account.isEnabled()).thenReturn(true);
|
||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.getEncoder().encodeToString("1234".getBytes()))), Optional.of(account));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnidentifiedInactive() {
|
||||
Account account = mock(Account.class);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of("1234".getBytes()));
|
||||
when(account.isEnabled()).thenReturn(false);
|
||||
|
||||
try {
|
||||
OptionalAccess.verify(Optional.empty(), Optional.of(new Anonymous(Base64.getEncoder().encodeToString("1234".getBytes()))), Optional.of(account));
|
||||
throw new AssertionError();
|
||||
} catch (WebApplicationException e) {
|
||||
assertEquals(e.getResponse().getStatus(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIdentifiedGoodTarget() {
|
||||
Account source = mock(Account.class);
|
||||
Account target = mock(Account.class);
|
||||
when(target.isEnabled()).thenReturn(true);
|
||||
OptionalAccess.verify(Optional.of(source), Optional.empty(), Optional.of(target));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2013 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.auth;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SaltedTokenHashTest {
|
||||
|
||||
@Test
|
||||
void testCreating() {
|
||||
SaltedTokenHash credentials = SaltedTokenHash.generateFor("mypassword");
|
||||
assertThat(credentials.salt()).isNotEmpty();
|
||||
assertThat(credentials.hash()).isNotEmpty();
|
||||
assertThat(credentials.hash().length()).isEqualTo(66);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMatching() {
|
||||
SaltedTokenHash credentials = SaltedTokenHash.generateFor("mypassword");
|
||||
|
||||
SaltedTokenHash provided = new SaltedTokenHash(credentials.hash(), credentials.salt());
|
||||
assertThat(provided.verify("mypassword")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMisMatching() {
|
||||
SaltedTokenHash credentials = SaltedTokenHash.generateFor("mypassword");
|
||||
|
||||
SaltedTokenHash provided = new SaltedTokenHash(credentials.hash(), credentials.salt());
|
||||
assertThat(provided.verify("wrong")).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user