From a16b6478a784d05d37a2ab04b549f4f04357f10e Mon Sep 17 00:00:00 2001 From: Ludy87 Date: Sun, 30 Mar 2025 23:12:04 +0200 Subject: [PATCH] any more change --- .../SPDF/config/EndpointInterceptor.java | 18 ++++-- .../session/AnonymusSessionRegistry.java | 15 +++-- .../config/interfaces/SessionsInterface.java | 6 +- .../session/CustomHttpSessionListener.java | 57 ++++++++++++++++--- .../session/SessionStatusController.java | 4 +- .../controller/web/AccountWebController.java | 34 +++++------ .../resources/templates/adminSettings.html | 14 ++--- 7 files changed, 101 insertions(+), 47 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java b/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java index 8b8d7521a..611a852f6 100644 --- a/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java +++ b/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java @@ -80,11 +80,13 @@ public class EndpointInterceptor implements HandlerInterceptor { .filter(s -> !s.isExpired()) .count(); - log.debug( + int maxUserSessions = sessionsInterface.getMaxUserSessions(); + + log.info( "Active sessions for {}: {} (max: {}) | Total: {} (max: {})", currentPrincipal, userSessions, - sessionsInterface.getMaxUserSessions(), + maxUserSessions, totalSessions, sessionsInterface.getMaxApplicationSessions()); @@ -93,7 +95,7 @@ public class EndpointInterceptor implements HandlerInterceptor { .filter(s -> !s.isExpired()) .anyMatch(s -> s.getSessionId().equals(sessionId)); - if ((userSessions >= sessionsInterface.getMaxUserSessions() + if ((userSessions >= maxUserSessions || totalSessions >= sessionsInterface.getMaxApplicationSessions()) && !isCurrentSessionRegistered) { response.sendError( @@ -129,8 +131,14 @@ public class EndpointInterceptor implements HandlerInterceptor { .filter(s -> !s.isExpired()) .anyMatch(s -> s.getSessionId().equals(sessionId)); - if (totalSessions >= sessionsInterface.getMaxApplicationSessions() - && !isCurrentSessionRegistered) { + int maxApplicationSessions = sessionsInterface.getMaxApplicationSessions(); + + log.info( + "Active sessions for anonymous: Total: {} (max: {})", + totalSessions, + maxApplicationSessions); + + if (totalSessions >= maxApplicationSessions && !isCurrentSessionRegistered) { response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Max sessions reached for this user. To continue on this device, please" diff --git a/src/main/java/stirling/software/SPDF/config/anonymus/session/AnonymusSessionRegistry.java b/src/main/java/stirling/software/SPDF/config/anonymus/session/AnonymusSessionRegistry.java index 00d6190e2..0a2c39e4b 100644 --- a/src/main/java/stirling/software/SPDF/config/anonymus/session/AnonymusSessionRegistry.java +++ b/src/main/java/stirling/software/SPDF/config/anonymus/session/AnonymusSessionRegistry.java @@ -167,11 +167,6 @@ public class AnonymusSessionRegistry implements HttpSessionListener, SessionsInt } } - @Override - public int getMaxApplicationSessions() { - return getMaxUserSessions(); - } - @Override public void removeSession(HttpSession session) { AnonymusSessionInfo sessionsInfo = (AnonymusSessionInfo) sessions.get(session.getId()); @@ -179,4 +174,14 @@ public class AnonymusSessionRegistry implements HttpSessionListener, SessionsInt session.invalidate(); sessions.remove(session.getId()); } + + @Override + public int getMaxApplicationSessions() { + return 5; + } + + @Override + public int getMaxUsers() { + return 1; + } } diff --git a/src/main/java/stirling/software/SPDF/config/interfaces/SessionsInterface.java b/src/main/java/stirling/software/SPDF/config/interfaces/SessionsInterface.java index d4d4314b8..7197e7ba9 100644 --- a/src/main/java/stirling/software/SPDF/config/interfaces/SessionsInterface.java +++ b/src/main/java/stirling/software/SPDF/config/interfaces/SessionsInterface.java @@ -21,6 +21,10 @@ public interface SessionsInterface { } default int getMaxApplicationSessions() { - return 10 * getMaxUserSessions(); + return getMaxUserSessions() * 3; + } + + default int getMaxUsers() { + return 10; } } diff --git a/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java b/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java index 526864d78..c93bb0a32 100644 --- a/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java +++ b/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Qualifier; @@ -27,12 +28,14 @@ import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.interfaces.SessionsInterface; import stirling.software.SPDF.config.interfaces.SessionsModelInterface; import stirling.software.SPDF.config.security.UserUtils; +import stirling.software.SPDF.model.ApplicationProperties; @Component @Slf4j public class CustomHttpSessionListener implements HttpSessionListener, SessionsInterface { private final SessionPersistentRegistry sessionPersistentRegistry; + private final ApplicationProperties applicationProperties; private final boolean loginEnabled; private final boolean runningEE; @@ -42,11 +45,13 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI public CustomHttpSessionListener( SessionPersistentRegistry sessionPersistentRegistry, @Qualifier("loginEnabled") boolean loginEnabled, - @Qualifier("runningEE") boolean runningEE) { + @Qualifier("runningEE") boolean runningEE, + ApplicationProperties applicationProperties) { super(); this.sessionPersistentRegistry = sessionPersistentRegistry; this.loginEnabled = loginEnabled; this.runningEE = runningEE; + this.applicationProperties = applicationProperties; } @Override @@ -56,6 +61,14 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI .toList(); } + public List getAllSessions(Object principalName, boolean expired) { + return sessionPersistentRegistry.getAllSessions().stream() + .filter(s -> s.getPrincipalName().equals(principalName)) + .filter(s -> expired == s.isExpired()) + .sorted(Comparator.comparing(SessionsModelInterface::getLastRequest)) + .collect(Collectors.toList()); + } + @Override public Collection getAllSessions() { return new ArrayList<>(sessionPersistentRegistry.getAllSessions()); @@ -66,6 +79,20 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI sessionPersistentRegistry.refreshLastRequest(sessionId); } + public Optional findLatestSession(String principalName) { + return getAllSessions(principalName, false).stream() + .filter(s -> s.getPrincipalName().equals(principalName)) + .max(Comparator.comparing(SessionsModelInterface::getLastRequest)); + } + + public void expireSession(String sessionId) { + sessionPersistentRegistry.expireSession(sessionId); + } + + public int getMaxInactiveInterval() { + return (int) defaultMaxInactiveInterval.getSeconds(); + } + @Override public void sessionCreated(HttpSessionEvent se) { HttpSession session = se.getSession(); @@ -207,21 +234,33 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI log.debug("Session {} expired=TRUE", session.getId()); } - // Get the maximum number of sessions + // Get the maximum number of application sessions @Override public int getMaxApplicationSessions() { - if (runningEE) { - return Integer.MAX_VALUE; - } - return getMaxUserSessions() * 10; + return getMaxUsers() * getMaxUserSessions(); } // Get the maximum number of user sessions @Override public int getMaxUserSessions() { - if (runningEE) { - return Integer.MAX_VALUE; + if (loginEnabled) { + return 3; } - return 3; + return 10; + } + + // Get the maximum number of user sessions + @Override + public int getMaxUsers() { + if (loginEnabled) { + if (runningEE) { + int maxUsers = applicationProperties.getPremium().getMaxUsers(); + if (maxUsers > 0) { + return maxUsers; + } + } + return 50; + } + return 1; } } diff --git a/src/main/java/stirling/software/SPDF/config/security/session/SessionStatusController.java b/src/main/java/stirling/software/SPDF/config/security/session/SessionStatusController.java index 1e928a6fc..d5bbfefe9 100644 --- a/src/main/java/stirling/software/SPDF/config/security/session/SessionStatusController.java +++ b/src/main/java/stirling/software/SPDF/config/security/session/SessionStatusController.java @@ -18,6 +18,7 @@ import jakarta.servlet.http.HttpSession; import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.interfaces.SessionsInterface; import stirling.software.SPDF.config.security.UserUtils; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; @@ -26,6 +27,7 @@ import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; public class SessionStatusController { @Autowired private SessionPersistentRegistry sessionPersistentRegistry; + @Autowired private SessionsInterface sessionInterface; // Returns the current session ID or 401 if no session exists @GetMapping("/session") @@ -59,7 +61,7 @@ public class SessionStatusController { .anyMatch(sessionEntity -> !sessionEntity.isExpired()); int userSessions = allSessions.size(); - int maxUserSessions = sessionPersistentRegistry.getMaxUserSessions(); + int maxUserSessions = sessionInterface.getMaxUserSessions(); // Check if the current session is valid or expired based on the session registry if (userSessions >= maxUserSessions && !isActivSession) { diff --git a/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java b/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java index f093d662c..51ab5c8be 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java @@ -14,7 +14,6 @@ import java.util.Optional; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; -import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; @@ -30,8 +29,9 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.interfaces.SessionsModelInterface; import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; -import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; +import stirling.software.SPDF.config.security.session.CustomHttpSessionListener; import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties.Security; import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; @@ -54,7 +54,7 @@ public class AccountWebController { public static final String OAUTH_2_AUTHORIZATION = "/oauth2/authorization/"; private final ApplicationProperties applicationProperties; - private final SessionPersistentRegistry sessionPersistentRegistry; + private final CustomHttpSessionListener customHttpSessionListener; // Assuming you have a repository for user operations private final UserRepository userRepository; private final boolean loginEnabledValue; @@ -62,15 +62,15 @@ public class AccountWebController { public AccountWebController( ApplicationProperties applicationProperties, - SessionPersistentRegistry sessionPersistentRegistry, UserRepository userRepository, @Qualifier("loginEnabled") boolean loginEnabledValue, - @Qualifier("runningEE") boolean runningEE) { + @Qualifier("runningEE") boolean runningEE, + CustomHttpSessionListener customHttpSessionListener) { this.applicationProperties = applicationProperties; - this.sessionPersistentRegistry = sessionPersistentRegistry; this.userRepository = userRepository; this.loginEnabledValue = loginEnabledValue; this.runningEE = runningEE; + this.customHttpSessionListener = customHttpSessionListener; } @GetMapping("/login") @@ -224,9 +224,9 @@ public class AccountWebController { Map userActiveSessions = new HashMap<>(); int activeUsers = 0; int disabledUsers = 0; - int maxSessions = sessionPersistentRegistry.getMaxSessions(); - int maxUserSessions = sessionPersistentRegistry.getMaxUserSessions(); - int sessionCount = sessionPersistentRegistry.getAllSessionsNotExpired().size(); + int maxSessions = customHttpSessionListener.getMaxApplicationSessions(); + int maxUserSessions = customHttpSessionListener.getMaxUserSessions(); + int sessionCount = customHttpSessionListener.getAllNonExpiredSessions().size(); while (iterator.hasNext()) { User user = iterator.next(); if (user != null) { @@ -239,13 +239,13 @@ public class AccountWebController { } } // Determine the user's session status and last request time - int maxInactiveInterval = sessionPersistentRegistry.getMaxInactiveInterval(); + int maxInactiveInterval = customHttpSessionListener.getMaxInactiveInterval(); boolean hasActiveSession = false; Date lastRequest; - Optional latestSession = - sessionPersistentRegistry.findLatestSession(user.getUsername()); + Optional latestSession = + customHttpSessionListener.findLatestSession(user.getUsername()); if (latestSession.isPresent()) { - SessionEntity sessionEntity = latestSession.get(); + SessionEntity sessionEntity = (SessionEntity) latestSession.get(); Date lastAccessedTime = sessionEntity.getLastRequest(); Instant now = Instant.now(); // Calculate session expiration and update session status accordingly @@ -254,7 +254,7 @@ public class AccountWebController { .toInstant() .plus(maxInactiveInterval, ChronoUnit.SECONDS); if (now.isAfter(expirationTime)) { - sessionPersistentRegistry.expireSession(sessionEntity.getSessionId()); + customHttpSessionListener.expireSession(sessionEntity.getSessionId()); } else { hasActiveSession = !sessionEntity.isExpired(); } @@ -271,8 +271,8 @@ public class AccountWebController { if (!user.isEnabled()) { disabledUsers++; } - List sessionInformations = - sessionPersistentRegistry.getAllSessions(user.getUsername(), false); + List sessionInformations = + customHttpSessionListener.getAllSessions(user.getUsername(), false); userActiveSessions.put(user.getUsername(), sessionInformations.size()); } } @@ -348,7 +348,7 @@ public class AccountWebController { model.addAttribute("maxSessions", maxSessions); model.addAttribute("maxUserSessions", maxUserSessions); model.addAttribute("sessionCount", sessionCount); - model.addAttribute("maxPaidUsers", applicationProperties.getPremium().getMaxUsers()); + model.addAttribute("maxPaidUsers", customHttpSessionListener.getMaxUsers()); return "adminSettings"; } diff --git a/src/main/resources/templates/adminSettings.html b/src/main/resources/templates/adminSettings.html index 9942e946c..a3f701720 100644 --- a/src/main/resources/templates/adminSettings.html +++ b/src/main/resources/templates/adminSettings.html @@ -37,10 +37,10 @@