refactor(core,common,proprietary): Replace Date with Instant/modern Date API alternative for improved time handling (#4497)

This commit is contained in:
Balázs Szücs
2025-09-28 17:41:20 +02:00
committed by GitHub
parent 07392ed25e
commit 133e6d3de6
21 changed files with 244 additions and 125 deletions

View File

@@ -4,7 +4,6 @@ import static stirling.software.common.util.ProviderUtils.validateProvider;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -218,7 +217,7 @@ public class AccountWebController {
Map<String, String> roleDetails = Role.getAllRoleDetails();
// Map to store session information and user activity status
Map<String, Boolean> userSessions = new HashMap<>();
Map<String, Date> userLastRequest = new HashMap<>();
Map<String, Instant> userLastRequest = new HashMap<>();
int activeUsers = 0;
int disabledUsers = 0;
while (iterator.hasNext()) {
@@ -249,27 +248,29 @@ public class AccountWebController {
// Determine the user's session status and last request time
int maxInactiveInterval = sessionPersistentRegistry.getMaxInactiveInterval();
boolean hasActiveSession = false;
Date lastRequest = null;
Instant lastRequest = null;
Optional<SessionEntity> latestSession =
sessionPersistentRegistry.findLatestSession(user.getUsername());
if (latestSession.isPresent()) {
SessionEntity sessionEntity = latestSession.get();
Date lastAccessedTime = sessionEntity.getLastRequest();
// sessionEntity stores Instant directly
Instant lastAccessedTime =
Optional.ofNullable(sessionEntity.getLastRequest())
.orElse(Instant.EPOCH);
Instant now = Instant.now();
// Calculate session expiration and update session status accordingly
Instant expirationTime =
lastAccessedTime
.toInstant()
.plus(maxInactiveInterval, ChronoUnit.SECONDS);
lastAccessedTime.plus(maxInactiveInterval, ChronoUnit.SECONDS);
if (now.isAfter(expirationTime)) {
sessionPersistentRegistry.expireSession(sessionEntity.getSessionId());
} else {
hasActiveSession = !sessionEntity.isExpired();
}
lastRequest = sessionEntity.getLastRequest();
lastRequest = lastAccessedTime;
} else {
// No session, set default last request time
lastRequest = new Date(0);
lastRequest = Instant.EPOCH;
}
userSessions.put(user.getUsername(), hasActiveSession);
userLastRequest.put(user.getUsername(), lastRequest);
@@ -286,19 +287,21 @@ public class AccountWebController {
allUsers.stream()
.sorted(
(u1, u2) -> {
boolean u1Active = userSessions.get(u1.getUsername());
boolean u2Active = userSessions.get(u2.getUsername());
boolean u1Active =
userSessions.getOrDefault(u1.getUsername(), false);
boolean u2Active =
userSessions.getOrDefault(u2.getUsername(), false);
if (u1Active && !u2Active) {
return -1;
} else if (!u1Active && u2Active) {
return 1;
} else {
Date u1LastRequest =
Instant u1LastRequest =
userLastRequest.getOrDefault(
u1.getUsername(), new Date(0));
Date u2LastRequest =
u1.getUsername(), Instant.EPOCH);
Instant u2LastRequest =
userLastRequest.getOrDefault(
u2.getUsername(), new Date(0));
u2.getUsername(), Instant.EPOCH);
return u2LastRequest.compareTo(u1LastRequest);
}
})

View File

@@ -1,6 +1,6 @@
package stirling.software.proprietary.security.controller.web;
import java.util.Date;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -44,17 +44,17 @@ public class TeamWebController {
// Filter out the Internal team
List<TeamWithUserCountDTO> teamsWithCounts =
allTeamsWithCounts.stream()
.filter(team -> !team.getName().equals(TeamService.INTERNAL_TEAM_NAME))
.filter(team -> !TeamService.INTERNAL_TEAM_NAME.equals(team.getName()))
.toList();
// Get the latest activity for each team
List<Object[]> teamActivities = sessionRepository.findLatestActivityByTeam();
// Convert the query results to a map for easy access in the view
Map<Long, Date> teamLastRequest = new HashMap<>();
Map<Long, Instant> teamLastRequest = new HashMap<>();
for (Object[] result : teamActivities) {
Long teamId = (Long) result[0]; // teamId alias
Date lastActivity = (Date) result[1]; // lastActivity alias
Instant lastActivity = (Instant) result[1]; // lastActivity alias
teamLastRequest.put(teamId, lastActivity);
}
@@ -97,7 +97,7 @@ public class TeamWebController {
.orElseThrow(() -> new RuntimeException("Team not found"));
// Prevent access to Internal team
if (team.getName().equals(TeamService.INTERNAL_TEAM_NAME)) {
if (TeamService.INTERNAL_TEAM_NAME.equals(team.getName())) {
return "redirect:/teams?error=internalTeamNotAccessible";
}
@@ -114,21 +114,18 @@ public class TeamWebController {
(user.getTeam() == null
|| !user.getTeam().getId().equals(id))
&& (user.getTeam() == null
|| !user.getTeam()
.getName()
.equals(
TeamService
.INTERNAL_TEAM_NAME)))
|| !TeamService.INTERNAL_TEAM_NAME.equals(
user.getTeam().getName())))
.toList();
// Get the latest session for each user in the team
List<Object[]> userSessions = sessionRepository.findLatestSessionByTeamId(id);
// Create a map of username to last request date
Map<String, Date> userLastRequest = new HashMap<>();
Map<String, Instant> userLastRequest = new HashMap<>();
for (Object[] result : userSessions) {
String username = (String) result[0]; // username alias
Date lastRequest = (Date) result[1]; // lastRequest alias
Instant lastRequest = (Instant) result[1]; // lastRequest alias
userLastRequest.put(username, lastRequest);
}

View File

@@ -23,7 +23,7 @@ public class JPATokenRepositoryImpl implements PersistentTokenRepository {
newToken.setSeries(token.getSeries());
newToken.setUsername(token.getUsername());
newToken.setToken(token.getTokenValue());
newToken.setLastUsed(token.getDate());
newToken.setLastUsed(token.getDate().toInstant());
persistentLoginRepository.save(newToken);
}
@@ -33,7 +33,7 @@ public class JPATokenRepositoryImpl implements PersistentTokenRepository {
PersistentLogin existingToken = persistentLoginRepository.findById(series).orElse(null);
if (existingToken != null) {
existingToken.setToken(tokenValue);
existingToken.setLastUsed(lastUsed);
existingToken.setLastUsed(lastUsed.toInstant());
persistentLoginRepository.save(existingToken);
}
}
@@ -43,7 +43,10 @@ public class JPATokenRepositoryImpl implements PersistentTokenRepository {
PersistentLogin token = persistentLoginRepository.findById(seriesId).orElse(null);
if (token != null) {
return new PersistentRememberMeToken(
token.getUsername(), token.getSeries(), token.getToken(), token.getLastUsed());
token.getUsername(),
token.getSeries(),
token.getToken(),
Date.from(token.getLastUsed()));
}
return null;
}

View File

@@ -1,6 +1,6 @@
package stirling.software.proprietary.security.database.repository;
import java.util.Date;
import java.time.Instant;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -27,7 +27,7 @@ public interface SessionRepository extends JpaRepository<SessionEntity, String>
"UPDATE SessionEntity s SET s.expired = :expired, s.lastRequest = :lastRequest WHERE s.principalName = :principalName")
void saveByPrincipalName(
@Param("expired") boolean expired,
@Param("lastRequest") Date lastRequest,
@Param("lastRequest") Instant lastRequest,
@Param("principalName") String principalName);
@Query(

View File

@@ -1,8 +1,9 @@
package stirling.software.proprietary.security.filter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
@@ -60,8 +61,12 @@ public class FirstLoginFilter extends OncePerRequestFilter {
}
if (log.isDebugEnabled()) {
HttpSession session = request.getSession(true);
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
String creationTime = timeFormat.format(new Date(session.getCreationTime()));
DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
String creationTime =
timeFormat.format(
Instant.ofEpochMilli(session.getCreationTime())
.atZone(ZoneId.systemDefault())
.toLocalTime());
log.debug(
"Request Info - New: {}, creationTimeSession {}, ID: {}, IP: {}, User-Agent: {}, Referer: {}, Request URL: {}",
session.isNew(),

View File

@@ -1,6 +1,6 @@
package stirling.software.proprietary.security.model;
import java.util.Date;
import java.time.Instant;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -25,5 +25,5 @@ public class PersistentLogin {
private String token;
@Column(name = "last_used", nullable = false)
private Date lastUsed;
private Instant lastUsed;
}

View File

@@ -1,7 +1,7 @@
package stirling.software.proprietary.security.model;
import java.io.Serializable;
import java.util.Date;
import java.time.Instant;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@@ -17,7 +17,7 @@ public class SessionEntity implements Serializable {
private String principalName;
private Date lastRequest;
private Instant lastRequest;
private boolean expired;
}

View File

@@ -4,6 +4,7 @@ import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
@@ -92,8 +93,8 @@ public class JwtService implements JwtServiceInterface {
.claims(claims)
.subject(username)
.issuer(ISSUER)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + EXPIRATION))
.issuedAt(Date.from(Instant.now()))
.expiration(Date.from(Instant.now().plusMillis(EXPIRATION)))
.signWith(keyPair.getPrivate(), Jwts.SIG.RS256);
String keyId = activeKey.getKeyId();
@@ -129,7 +130,7 @@ public class JwtService implements JwtServiceInterface {
@Override
public boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
return extractExpiration(token).before(Date.from(Instant.now()));
}
private Date extractExpiration(String token) {

View File

@@ -1,6 +1,7 @@
package stirling.software.proprietary.security.session;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -67,7 +68,7 @@ public class SessionPersistentRegistry implements SessionRegistry {
new SessionInformation(
sessionEntity.getPrincipalName(),
sessionEntity.getSessionId(),
sessionEntity.getLastRequest()));
Date.from(sessionEntity.getLastRequest())));
}
}
}
@@ -101,7 +102,7 @@ public class SessionPersistentRegistry implements SessionRegistry {
SessionEntity sessionEntity = new SessionEntity();
sessionEntity.setSessionId(sessionId);
sessionEntity.setPrincipalName(principalName);
sessionEntity.setLastRequest(new Date()); // Set lastRequest to the current date
sessionEntity.setLastRequest(Instant.now()); // Set lastRequest to the current date
sessionEntity.setExpired(false);
sessionRepository.save(sessionEntity);
}
@@ -119,7 +120,7 @@ public class SessionPersistentRegistry implements SessionRegistry {
Optional<SessionEntity> sessionEntityOpt = sessionRepository.findById(sessionId);
if (sessionEntityOpt.isPresent()) {
SessionEntity sessionEntity = sessionEntityOpt.get();
sessionEntity.setLastRequest(new Date()); // Update lastRequest to the current date
sessionEntity.setLastRequest(Instant.now()); // Update lastRequest to the current date
sessionRepository.save(sessionEntity);
}
}
@@ -132,7 +133,7 @@ public class SessionPersistentRegistry implements SessionRegistry {
return new SessionInformation(
sessionEntity.getPrincipalName(),
sessionEntity.getSessionId(),
sessionEntity.getLastRequest());
Date.from(sessionEntity.getLastRequest()));
}
return null;
}
@@ -170,7 +171,7 @@ public class SessionPersistentRegistry implements SessionRegistry {
// Update session details by principal name
public void updateSessionByPrincipalName(
String principalName, boolean expired, Date lastRequest) {
sessionRepository.saveByPrincipalName(expired, lastRequest, principalName);
sessionRepository.saveByPrincipalName(expired, lastRequest.toInstant(), principalName);
}
// Find the latest session for a given principal name