init commit
This commit is contained in:
221
src/main/java/com/company/auth/config/SecurityConfig.java
Normal file
221
src/main/java/com/company/auth/config/SecurityConfig.java
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user