WIP: feat(security): implement refresh tokens #49
@@ -2,9 +2,29 @@ package com.ddf.vodsystem.repositories;
|
||||
|
||||
import com.ddf.vodsystem.entities.TokenFamily;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Repository
|
||||
public interface TokenFamilyRepository extends JpaRepository<TokenFamily, Long> {
|
||||
/**
|
||||
* Deletes families that can no longer be refreshed: revoked, expired, or with every refresh
|
||||
* token expired. Their refresh tokens are removed by the {@code ON DELETE CASCADE} foreign key.
|
||||
*
|
||||
* @return the number of families deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Query("""
|
||||
DELETE FROM TokenFamily f
|
||||
WHERE f.revokedAt IS NOT NULL
|
||||
OR f.expiresAt <= ?1
|
||||
OR NOT EXISTS (
|
||||
SELECT 1 FROM RefreshToken r
|
||||
WHERE r.tokenFamily = f AND r.expiresAt > ?1
|
||||
)
|
||||
""")
|
||||
int deleteDead(Instant now);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ import com.ddf.vodsystem.entities.User;
|
||||
import com.ddf.vodsystem.exceptions.NotAuthenticated;
|
||||
import com.ddf.vodsystem.repositories.RefreshTokenRepository;
|
||||
import com.ddf.vodsystem.repositories.TokenFamilyRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -28,6 +31,7 @@ import java.util.Optional;
|
||||
*/
|
||||
@Service
|
||||
public class TokenService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TokenService.class);
|
||||
private static final SecureRandom RNG = new SecureRandom();
|
||||
private static final HexFormat HEX = HexFormat.of();
|
||||
|
||||
@@ -192,6 +196,19 @@ public class TokenService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled cleanup that deletes token families that can no longer be refreshed, along with all
|
||||
* their refresh tokens.
|
||||
* <p>
|
||||
* Runs hourly. Used tokens in live families are kept, since reuse detection needs them.
|
||||
*/
|
||||
@Scheduled(fixedDelay = 3_600_000)
|
||||
@Transactional
|
||||
public void deleteDeadSessions() {
|
||||
int deleted = tokenFamilyRepository.deleteDead(Instant.now(clock));
|
||||
if (deleted > 0) logger.info("Deleted {} dead token families", deleted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a successful {@link #rotate(String)}.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user