package es.uv.saic.config; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy; import org.springframework.security.web.session.HttpSessionEventPublisher; import org.springframework.security.web.util.matcher.IpAddressMatcher; import es.uv.saic.service.AuthProvider; import jakarta.servlet.http.HttpServletRequest; @Configuration @EnableWebSecurity @EnableMethodSecurity public class SecurityConfig { @Autowired AuthProvider authProvider; @Value("${saic.actuator.validIp}") private String validIp; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((auth) -> auth .requestMatchers("/", "/css/**", "/js/**", "/img/**", "/logos/*", "/logos/**").permitAll() .requestMatchers("/login**").permitAll() .requestMatchers("/keepalive").permitAll() .requestMatchers("/public/**").permitAll() .requestMatchers("/actuator/**").access(hasIpAddress(this.validIp)) ) .authorizeHttpRequests((auth)-> auth //.anyRequest().fullyAuthenticated() .anyRequest().permitAll() ) .formLogin((form) -> form .loginPage("/login") .defaultSuccessUrl("/procedures?_new=1",true) .failureUrl("/login?error=noauth") .successHandler(new AuthSuccessHandler()) .permitAll() ) .logout((logout) -> logout .logoutSuccessUrl("/login") .invalidateHttpSession(true) .clearAuthentication(true) .deleteCookies("JSESSIONID") .deleteCookies("SESSION") ) .csrf((csrf) -> csrf.disable()); http.sessionManagement((session) -> session .sessionAuthenticationErrorUrl("/login?error=expired") .invalidSessionUrl("/login?error=expired") .maximumSessions(1) .expiredUrl("/login?error=expired") .maxSessionsPreventsLogin(false) .sessionRegistry(sessionRegistry()) ) .sessionManagement((session) -> session .sessionAuthenticationStrategy(concurrentSession()) .sessionFixation() .newSession() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) ); http.headers((headers) -> headers .frameOptions((options) -> options.sameOrigin()) ); return http.build(); } private static AuthorizationManager hasIpAddress(String ipAddress) { IpAddressMatcher ipAddressMatcher = new IpAddressMatcher(ipAddress); return (authentication, context) -> { HttpServletRequest request = context.getRequest(); return new AuthorizationDecision(ipAddressMatcher.matches(request)); }; } @Bean public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { return http.getSharedObject(AuthenticationManagerBuilder.class) .authenticationProvider(authProvider) .build(); } @Bean public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } @Bean public DefaultSpringSecurityContextSource contextSource() { return new DefaultSpringSecurityContextSource( Collections.singletonList("ldap://ldap.uv.es"), "dc=uv,dc=es"); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } @Bean public CompositeSessionAuthenticationStrategy concurrentSession() { ConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry()); concurrentAuthenticationStrategy.setMaximumSessions(1); concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(true); List delegateStrategies = new ArrayList(); delegateStrategies.add(concurrentAuthenticationStrategy); delegateStrategies.add(new SessionFixationProtectionStrategy()); delegateStrategies.add(new RegisterSessionAuthenticationStrategy(sessionRegistry())); CompositeSessionAuthenticationStrategy authenticationStrategy = new CompositeSessionAuthenticationStrategy(delegateStrategies); return authenticationStrategy; } }