add lock to read by Hash
This commit is contained in:
@@ -1,15 +1,17 @@
|
|||||||
package com.ddf.vodsystem.repositories;
|
package com.ddf.vodsystem.repositories;
|
||||||
|
|
||||||
import com.ddf.vodsystem.entities.RefreshToken;
|
import com.ddf.vodsystem.entities.RefreshToken;
|
||||||
|
import jakarta.persistence.LockModeType;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Lock;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.sql.Ref;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
|
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
|
||||||
|
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||||
@Query("SELECT r FROM RefreshToken r WHERE r.tokenHash = ?1")
|
@Query("SELECT r FROM RefreshToken r WHERE r.tokenHash = ?1")
|
||||||
Optional<RefreshToken> findByHash(byte[] tokenHash);
|
Optional<RefreshToken> findByHash(byte[] tokenHash);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import java.security.SecureRandom;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HexFormat;
|
import java.util.HexFormat;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class TokenService {
|
public class TokenService {
|
||||||
@@ -83,21 +82,17 @@ public class TokenService {
|
|||||||
.orElseThrow(() -> new NotAuthenticated("No such refresh token"));
|
.orElseThrow(() -> new NotAuthenticated("No such refresh token"));
|
||||||
|
|
||||||
// Find Token Family
|
// Find Token Family
|
||||||
Optional<TokenFamily> tokenFamily = tokenFamilyRepository.findById(refreshToken.getTokenFamily().getId());
|
TokenFamily tokenFamily = refreshToken.getTokenFamily();
|
||||||
|
|
||||||
if (tokenFamily.isEmpty()) {
|
if (tokenFamily.getRevokedAt() != null) {
|
||||||
throw new IllegalStateException("Token must be tied to a family");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenFamily.get().getRevokedAt() != null) {
|
|
||||||
throw new NotAuthenticated("Token family has been revoked");
|
throw new NotAuthenticated("Token family has been revoked");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reuse Check
|
// Reuse Check
|
||||||
if (refreshToken.getUsedAt() != null) {
|
if (refreshToken.getUsedAt() != null) {
|
||||||
if (now.isAfter(refreshToken.getUsedAt().plus(refreshGracePeriod))) {
|
if (now.isAfter(refreshToken.getUsedAt().plus(refreshGracePeriod))) {
|
||||||
tokenFamily.get().setRevokedAt(Instant.now());
|
tokenFamily.setRevokedAt(Instant.now());
|
||||||
tokenFamilyRepository.save(tokenFamily.get());
|
tokenFamilyRepository.save(tokenFamily);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotAuthenticated("Refresh token already being used");
|
throw new NotAuthenticated("Refresh token already being used");
|
||||||
@@ -106,7 +101,7 @@ public class TokenService {
|
|||||||
// Expiry Check
|
// Expiry Check
|
||||||
if (
|
if (
|
||||||
now.isAfter(refreshToken.getExpiresAt()) ||
|
now.isAfter(refreshToken.getExpiresAt()) ||
|
||||||
now.isAfter(tokenFamily.get().getExpiresAt())
|
now.isAfter(tokenFamily.getExpiresAt())
|
||||||
) {
|
) {
|
||||||
throw new NotAuthenticated("Refresh token or family expired");
|
throw new NotAuthenticated("Refresh token or family expired");
|
||||||
}
|
}
|
||||||
@@ -118,10 +113,10 @@ public class TokenService {
|
|||||||
byte[] newRawToken = generateRandomBytes(32);
|
byte[] newRawToken = generateRandomBytes(32);
|
||||||
createRefreshToken(
|
createRefreshToken(
|
||||||
newRawToken,
|
newRawToken,
|
||||||
tokenFamily.get()
|
tokenFamily
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Rotation(tokenFamily.get().getUser().getId(), HEX.formatHex(newRawToken));
|
return new Rotation(tokenFamily.getUser().getId(), HEX.formatHex(newRawToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Rotation(Long userId, String newRefreshToken) {}
|
public record Rotation(Long userId, String newRefreshToken) {}
|
||||||
@@ -152,7 +147,7 @@ public class TokenService {
|
|||||||
refreshToken.setTokenHash(sha256(token));
|
refreshToken.setTokenHash(sha256(token));
|
||||||
refreshToken.setCreatedAt(now);
|
refreshToken.setCreatedAt(now);
|
||||||
refreshToken.setExpiresAt(now.plusMillis(refreshTokenExpirationMs.toMillis()));
|
refreshToken.setExpiresAt(now.plusMillis(refreshTokenExpirationMs.toMillis()));
|
||||||
return refreshTokenRepository.saveAndFlush(refreshToken);
|
return refreshTokenRepository.save(refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user