fix revokation bugs and add unit tests
This commit is contained in:
@@ -17,6 +17,7 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.time.*;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Optional;
|
||||
@@ -518,20 +519,110 @@ class TokenServiceTest {
|
||||
verify(refreshTokenRepository, never()).save(any());
|
||||
verifyNoInteractions(tokenFamilyRepository);
|
||||
}
|
||||
}
|
||||
|
||||
private TokenFamily activeFamily() {
|
||||
TokenFamily tokenFamily = new TokenFamily();
|
||||
tokenFamily.setId(1L);
|
||||
tokenFamily.setUser(createUser(1L, "user", "user"));
|
||||
tokenFamily.setExpiresAt(clock.instant().plusSeconds(10));
|
||||
return tokenFamily;
|
||||
@Nested
|
||||
@DisplayName("revoke()")
|
||||
class revoke {
|
||||
@Test
|
||||
void knownToken_revokesTokenAndFamily() {
|
||||
TokenFamily tokenFamily = activeFamily();
|
||||
RefreshToken refreshToken = tokenIn(tokenFamily);
|
||||
when(refreshTokenRepository.findByHash(any())).thenReturn(Optional.of(refreshToken));
|
||||
|
||||
tokenService.revoke(rawToken);
|
||||
|
||||
assertEquals(clock.instant(), tokenFamily.getRevokedAt());
|
||||
assertEquals(clock.instant(), refreshToken.getRevokedAt());
|
||||
}
|
||||
|
||||
private RefreshToken tokenIn(TokenFamily tokenFamily) {
|
||||
RefreshToken refreshToken = new RefreshToken();
|
||||
refreshToken.setTokenFamily(tokenFamily);
|
||||
refreshToken.setExpiresAt(clock.instant().plusSeconds(10));
|
||||
return refreshToken;
|
||||
@Test
|
||||
void knownToken_savesTokenAndFamily() {
|
||||
TokenFamily tokenFamily = activeFamily();
|
||||
RefreshToken refreshToken = tokenIn(tokenFamily);
|
||||
when(refreshTokenRepository.findByHash(any())).thenReturn(Optional.of(refreshToken));
|
||||
|
||||
tokenService.revoke(rawToken);
|
||||
|
||||
verify(tokenFamilyRepository).save(tokenFamily);
|
||||
verify(refreshTokenRepository).save(refreshToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
void knownToken_looksUpBySingleSha256Hash() throws Exception {
|
||||
when(refreshTokenRepository.findByHash(any())).thenReturn(Optional.empty());
|
||||
|
||||
tokenService.revoke(rawToken);
|
||||
|
||||
byte[] expectedHash = MessageDigest.getInstance("SHA-256").digest(HEX.parseHex(rawToken));
|
||||
verify(refreshTokenRepository).findByHash(expectedHash);
|
||||
}
|
||||
|
||||
@Test
|
||||
void alreadyRevoked_keepsOriginalTimestampsAndDoesNotSave() {
|
||||
Instant revokedAt = clock.instant();
|
||||
TokenFamily tokenFamily = activeFamily();
|
||||
tokenFamily.setRevokedAt(revokedAt);
|
||||
RefreshToken refreshToken = tokenIn(tokenFamily);
|
||||
refreshToken.setRevokedAt(revokedAt);
|
||||
when(refreshTokenRepository.findByHash(any())).thenReturn(Optional.of(refreshToken));
|
||||
|
||||
clock.advance(Duration.ofMinutes(1));
|
||||
tokenService.revoke(rawToken);
|
||||
|
||||
assertEquals(revokedAt, tokenFamily.getRevokedAt());
|
||||
assertEquals(revokedAt, refreshToken.getRevokedAt());
|
||||
verify(tokenFamilyRepository, never()).save(any());
|
||||
verify(refreshTokenRepository, never()).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownToken_doesNothing() {
|
||||
when(refreshTokenRepository.findByHash(any())).thenReturn(Optional.empty());
|
||||
|
||||
tokenService.revoke(rawToken);
|
||||
|
||||
verify(refreshTokenRepository, never()).save(any());
|
||||
verifyNoInteractions(tokenFamilyRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullToken_doesNothing() {
|
||||
tokenService.revoke(null);
|
||||
|
||||
verifyNoInteractions(refreshTokenRepository, tokenFamilyRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
void blankToken_doesNothing() {
|
||||
tokenService.revoke("");
|
||||
|
||||
verifyNoInteractions(refreshTokenRepository, tokenFamilyRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
void malformedToken_throwsNotAuthenticated() {
|
||||
assertThrows(
|
||||
NotAuthenticated.class,
|
||||
() -> tokenService.revoke("not-hex")
|
||||
);
|
||||
|
||||
verifyNoInteractions(refreshTokenRepository, tokenFamilyRepository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TokenFamily activeFamily() {
|
||||
TokenFamily tokenFamily = new TokenFamily();
|
||||
tokenFamily.setId(1L);
|
||||
tokenFamily.setUser(createUser(1L, "user", "user"));
|
||||
tokenFamily.setExpiresAt(clock.instant().plusSeconds(10));
|
||||
return tokenFamily;
|
||||
}
|
||||
|
||||
private RefreshToken tokenIn(TokenFamily tokenFamily) {
|
||||
RefreshToken refreshToken = new RefreshToken();
|
||||
refreshToken.setTokenFamily(tokenFamily);
|
||||
refreshToken.setExpiresAt(clock.instant().plusSeconds(10));
|
||||
return refreshToken;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user