222 lines
7.7 KiB
Java
222 lines
7.7 KiB
Java
/**
|
|
* Security Configuration
|
|
*
|
|
* Spring Security configuration for JWT-based authentication.
|
|
*
|
|
* @author David Valera Melendez <david@valera-melendez.de>
|
|
* @since February 2025
|
|
*/
|
|
package com.company.auth.config;
|
|
|
|
import com.company.auth.security.JwtAuthenticationEntryPoint;
|
|
import com.company.auth.security.JwtAuthenticationFilter;
|
|
import com.company.auth.service.UserService;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Configuration;
|
|
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.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.annotation.web.configurers.AbstractHttpConfigurer;
|
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
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.authentication.UsernamePasswordAuthenticationFilter;
|
|
import org.springframework.web.cors.CorsConfiguration;
|
|
import org.springframework.web.cors.CorsConfigurationSource;
|
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Security Configuration
|
|
*
|
|
* Configures Spring Security for:
|
|
* - JWT-based authentication
|
|
* - Stateless session management
|
|
* - CORS configuration
|
|
* - Security filters and providers
|
|
*/
|
|
@Configuration
|
|
@EnableWebSecurity
|
|
@EnableMethodSecurity(prePostEnabled = true)
|
|
public class SecurityConfig {
|
|
|
|
@Autowired
|
|
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
|
|
|
|
@Autowired
|
|
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
|
|
|
@Autowired
|
|
private UserService userService;
|
|
|
|
@Autowired
|
|
private PasswordEncoder passwordEncoder;
|
|
|
|
/**
|
|
* Authentication provider bean
|
|
*
|
|
* @return DAO authentication provider
|
|
*/
|
|
@Bean
|
|
public AuthenticationProvider authenticationProvider() {
|
|
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
|
authProvider.setUserDetailsService(userService);
|
|
authProvider.setPasswordEncoder(passwordEncoder);
|
|
return authProvider;
|
|
}
|
|
|
|
/**
|
|
* Authentication manager bean
|
|
*
|
|
* @param config Authentication configuration
|
|
* @return Authentication manager
|
|
* @throws Exception if configuration fails
|
|
*/
|
|
@Bean
|
|
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
|
return config.getAuthenticationManager();
|
|
}
|
|
|
|
/**
|
|
* CORS configuration source
|
|
*
|
|
* @return CORS configuration source
|
|
*/
|
|
@Bean
|
|
public CorsConfigurationSource corsConfigurationSource() {
|
|
CorsConfiguration configuration = new CorsConfiguration();
|
|
|
|
// Allow specific origins in production, * for development
|
|
configuration.setAllowedOriginPatterns(Arrays.asList(
|
|
"http://localhost:3000", // React development
|
|
"http://localhost:4200", // Angular development
|
|
"http://localhost:8080", // Local backend
|
|
"https://*.company.com", // Production domains
|
|
"https://company.com"
|
|
));
|
|
|
|
configuration.setAllowedMethods(Arrays.asList(
|
|
"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"
|
|
));
|
|
|
|
configuration.setAllowedHeaders(Arrays.asList(
|
|
"Authorization",
|
|
"Content-Type",
|
|
"X-Requested-With",
|
|
"Accept",
|
|
"Origin",
|
|
"Access-Control-Request-Method",
|
|
"Access-Control-Request-Headers",
|
|
// Custom headers for device fingerprinting
|
|
"User-Agent",
|
|
"Accept-Language",
|
|
"Timezone",
|
|
"Screen-Resolution",
|
|
"Color-Depth",
|
|
"Hardware-Concurrency",
|
|
"Device-Memory",
|
|
"Platform",
|
|
"Cookie-Enabled",
|
|
"DNT",
|
|
"Webdriver",
|
|
"Device-Fingerprint"
|
|
));
|
|
|
|
configuration.setExposedHeaders(Arrays.asList(
|
|
"Authorization",
|
|
"Content-Disposition"
|
|
));
|
|
|
|
configuration.setAllowCredentials(true);
|
|
configuration.setMaxAge(3600L); // 1 hour preflight cache
|
|
|
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
source.registerCorsConfiguration("/**", configuration);
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Security filter chain configuration
|
|
*
|
|
* @param http HTTP security configuration
|
|
* @return Security filter chain
|
|
* @throws Exception if configuration fails
|
|
*/
|
|
@Bean
|
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
http
|
|
// Disable CSRF for stateless REST APIs
|
|
.csrf(AbstractHttpConfigurer::disable)
|
|
|
|
// Configure CORS
|
|
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
|
|
|
// Configure authorization rules
|
|
.authorizeHttpRequests(authz -> authz
|
|
// Public endpoints
|
|
.requestMatchers(
|
|
"/api/auth/register",
|
|
"/api/auth/login",
|
|
"/api/auth/verify-device",
|
|
"/api/auth/verify-2fa",
|
|
"/api/auth/refresh",
|
|
"/api/auth/resend-device-verification",
|
|
"/api/auth/resend-2fa"
|
|
).permitAll()
|
|
|
|
// Health check and monitoring endpoints
|
|
.requestMatchers(
|
|
"/actuator/health",
|
|
"/actuator/health/**",
|
|
"/actuator/info"
|
|
).permitAll()
|
|
|
|
// API documentation endpoints
|
|
.requestMatchers(
|
|
"/v3/api-docs/**",
|
|
"/swagger-ui/**",
|
|
"/swagger-ui.html",
|
|
"/swagger-resources/**",
|
|
"/webjars/**"
|
|
).permitAll()
|
|
|
|
// Static resources
|
|
.requestMatchers(
|
|
"/favicon.ico",
|
|
"/error"
|
|
).permitAll()
|
|
|
|
// All other endpoints require authentication
|
|
.anyRequest().authenticated()
|
|
)
|
|
|
|
// Configure exception handling
|
|
.exceptionHandling(ex -> ex
|
|
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
|
|
)
|
|
|
|
// Configure session management (stateless)
|
|
.sessionManagement(session -> session
|
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
)
|
|
|
|
// Configure authentication provider
|
|
.authenticationProvider(authenticationProvider())
|
|
|
|
// Add JWT authentication filter
|
|
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
|
|
|
return http.build();
|
|
}
|
|
}
|