Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handle sessions #6047

Merged
merged 4 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Kitodo/src/main/java/org/kitodo/production/helper/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -550,4 +550,23 @@ public static String generateRandomString(int length) {
}
return sb.toString();
}

/**
* Returns an object description for error messages. It consists of the
* class name and optionally the {@code toString()}, if {@code toString()}
* is overloaded.
*
* @param object
* object to be described
* @return object description
*/
public static String getObjectDescription(Object object) {
if (Objects.isNull(object)) {
return "null";
}
String fullClassName = object.getClass().getName();
String objectToString = object.toString();
return objectToString.startsWith(fullClassName.concat("@")) ? fullClassName
: fullClassName + '(' + objectToString + ')';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
package org.kitodo.production.security;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.production.helper.Helper;
import org.kitodo.production.services.ServiceManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -31,6 +35,7 @@
*/
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {

private static final Logger logger = LogManager.getLogger(CustomLogoutSuccessHandler.class);
private final String onSuccessUrl;
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

Expand All @@ -41,12 +46,21 @@ public CustomLogoutSuccessHandler(String onSuccessUrl) {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
if (Objects.nonNull(authentication) && Objects.nonNull(authentication.getDetails())) {
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
UserDetails user = (UserDetails) principal;
ServiceManager.getSessionService().expireSessionsOfUser(user);
if (Objects.nonNull(authentication)) {
if (Objects.nonNull(authentication.getDetails())) {
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
UserDetails user = (UserDetails) principal;
ServiceManager.getSessionService().expireSessionsOfUser(user);
} else {
logger.warn(MessageFormat.format("Cannot expire session: {0} is not an instance of UserDetails",
Helper.getObjectDescription(principal)));
}
} else {
logger.warn("Cannot expire session: authentication.getDetails() is null");
}
} else {
logger.warn("Cannot expire session: authentication is null");
}
redirectStrategy.sendRedirect(request, response, onSuccessUrl);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,30 @@

package org.kitodo.production.services.security;

import java.text.MessageFormat;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.production.helper.Helper;
import org.kitodo.production.metadata.MetadataLock;
import org.kitodo.production.security.SecurityConfig;
import org.kitodo.production.security.SecuritySession;
import org.kitodo.production.security.SecurityUserDetails;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetails;

public class SessionService {
public class SessionService implements HttpSessionListener {

private static final Logger logger = LogManager.getLogger(SessionService.class);
private static volatile SessionService instance = null;
private final SessionRegistry sessionRegistry;

Expand All @@ -37,6 +46,27 @@ private SessionService() {
this.sessionRegistry = securityConfig.getSessionRegistry();
}

/*
* This function is called when the session from the servlet container expires.
*/
@Override
public void sessionDestroyed(HttpSessionEvent se) {
Object securityContextObject = se.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
if (securityContextObject instanceof SecurityContextImpl) {
SecurityContextImpl securityContext = (SecurityContextImpl) securityContextObject;
Object principal = securityContext.getAuthentication().getPrincipal();
if (principal instanceof SecurityUserDetails) {
expireSessionsOfUser((SecurityUserDetails) principal);
} else {
logger.warn(MessageFormat.format("Cannot expire session: {0} is not an instance of SecurityUserDetails",
Helper.getObjectDescription(principal)));
}
} else {
logger.warn(MessageFormat.format("Cannot expire session: {0} is not an instance of SecurityContextImpl",
Helper.getObjectDescription(securityContextObject)));
}
}

/**
* Expires all active sessions of a spring security UserDetails object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,13 @@
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.kitodo.production.security.SecurityUserDetails;
import org.kitodo.production.services.ServiceManager;
import org.springframework.security.core.context.SecurityContextImpl;

/**
* Listener to set up Kitodo versioning information from Manifest on application
* startup.
*/
@WebListener
public class KitodoVersionListener implements ServletContextListener, HttpSessionListener {
public class KitodoVersionListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
Expand All @@ -56,21 +48,4 @@ public void contextInitialized(ServletContextEvent sce) {
public void contextDestroyed(ServletContextEvent sce) {
// nothing is done here
}

@Override
public void sessionCreated(HttpSessionEvent se) {
// nothing is done here
}

@Override
public void sessionDestroyed(HttpSessionEvent se) {
Object securityContextObject = se.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
if (securityContextObject instanceof SecurityContextImpl) {
SecurityContextImpl securityContext = (SecurityContextImpl) securityContextObject;
Object principal = securityContext.getAuthentication().getPrincipal();
if (principal instanceof SecurityUserDetails) {
ServiceManager.getSessionService().expireSessionsOfUser((SecurityUserDetails) principal);
}
}
}
}