11package com .xpeho .spring_boot_java_random_user .config ;
22
3+ import jakarta .servlet .http .HttpServletRequest ;
34import org .springframework .context .annotation .Bean ;
45import org .springframework .context .annotation .Configuration ;
56import org .springframework .beans .factory .annotation .Value ;
7+ import org .springframework .http .HttpHeaders ;
68import org .springframework .http .HttpMethod ;
79import org .springframework .security .core .userdetails .User ;
810import org .springframework .security .core .userdetails .UserDetails ;
1315import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
1416import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
1517import org .springframework .security .config .http .SessionCreationPolicy ;
18+ import org .springframework .security .config .annotation .web .configurers .AbstractHttpConfigurer ;
1619import org .springframework .security .provisioning .InMemoryUserDetailsManager ;
1720import org .springframework .security .web .SecurityFilterChain ;
21+ import org .springframework .security .web .context .NullSecurityContextRepository ;
1822
1923@ Configuration
2024@ EnableWebSecurity
2125public class SecurityConfig {
2226
27+ // Constants for security configuration
28+ private static final String RANDOM_USERS_PATH = "/random-users/**" ;
29+ private static final String RANDOM_USERS_PREFIX = "/random-users" ;
30+ private static final String ADMIN_ROLE = "ADMIN" ;
31+
2332 @ Value ("${app.security.admin.username}" )
2433 private String adminUsername ;
2534
@@ -39,35 +48,56 @@ public class SecurityConfig {
3948 private String testPassword ;
4049
4150 @ Bean
42- SecurityFilterChain securityFilterChain (HttpSecurity http ) throws Exception {
43- http
44- .csrf (csrf -> csrf .ignoringRequestMatchers ("/random-users/**" ))
45- .sessionManagement (session -> session .sessionCreationPolicy (SessionCreationPolicy .STATELESS ))
46- .httpBasic (Customizer .withDefaults ())
47- .authorizeHttpRequests (auth -> auth
48- .requestMatchers (
49- "/api/**" ,
50- "/swagger-ui/**" ,
51- "/swagger-ui.html" ,
52- "/v3/api-docs/**" ,
53- "/actuator/health"
54- ).permitAll ()
55- .requestMatchers (HttpMethod .OPTIONS , "/**" ).permitAll ()
56- .requestMatchers (HttpMethod .GET , "/random-users/**" ).hasAnyRole ("ADMIN" , "USER" , "TEST" )
57- .requestMatchers (HttpMethod .POST , "/random-users/**" ).hasRole ("ADMIN" )
58- .requestMatchers (HttpMethod .PUT , "/random-users/**" ).hasRole ("ADMIN" )
59- .requestMatchers (HttpMethod .DELETE , "/random-users/**" ).hasRole ("ADMIN" )
60- .anyRequest ().authenticated ()
61- );
62-
63- return http .build ();
51+ public SecurityFilterChain securityFilterChain (HttpSecurity http ) {
52+ try {
53+ return http
54+ .csrf (csrf -> csrf .ignoringRequestMatchers (this ::isBasicAuthOnRandomUsers ))
55+ .securityContext (context -> context .securityContextRepository (new NullSecurityContextRepository ()))
56+ .sessionManagement (session -> session .sessionCreationPolicy (SessionCreationPolicy .STATELESS ))
57+ .requestCache (AbstractHttpConfigurer ::disable )
58+ .formLogin (AbstractHttpConfigurer ::disable )
59+ .logout (AbstractHttpConfigurer ::disable )
60+ .httpBasic (Customizer .withDefaults ())
61+ .authorizeHttpRequests (auth -> auth
62+ .requestMatchers (getPublicEndpoints ()).permitAll ()
63+ .requestMatchers (HttpMethod .OPTIONS , "/**" ).permitAll ()
64+ .requestMatchers (HttpMethod .GET , RANDOM_USERS_PATH ).hasAnyRole (ADMIN_ROLE , "USER" , "TEST" )
65+ .requestMatchers (HttpMethod .POST , RANDOM_USERS_PATH ).hasRole (ADMIN_ROLE )
66+ .requestMatchers (HttpMethod .PUT , RANDOM_USERS_PATH ).hasRole (ADMIN_ROLE )
67+ .requestMatchers (HttpMethod .DELETE , RANDOM_USERS_PATH ).hasRole (ADMIN_ROLE )
68+ .anyRequest ().authenticated ()
69+ )
70+ .build ();
71+ } catch (Exception e ) {
72+ throw new SecurityConfigurationException ("Failed to build Spring Security filter chain" , e );
73+ }
74+ }
75+
76+
77+ private boolean isBasicAuthOnRandomUsers (HttpServletRequest request ) {
78+ String authHeader = request .getHeader (HttpHeaders .AUTHORIZATION );
79+ boolean isBasicAuth = authHeader != null && authHeader .startsWith ("Basic " );
80+ String servletPath = request .getServletPath ();
81+ boolean isRandomUsersPath = servletPath != null && servletPath .startsWith (RANDOM_USERS_PREFIX );
82+ return isRandomUsersPath && isBasicAuth ;
83+ }
84+
85+ private String [] getPublicEndpoints () {
86+ return new String []{
87+ "/api/**" ,
88+ "/swagger-ui/**" ,
89+ "/swagger-ui.html" ,
90+ "/v3/api-docs/**" ,
91+ "/actuator/health"
92+ };
6493 }
6594
95+ // UserDetailsService bean to define in-memory users with roles and encoded passwords
6696 @ Bean
6797 UserDetailsService userDetailsService (PasswordEncoder passwordEncoder ) {
6898 UserDetails admin = User .withUsername (adminUsername )
6999 .password (passwordEncoder .encode (adminPassword ))
70- .roles ("ADMIN" )
100+ .roles (ADMIN_ROLE )
71101 .build ();
72102
73103 UserDetails user = User .withUsername (userUsername )
0 commit comments