package com.gcc_manpower.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; 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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder() { return new PasswordEncoder() { private final BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder(); @Override public String encode(CharSequence rawPassword) { return bcrypt.encode(rawPassword); } @Override public boolean matches(CharSequence rawPassword, String dbPassword) { if (dbPassword != null && dbPassword.startsWith("$2a$")) { return bcrypt.matches(rawPassword, dbPassword); } return rawPassword.toString().equals(dbPassword); } }; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // Configure headers for clickjacking and XSS protection .headers(headers -> headers .frameOptions(frame -> frame.sameOrigin()) .xssProtection( xss -> xss.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))) // Configure URL authorization .authorizeHttpRequests(auth -> auth // Allow static resources .requestMatchers( "/assets/**", "/css/**", "/js/**", "/images/**", "/favicon.ico", "/error") .permitAll() // Allow login pages and login API endpoints .requestMatchers( "/login", "/api/val-app-usr-login", "/gcctonermanagement/login", "/gcctonermanagement/api/login", "/gccservicepaymenttracker/login", "/gccservicepaymenttracker/api/login", "/gccservicedocuments/login", "/gccservicedocuments/api/login", "/gccadjustmentmanagement/login", "/gccadjustmentmanagement/api/login", "/gcctapaldetailsmanagement/login", "/gcctapaldetailsmanagement/api/login", "/gccrentalmanagement/login", "/gccrentalmanagement/api/login") .permitAll() // Allow logout endpoints .requestMatchers( "/usr-logout", "/gcctonermanagement/logout", "/gccservicepaymenttracker/logout", "/gccservicedocuments/logout", "/gccadjustmentmanagement/logout", "/gcctapaldetailsmanagement/logout", "/gccrentalmanagement/logout") .permitAll() // Require authentication for all other requests .anyRequest().authenticated()) // Configure CSRF protection (ignore CSRF on the login endpoints only) .csrf(csrf -> csrf .ignoringRequestMatchers( "/api/val-app-usr-login", "/gcctonermanagement/api/login", "/gccservicepaymenttracker/api/login", "/gccservicedocuments/api/login", "/gccadjustmentmanagement/api/login", "/gcctapaldetailsmanagement/api/login", "/gccrentalmanagement/api/login")) // Session management configuration with module-aware invalid session // redirection .sessionManagement(session -> session .invalidSessionStrategy((request, response) -> { // Create a fresh session so requestedSessionIdValid won't cause endless loop request.getSession(true); String requestURI = request.getRequestURI(); if (requestURI.contains("/gccservicepaymenttracker")) { response.sendRedirect(request.getContextPath() + "/gccservicepaymenttracker/login"); } else if (requestURI.contains("/gcctonermanagement")) { response.sendRedirect(request.getContextPath() + "/gcctonermanagement/login"); } else if (requestURI.contains("/gccservicedocuments")) { response.sendRedirect(request.getContextPath() + "/gccservicedocuments/login"); } else if (requestURI.contains("/gccadjustmentmanagement")) { response.sendRedirect(request.getContextPath() + "/gccadjustmentmanagement/login"); } else if (requestURI.contains("/gcctapaldetailsmanagement")) { response.sendRedirect(request.getContextPath() + "/gcctapaldetailsmanagement/login"); } else if (requestURI.contains("/gccrentalmanagement")) { response.sendRedirect(request.getContextPath() + "/gccrentalmanagement/login"); } else { response.sendRedirect(request.getContextPath() + "/login"); } })) // Exception handling for unauthenticated requests with module-aware redirection .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint((request, response, authException) -> { String requestURI = request.getRequestURI(); if (requestURI.contains("/gccservicepaymenttracker")) { response.sendRedirect(request.getContextPath() + "/gccservicepaymenttracker/login"); } else if (requestURI.contains("/gcctonermanagement")) { response.sendRedirect(request.getContextPath() + "/gcctonermanagement/login"); } else if (requestURI.contains("/gccservicedocuments")) { response.sendRedirect(request.getContextPath() + "/gccservicedocuments/login"); } else if (requestURI.contains("/gccadjustmentmanagement")) { response.sendRedirect(request.getContextPath() + "/gccadjustmentmanagement/login"); } else if (requestURI.contains("/gcctapaldetailsmanagement")) { response.sendRedirect(request.getContextPath() + "/gcctapaldetailsmanagement/login"); } else if (requestURI.contains("/gccrentalmanagement")) { response.sendRedirect(request.getContextPath() + "/gccrentalmanagement/login"); } else { response.sendRedirect(request.getContextPath() + "/login"); } })); return http.build(); } }