mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-04-19 11:11:18 +00:00
logout process
This commit is contained in:
parent
79439f392f
commit
762571f42b
@ -1,5 +1,7 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
@ -39,6 +41,9 @@ public class EndpointInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
|
||||
if ("GET".equalsIgnoreCase(request.getMethod())) {
|
||||
|
||||
Principal principal = request.getUserPrincipal();
|
||||
|
||||
if ("/".equals(request.getRequestURI())
|
||||
|| "/login".equals(request.getRequestURI())
|
||||
|| "/home".equals(request.getRequestURI())
|
||||
@ -55,20 +60,15 @@ public class EndpointInterceptor implements HandlerInterceptor {
|
||||
|| request.getRequestURI().endsWith(".webmanifest")
|
||||
|| request.getRequestURI().contains("/files/")) {
|
||||
return true;
|
||||
} else {
|
||||
} else if (principal != null) {
|
||||
if (session == null) {
|
||||
session = request.getSession(true);
|
||||
}
|
||||
|
||||
final HttpSession finalSession = session;
|
||||
String sessionId = finalSession.getId();
|
||||
|
||||
// Den aktuellen Benutzer (principalName) aus der Session ermitteln.
|
||||
// Es wird angenommen, dass das Attribut "principalName" in der Session gesetzt
|
||||
// wurde.
|
||||
final String currentPrincipal =
|
||||
finalSession.getAttribute("principalName") != null
|
||||
? finalSession.getAttribute("principalName").toString()
|
||||
: "unknown";
|
||||
final String currentPrincipal = principal.getName();
|
||||
|
||||
// Zähle alle nicht abgelaufenen Sessions des aktuellen Benutzers.
|
||||
long userSessions =
|
||||
|
@ -42,8 +42,6 @@ public class AnonymusSessionRegistry implements HttpSessionListener, SessionsInt
|
||||
return;
|
||||
}
|
||||
|
||||
session.setAttribute("principalName", "anonymousUser");
|
||||
|
||||
// Speichern des Erstellungszeitpunkts
|
||||
Date creationTime = new Date();
|
||||
|
||||
|
@ -9,7 +9,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@RestController
|
||||
public class AnonymusSessionStatusController {
|
||||
|
@ -36,6 +36,7 @@ import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationFailureHandler;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationSuccessHandler;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2ResponseAuthenticationConverter;
|
||||
import stirling.software.SPDF.config.security.session.PreLogoutDataCaptureHandler;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.User;
|
||||
@ -158,6 +159,8 @@ public class SecurityConfiguration {
|
||||
http.logout(
|
||||
logout ->
|
||||
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||
.addLogoutHandler(
|
||||
new PreLogoutDataCaptureHandler(sessionRegistry))
|
||||
.logoutSuccessHandler(
|
||||
new CustomLogoutSuccessHandler(applicationProperties))
|
||||
.clearAuthentication(true)
|
||||
|
@ -10,6 +10,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
@ -33,13 +34,20 @@ import stirling.software.SPDF.model.SessionEntity;
|
||||
public class CustomHttpSessionListener implements HttpSessionListener, SessionsInterface {
|
||||
|
||||
private final SessionPersistentRegistry sessionPersistentRegistry;
|
||||
private final boolean loginEnabled;
|
||||
private final boolean runningEE;
|
||||
|
||||
@Value("${server.servlet.session.timeout:120s}") // TODO: Change to 30m
|
||||
private Duration defaultMaxInactiveInterval;
|
||||
|
||||
public CustomHttpSessionListener(SessionPersistentRegistry sessionPersistentRegistry) {
|
||||
public CustomHttpSessionListener(
|
||||
SessionPersistentRegistry sessionPersistentRegistry,
|
||||
@Qualifier("loginEnabled") boolean loginEnabled,
|
||||
@Qualifier("runningEE") boolean runningEE) {
|
||||
super();
|
||||
this.sessionPersistentRegistry = sessionPersistentRegistry;
|
||||
this.loginEnabled = loginEnabled;
|
||||
this.runningEE = runningEE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -110,18 +118,46 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI
|
||||
if (principalName == null) {
|
||||
return;
|
||||
}
|
||||
session.setAttribute("principalName", principalName);
|
||||
if ("anonymousUser".equals(principalName)) {
|
||||
log.info("Principal is anonymousUser");
|
||||
if ("anonymousUser".equals(principalName) && loginEnabled) {
|
||||
return;
|
||||
}
|
||||
int allNonExpiredSessions = getAllNonExpiredSessions().size();
|
||||
if (allNonExpiredSessions >= getMaxUserSessions()) {
|
||||
|
||||
allNonExpiredSessions =
|
||||
getAllSessions().stream()
|
||||
.filter(s -> !s.isExpired())
|
||||
.filter(s -> s.getPrincipalName().equals(principalName))
|
||||
.filter(s -> "anonymousUser".equals(principalName) && !loginEnabled)
|
||||
.peek(s -> log.info("Session {}", s.getPrincipalName()))
|
||||
.toList()
|
||||
.size();
|
||||
|
||||
int all =
|
||||
getAllSessions().stream()
|
||||
.filter(s -> !s.isExpired() && s.getPrincipalName().equals(principalName))
|
||||
.toList()
|
||||
.size();
|
||||
boolean isAnonymousUserWithoutLogin = "anonymousUser".equals(principalName) && loginEnabled;
|
||||
log.info(
|
||||
"all {} allNonExpiredSessions {} {} isAnonymousUserWithoutLogin {}",
|
||||
all,
|
||||
allNonExpiredSessions,
|
||||
getMaxUserSessions(),
|
||||
isAnonymousUserWithoutLogin);
|
||||
|
||||
if (allNonExpiredSessions >= getMaxApplicationSessions() && !isAnonymousUserWithoutLogin) {
|
||||
log.info("Session {} Expired=TRUE", session.getId());
|
||||
sessionPersistentRegistry.expireSession(session.getId());
|
||||
sessionPersistentRegistry.removeSessionInformation(se.getSession().getId());
|
||||
// if (allNonExpiredSessions > getMaxUserSessions()) {
|
||||
// enforceMaxSessionsForPrincipal(principalName);
|
||||
// }
|
||||
} else if (all >= getMaxUserSessions() && !isAnonymousUserWithoutLogin) {
|
||||
enforceMaxSessionsForPrincipal(principalName);
|
||||
log.info("Session {} Expired=TRUE", principalName);
|
||||
} else if (isAnonymousUserWithoutLogin) {
|
||||
sessionPersistentRegistry.expireSession(session.getId());
|
||||
sessionPersistentRegistry.removeSessionInformation(se.getSession().getId());
|
||||
} else {
|
||||
log.info("Session created: {}", principalName);
|
||||
sessionPersistentRegistry.registerNewSession(se.getSession().getId(), principalName);
|
||||
@ -164,7 +200,6 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionInformation sessionsInfo =
|
||||
sessionPersistentRegistry.getSessionInformation(session.getId());
|
||||
if (sessionsInfo == null) {
|
||||
@ -197,4 +232,22 @@ public class CustomHttpSessionListener implements HttpSessionListener, SessionsI
|
||||
sessionPersistentRegistry.removeSessionInformation(session.getId());
|
||||
log.info("Session {} wurde Expired=TRUE", session.getId());
|
||||
}
|
||||
|
||||
// Get the maximum number of sessions
|
||||
@Override
|
||||
public int getMaxApplicationSessions() {
|
||||
if (runningEE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return getMaxUserSessions() * 10;
|
||||
}
|
||||
|
||||
// Get the maximum number of user sessions
|
||||
@Override
|
||||
public int getMaxUserSessions() {
|
||||
if (runningEE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package stirling.software.SPDF.config.security.session;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class PreLogoutDataCaptureHandler implements LogoutHandler {
|
||||
|
||||
private final SessionPersistentRegistry sessionPersistentRegistry;
|
||||
|
||||
@Override
|
||||
public void logout(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Authentication authentication) {
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String sessionId = session.getId();
|
||||
if (sessionId == null) {
|
||||
return;
|
||||
}
|
||||
String path = request.getServletPath();
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
if (!"/logout".equals(path)) {
|
||||
return;
|
||||
}
|
||||
log.debug("Session ID: {} Principal: {}", sessionId, authentication.getPrincipal());
|
||||
sessionPersistentRegistry.expireSession(sessionId);
|
||||
sessionPersistentRegistry.removeSessionInformation(sessionId);
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ public class SessionScheduled {
|
||||
} else if (principal instanceof String stringPrincipal) {
|
||||
// Skip anonymousUser if login is enabled
|
||||
if ("anonymousUser".equals(stringPrincipal) && loginEnabledValue) {
|
||||
sessionPersistentRegistry.expireAllSessionsByPrincipalName(stringPrincipal);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -49,18 +50,13 @@ public class SessionScheduled {
|
||||
Instant expirationTime =
|
||||
lastRequest.toInstant().plus(maxInactiveInterval, ChronoUnit.SECONDS);
|
||||
if (now.isAfter(expirationTime)) {
|
||||
log.info(
|
||||
"SessionID: {} expiration time: {} Current time: {}",
|
||||
sessionInformation.getSessionId(),
|
||||
expirationTime,
|
||||
now);
|
||||
sessionPersistentRegistry.expireSession(sessionInformation.getSessionId());
|
||||
sessionInformation.expireNow();
|
||||
if (authentication != null && principal.equals(authentication.getPrincipal())) {
|
||||
authentication.setAuthenticated(false);
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
log.info(
|
||||
log.debug(
|
||||
"Session expired for principal: {} SessionID: {}",
|
||||
principal,
|
||||
sessionInformation.getSessionId());
|
||||
|
@ -348,7 +348,6 @@ public class AccountWebController {
|
||||
model.addAttribute("maxSessions", maxSessions);
|
||||
model.addAttribute("maxUserSessions", maxUserSessions);
|
||||
model.addAttribute("sessionCount", sessionCount);
|
||||
model.addAttribute("maxEnterpriseUsers", applicationProperties.getPremium().getMaxUsers());
|
||||
model.addAttribute("maxPaidUsers", applicationProperties.getPremium().getMaxUsers());
|
||||
return "adminSettings";
|
||||
}
|
||||
|
@ -59,8 +59,8 @@
|
||||
</a>
|
||||
|
||||
<div class="my-4">
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.totalUsers}">Total Users:</strong> <span
|
||||
th:text="${totalUsers}"></span><span th:if="${@runningProOrHigher}" th:text="'/'+${maxEnterpriseUsers}"></span>
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.totalUsers}">Total Users:</strong>
|
||||
<span th:text="${totalUsers}"></span>
|
||||
<span th:if="${@runningProOrHigher}" th:text="'/'+${maxPaidUsers}"></span>
|
||||
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.activeUsers}">Active Users:</strong>
|
||||
@ -70,11 +70,13 @@
|
||||
<span th:text="${disabledUsers}"></span>
|
||||
<th:block th:if="${@runningProOrHigher}">
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.totalSessions}">Total
|
||||
Sessions:</strong> <span th:text="${sessionCount}"></span>
|
||||
Sessions:</strong>
|
||||
<span th:text="${sessionCount}"></span>
|
||||
</th:block>
|
||||
<th:block th:if="${!@runningProOrHigher}">
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.totalSessions}">Total
|
||||
Sessions:</strong> <span th:text="${sessionCount}"></span>/<span th:text="${maxSessions}"></span>
|
||||
Sessions:</strong>
|
||||
<span th:text="${sessionCount}"></span>/<span th:text="${maxSessions}"></span>
|
||||
</th:block>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user