mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-04-19 11:11:18 +00:00
add runningEE and more
This commit is contained in:
parent
e7b3fd0859
commit
969ca7be50
@ -1,6 +1,7 @@
|
||||
package stirling.software.SPDF.config.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
@ -66,43 +67,50 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||
Object principalTest = authentication.getPrincipal();
|
||||
String username = UserUtils.getUsernameFromPrincipal(principalTest);
|
||||
|
||||
log.info("Principal: {}", username);
|
||||
List<SessionInformation> allSessions =
|
||||
sessionPersistentRegistry.getAllSessions(username, false);
|
||||
|
||||
int userSessions = allSessions.size();
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) {
|
||||
session = request.getSession(true);
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
String sessionId = session.getId();
|
||||
|
||||
String sessionId = request.getSession(false).getId();
|
||||
|
||||
log.info("allSessions: {} username: {}", allSessions.size(), username);
|
||||
|
||||
if (allSessions.size() > 2) {
|
||||
// Sortiere nach letzter Aktivität – älteste zuerst
|
||||
List<SessionInformation> sortedSessions =
|
||||
allSessions.stream()
|
||||
.sorted(Comparator.comparing(SessionInformation::getLastRequest))
|
||||
.collect(Collectors.toList());
|
||||
int sessionsToExpire = allSessions.size() - 2;
|
||||
for (int i = 0; i < sessionsToExpire; i++) {
|
||||
SessionInformation oldSession = sortedSessions.get(i);
|
||||
if (!sessionId.equals(oldSession.getSessionId())) {
|
||||
sessionPersistentRegistry.expireSession(oldSession.getSessionId());
|
||||
oldSession.expireNow();
|
||||
log.info(
|
||||
"Expired old session: {} (last request: {})",
|
||||
oldSession.getSessionId(),
|
||||
oldSession.getLastRequest());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (SessionInformation sessionInformation : allSessions) {
|
||||
if (sessionId.equals(sessionInformation.getSessionId())) {
|
||||
log.info("Session found: {}", sessionId);
|
||||
log.info("lastRequest: {}", sessionInformation.getLastRequest());
|
||||
sessionPersistentRegistry.refreshLastRequest(sessionId);
|
||||
SessionInformation sessionInfo =
|
||||
sessionPersistentRegistry.getSessionInformation(sessionId);
|
||||
log.info("new lastRequest: {}", sessionInfo.getLastRequest());
|
||||
} else if (allSessions.size() > 2) {
|
||||
sessionPersistentRegistry.expireSession(sessionId);
|
||||
sessionInformation.expireNow();
|
||||
authentication.setAuthenticated(false);
|
||||
SecurityContextHolder.clearContext();
|
||||
request.getSession().invalidate();
|
||||
log.info(
|
||||
"Expired session: {} Date: {}",
|
||||
sessionInformation.getSessionId(),
|
||||
sessionInformation.getLastRequest());
|
||||
response.sendRedirect(request.getContextPath() + "/login?error=expiredSession");
|
||||
return;
|
||||
}
|
||||
}
|
||||
allSessions = sessionPersistentRegistry.getAllSessions(username, false);
|
||||
|
||||
log.info(
|
||||
"username: {} || before Sessions: {} | after Sessions: {}",
|
||||
username,
|
||||
userSessions,
|
||||
allSessions.size());
|
||||
|
||||
SessionEntity sessionEntity = sessionPersistentRegistry.getSessionEntity(sessionId);
|
||||
|
||||
if (allSessions.isEmpty() || sessionEntity.isExpired()) {
|
||||
|
@ -7,6 +7,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.session.SessionInformation;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
@ -24,11 +25,14 @@ import stirling.software.SPDF.model.SessionEntity;
|
||||
public class SessionPersistentRegistry implements SessionRegistry {
|
||||
|
||||
private final SessionRepository sessionRepository;
|
||||
private final boolean runningEE;
|
||||
|
||||
@Value("${server.servlet.session.timeout:120s}") // TODO: Change to 30m
|
||||
private Duration defaultMaxInactiveInterval;
|
||||
|
||||
public SessionPersistentRegistry(SessionRepository sessionRepository) {
|
||||
public SessionPersistentRegistry(
|
||||
SessionRepository sessionRepository, @Qualifier("runningEE") boolean runningEE) {
|
||||
this.runningEE = runningEE;
|
||||
this.sessionRepository = sessionRepository;
|
||||
}
|
||||
|
||||
@ -184,4 +188,12 @@ public class SessionPersistentRegistry implements SessionRegistry {
|
||||
// The first session in the list is the latest session for the given principal name
|
||||
return Optional.of(allSessions.get(0));
|
||||
}
|
||||
|
||||
// Get the maximum number of sessions
|
||||
public int getMaxSessions() {
|
||||
if (runningEE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package stirling.software.SPDF.config.security.session;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
@ -14,7 +15,7 @@ public class SessionRegistryConfig {
|
||||
|
||||
@Bean
|
||||
public SessionPersistentRegistry sessionPersistentRegistry(
|
||||
SessionRepository sessionRepository) {
|
||||
return new SessionPersistentRegistry(sessionRepository);
|
||||
SessionRepository sessionRepository, @Qualifier("runningEE") boolean runningEE) {
|
||||
return new SessionPersistentRegistry(sessionRepository, runningEE);
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import org.springframework.http.ResponseEntity;
|
||||
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.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@ -30,7 +28,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.SPDF.config.security.UserService;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.config.security.UserUtils;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
@ -293,19 +291,11 @@ public class UserController {
|
||||
if (!enabled) {
|
||||
// Invalidate all sessions if the user is being disabled
|
||||
List<Object> principals = sessionRegistry.getAllPrincipals();
|
||||
String userNameP = "";
|
||||
for (Object principal : principals) {
|
||||
List<SessionInformation> sessionsInformation =
|
||||
sessionRegistry.getAllSessions(principal, false);
|
||||
if (principal instanceof UserDetails detailsUser) {
|
||||
userNameP = detailsUser.getUsername();
|
||||
} else if (principal instanceof OAuth2User oAuth2User) {
|
||||
userNameP = oAuth2User.getName();
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal saml2User) {
|
||||
userNameP = saml2User.name();
|
||||
} else if (principal instanceof String stringUser) {
|
||||
userNameP = stringUser;
|
||||
}
|
||||
String userNameP = UserUtils.getUsernameFromPrincipal(principal);
|
||||
|
||||
if (userNameP.equalsIgnoreCase(username)) {
|
||||
for (SessionInformation sessionInfo : sessionsInformation) {
|
||||
sessionRegistry.expireSession(sessionInfo.getSessionId());
|
||||
|
@ -14,6 +14,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
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;
|
||||
@ -205,8 +206,10 @@ public class AccountWebController {
|
||||
// Map to store session information and user activity status
|
||||
Map<String, Boolean> userSessions = new HashMap<>();
|
||||
Map<String, Date> userLastRequest = new HashMap<>();
|
||||
Map<String, Integer> userActiveSessions = new HashMap<>();
|
||||
int activeUsers = 0;
|
||||
int disabledUsers = 0;
|
||||
int maxSessions = sessionPersistentRegistry.getMaxSessions();
|
||||
while (iterator.hasNext()) {
|
||||
User user = iterator.next();
|
||||
if (user != null) {
|
||||
@ -221,7 +224,7 @@ public class AccountWebController {
|
||||
// Determine the user's session status and last request time
|
||||
int maxInactiveInterval = sessionPersistentRegistry.getMaxInactiveInterval();
|
||||
boolean hasActiveSession = false;
|
||||
Date lastRequest = null;
|
||||
Date lastRequest;
|
||||
Optional<SessionEntity> latestSession =
|
||||
sessionPersistentRegistry.findLatestSession(user.getUsername());
|
||||
if (latestSession.isPresent()) {
|
||||
@ -251,6 +254,9 @@ public class AccountWebController {
|
||||
if (!user.isEnabled()) {
|
||||
disabledUsers++;
|
||||
}
|
||||
List<SessionInformation> sessionInformations =
|
||||
sessionPersistentRegistry.getAllSessions(user.getUsername(), false);
|
||||
userActiveSessions.put(user.getUsername(), sessionInformations.size());
|
||||
}
|
||||
}
|
||||
// Sort users by active status and last request date
|
||||
@ -316,9 +322,11 @@ public class AccountWebController {
|
||||
model.addAttribute("roleDetails", roleDetails);
|
||||
model.addAttribute("userSessions", userSessions);
|
||||
model.addAttribute("userLastRequest", userLastRequest);
|
||||
model.addAttribute("userActiveSessions", userActiveSessions);
|
||||
model.addAttribute("totalUsers", allUsers.size());
|
||||
model.addAttribute("activeUsers", activeUsers);
|
||||
model.addAttribute("disabledUsers", disabledUsers);
|
||||
model.addAttribute("maxSessions", maxSessions);
|
||||
return "addUsers";
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-9 bg-card">
|
||||
<div class="col-md-12 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">manage_accounts</span>
|
||||
<span class="tool-header-text" th:text="#{adminUserSettings.header}">Admin User Control Settings</span>
|
||||
@ -45,6 +45,7 @@
|
||||
<strong th:text="#{adminUserSettings.totalUsers}">Total Users:</strong> <span th:text="${totalUsers}"></span>
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.activeUsers}">Active Users:</strong> <span th:text="${activeUsers}"></span>
|
||||
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.disabledUsers}">Disabled Users:</strong> <span th:text="${disabledUsers}"></span>
|
||||
<strong th:if="${!@runningEE}" style="margin-left: 20px;" th:text="#{adminUserSettings.maxSessions}">Max Sessions</strong> <span th:text="${maxSessions}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div th:if="${addMessage}" class="p-3" style="background: var(--md-sys-color-outline-variant);border-radius: 2rem; text-align: center;">
|
||||
@ -69,6 +70,7 @@
|
||||
<th scope="col" th:title="#{adminUserSettings.roles}" th:text="#{adminUserSettings.roles}">Roles</th>
|
||||
<th scope="col" th:title="#{adminUserSettings.authenticated}" class="text-overflow" th:text="#{adminUserSettings.authenticated}">Authenticated</th>
|
||||
<th scope="col" th:title="#{adminUserSettings.lastRequest}" class="text-overflow" th:text="#{adminUserSettings.lastRequest}">Last Request</th>
|
||||
<th th:if="${!@runningEE}" scope="col" th:title="#{adminUserSettings.userSession}" th:text="#{adminUserSettings.userSessions}" colspan="1">Sessions</th>
|
||||
<th scope="col" th:title="#{adminUserSettings.actions}" th:text="#{adminUserSettings.actions}" colspan="2">Actions</th>
|
||||
<!-- <th scope="col"></th> -->
|
||||
</tr>
|
||||
@ -80,6 +82,7 @@
|
||||
<td style="align-content: center;" th:text="#{${user.roleName}}"></td>
|
||||
<td style="align-content: center;" th:text="${user.authenticationType}"></td>
|
||||
<td style="align-content: center;" th:text="${userLastRequest[user.username] != null ? #dates.format(userLastRequest[user.username], 'yyyy-MM-dd HH:mm:ss') : 'N/A'}"></td>
|
||||
<td th:if="${!@runningEE}" style="align-content: center;" th:text="${userActiveSessions[user.username] != null ? userActiveSessions[user.username] : 0}"></td>
|
||||
<td style="align-content: center;">
|
||||
<form th:if="${user.username != currentUsername}" th:action="@{'/api/v1/user/admin/deleteUser/' + ${user.username}}" method="post" onsubmit="return confirmDeleteUser()">
|
||||
<button type="submit" th:title="#{adminUserSettings.deleteUser}" class="btn btn-info btn-sm"><span class="material-symbols-rounded">person_remove</span></button>
|
||||
|
Loading…
x
Reference in New Issue
Block a user