Skip to content

Commit 2eb2028

Browse files
Theo-lbgCopilot
andcommitted
feat(security): enhance security filter chain and add custom exception handling
Co-authored-by: Copilot <copilot@github.com>
1 parent 3ca0012 commit 2eb2028

2 files changed

Lines changed: 61 additions & 23 deletions

File tree

src/main/java/com/xpeho/spring_boot_java_random_user/config/SecurityConfig.java

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.xpeho.spring_boot_java_random_user.config;
22

3+
import jakarta.servlet.http.HttpServletRequest;
34
import org.springframework.context.annotation.Bean;
45
import org.springframework.context.annotation.Configuration;
56
import org.springframework.beans.factory.annotation.Value;
7+
import org.springframework.http.HttpHeaders;
68
import org.springframework.http.HttpMethod;
79
import org.springframework.security.core.userdetails.User;
810
import org.springframework.security.core.userdetails.UserDetails;
@@ -13,13 +15,20 @@
1315
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
1416
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
1517
import org.springframework.security.config.http.SessionCreationPolicy;
18+
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
1619
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
1720
import org.springframework.security.web.SecurityFilterChain;
21+
import org.springframework.security.web.context.NullSecurityContextRepository;
1822

1923
@Configuration
2024
@EnableWebSecurity
2125
public 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)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.xpeho.spring_boot_java_random_user.config;
2+
3+
public class SecurityConfigurationException extends RuntimeException {
4+
5+
public SecurityConfigurationException(String message, Throwable cause) {
6+
super(message, cause);
7+
}
8+
}

0 commit comments

Comments
 (0)