Compare commits

..

2 Commits

Author SHA1 Message Date
Zakaria a59913bb38 fix(cognito): keep revoked tokens across restarts
RevokedTokenInfo serialized its derived isExpired() as "expired", which the
persistent store's ObjectMapper then refused to read back. On restart the file
was moved aside as .corrupt and every revocation was forgotten, so refresh
tokens revoked by sign-out worked again. The derived field is no longer
written, and files that carry it are read with it ignored.
2026-10-24 14:50:02 -04:00
Zakaria 2969939a99 Merge pull request 'feat(cloudfront): serve POST, PUT, PATCH and DELETE viewer requests (#4229)' (#4) from feat/cloudfront-upstream-fixes into main
Reviewed-on: #4
2026-10-24 18:38:31 +00:00
2 changed files with 51 additions and 0 deletions
@@ -3,13 +3,19 @@ package io.github.hectorvent.floci.services.cognito.model;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
/** /**
* Information about a revoked token for tracking and validation purposes. * Information about a revoked token for tracking and validation purposes.
* Used to implement AWS Cognito AdminUserGlobalSignOut token revocation behavior. * Used to implement AWS Cognito AdminUserGlobalSignOut token revocation behavior.
*
* <p>{@code expired} is derived from {@code expiresAt}, so it is not stored. Files written before
* that still carry it, and are read with it ignored instead of being discarded as corrupt.
*/ */
@RegisterForReflection @RegisterForReflection
@JsonIgnoreProperties(ignoreUnknown = true)
public class RevokedTokenInfo { public class RevokedTokenInfo {
private final String jti; private final String jti;
@@ -62,6 +68,7 @@ public class RevokedTokenInfo {
/** /**
* Check if this revocation record has expired and can be cleaned up. * Check if this revocation record has expired and can be cleaned up.
*/ */
@JsonIgnore
public boolean isExpired() { public boolean isExpired() {
return System.currentTimeMillis() / 1000L > expiresAt; return System.currentTimeMillis() / 1000L > expiresAt;
} }
@@ -0,0 +1,44 @@
package io.github.hectorvent.floci.services.cognito;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.hectorvent.floci.services.cognito.model.RevokedTokenInfo;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
/** Revoked tokens must survive a restart, which reads them back with a strict ObjectMapper. */
class RevokedTokenInfoPersistenceTest {
private static final TypeReference<Map<String, RevokedTokenInfo>> TYPE = new TypeReference<>() {
};
private final ObjectMapper strictMapper = new ObjectMapper();
@Test
void roundTripsWithoutTheDerivedExpiredField() throws Exception {
RevokedTokenInfo info = new RevokedTokenInfo("jti-1", "refresh", "alice", "us-east-1_pool", 1_000L, 4_102_444_800L);
String json = strictMapper.writeValueAsString(Map.of("k", info));
RevokedTokenInfo read = strictMapper.readValue(json, TYPE).get("k");
assertFalse(json.contains("\"expired\""), json);
assertEquals("jti-1", read.getJti());
assertEquals(4_102_444_800L, read.getExpiresAt());
}
@Test
void readsFilesWrittenWithTheExpiredField() throws Exception {
String saved = """
{"000000000000/revoked:us-east-1_pool:jti-1":{"jti":"jti-1","tokenType":"refresh","username":"alice",
"userPoolId":"us-east-1_pool","revokedAt":1792858112669,"expiresAt":1824394112,"expired":false}}
""";
RevokedTokenInfo read = strictMapper.readValue(saved, TYPE).get("000000000000/revoked:us-east-1_pool:jti-1");
assertEquals("alice", read.getUsername());
assertEquals(1824394112L, read.getExpiresAt());
}
}