From 625275124a9b6d4a18cebf2c52f60bb584b9eccd Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com.> Date: Sun, 18 Feb 2024 15:47:19 +0000 Subject: [PATCH] fix for #818 --- .../security/SecurityConfiguration.java | 16 ++++++++++++++ .../SPDF/controller/api/UserController.java | 21 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java index ca88dcb9..76d78aaf 100644 --- a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java @@ -9,6 +9,9 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.session.SessionRegistry; +import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -44,6 +47,11 @@ public class SecurityConfiguration { @Autowired private FirstLoginFilter firstLoginFilter; + @Bean + public SessionRegistry sessionRegistry() { + return new SessionRegistryImpl(); + } + @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); @@ -53,6 +61,14 @@ public class SecurityConfiguration { http.csrf(csrf -> csrf.disable()); http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class); + http.sessionManagement( + sessionManagement -> + sessionManagement + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) + .maximumSessions(3) + .maxSessionsPreventsLogin(true) + .sessionRegistry(sessionRegistry()) + .expiredUrl("/login?logout=true")); http.formLogin( formLogin -> formLogin diff --git a/src/main/java/stirling/software/SPDF/controller/api/UserController.java b/src/main/java/stirling/software/SPDF/controller/api/UserController.java index ce15d19c..c610759a 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/UserController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/UserController.java @@ -10,6 +10,9 @@ import org.springframework.http.HttpStatus; 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.session.SessionRegistry; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -228,11 +231,27 @@ public class UserController { if (currentUsername.equals(username)) { throw new IllegalArgumentException("Cannot delete currently logined in user."); } - + invalidateUserSessions(username); userService.deleteUser(username); return "redirect:/addUsers"; } + @Autowired private SessionRegistry sessionRegistry; + + private void invalidateUserSessions(String username) { + for (Object principal : sessionRegistry.getAllPrincipals()) { + if (principal instanceof UserDetails) { + UserDetails userDetails = (UserDetails) principal; + if (userDetails.getUsername().equals(username)) { + for (SessionInformation session : + sessionRegistry.getAllSessions(principal, false)) { + session.expireNow(); + } + } + } + } + } + @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PostMapping("/get-api-key") public ResponseEntity getApiKey(Principal principal) {