package com.dh7789dev.xpeditis.configuration; 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.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; @Configuration @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) public class SecurityConfiguration { @Value("${application.csrf.enabled}") boolean csrfEnabled; private static final String ADMIN_ROLE = "ADMIN"; private static final String ADMIN_PLATFORM_ROLE = "ADMIN_PLATFORM"; private static final String API_V1_URI = "/api/v1/**"; private static final String[] WHITE_LIST_URL = { "/api/v1/auth/**", "/api/v1/devis/**", "/api/v1/grilles-tarifaires/**", "/actuator/health/**"}; private static final String[] ADMIN_ONLY_URL = { "/api/v1/users"}; private static final String[] GENERAL_API_URL = { "/api/v1/quotes/**", "/api/v1/shipments/**", "/api/v1/companies/profile"}; private static final String[] INTERNAL_WHITE_LIST_URL = { "/v2/api-docs", "/v3/api-docs", "/v3/api-docs/**", "/swagger-resources", "/swagger-resources/**", "/configuration/ui", "/configuration/security", "/swagger-ui/**", "/webjars/**", "/swagger-ui.html", "/addevent"}; private static final WebExpressionAuthorizationManager INTERNAL_ACCESS = new WebExpressionAuthorizationManager("hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')"); private final UserDetailsService userDetailsService; private final LogoutHandler logoutHandler; @Autowired public SecurityConfiguration(UserDetailsService userDetailsService, LogoutHandler logoutHandler) { this.userDetailsService = userDetailsService; this.logoutHandler = logoutHandler; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { return configuration.getAuthenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } @Bean public AuthenticationProvider authenticationProvider() { final DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setPasswordEncoder(passwordEncoder()); provider.setUserDetailsService(userDetailsService); return provider; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthFilter) throws Exception { if (csrfEnabled) { http.csrf(csrf -> csrf.ignoringRequestMatchers(antMatcher("/h2-console/**"))); } else { // csrf is disabled for dev and test http.csrf(AbstractHttpConfigurer::disable); } http.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)); http.authorizeHttpRequests(auth -> auth.requestMatchers(WHITE_LIST_URL).permitAll() .requestMatchers(antMatcher(HttpMethod.GET, "/")).permitAll() .requestMatchers("/api/v1/users/**").authenticated() .requestMatchers("/api/v1/profile/**").authenticated() .requestMatchers(GENERAL_API_URL).authenticated() .requestMatchers(antMatcher("/h2-console/**")).access(INTERNAL_ACCESS) .requestMatchers(antMatcher("/actuator/**")).access(INTERNAL_ACCESS) .requestMatchers(INTERNAL_WHITE_LIST_URL).access(INTERNAL_ACCESS) .anyRequest().authenticated() ) .sessionManagement(session -> session.sessionCreationPolicy(STATELESS)) .authenticationProvider(authenticationProvider()) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) .logout(logout -> logout .logoutUrl("/api/v1/auth/logout") .addLogoutHandler(logoutHandler) .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext())); return http.build(); } }