I wish to allow all users to login via JWT. Only logged in users are allowed to access the private endpoints. Nothing is being logged, not even as "Access Denied". Here is my SecurityConfig
configuration class.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests()
.requestMatchers(publicEndpoints()).permitAll()
.requestMatchers(userEndpoints()).permitAll()
.requestMatchers(adminEndpoints()).hasRole("ADMIN")
.anyRequest().denyAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.accessDeniedHandler((request, response, ex) -> {
System.out.println("Access Denied: " + ex.getMessage());
response.sendError(HttpServletResponse.SC_FORBIDDEN);
});
return http.build();
}
private RequestMatcher userEndpoints() {
return new OrRequestMatcher(
new AntPathRequestMatcher("/u/**")
);
}
private RequestMatcher adminEndpoints() {
return new OrRequestMatcher(
new AntPathRequestMatcher("/admin/**")
);
}
private RequestMatcher publicEndpoints() {
return new OrRequestMatcher(
new AntPathRequestMatcher("/user/register"),
new AntPathRequestMatcher("/user/signin")
);
}
}
Here is the JwtAuthenticationFilter:
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
if(authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
final String jwtToken = authHeader.substring(7); // removes "Bearer " string.
final String username = jwtService.extractUsername(jwtToken);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource()
.buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
Currently, with the above configuration, I am getting no logs whatsoever. I tried changing the security configuration to .requestMatchers(userEndpoints()).hasRole("USER")
which still returned 403 Forbidden. But this time, there was a log saying "Access Denied: Access Denied".
I have also tried using @PreAuthorize("hasRole('USER')")
for the controller method being called, but that also did nothing.
In the SecurityConfig class, inside the securityFilterChain method, you are using the "denyAll()" method. With it, you are saying that all the aforementioned requests should be denied. Change the "denyAll()" to "authenticated()".
The method would be as follows:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests()
.requestMatchers(publicEndpoints()).permitAll()
.requestMatchers(userEndpoints()).permitAll()
.requestMatchers(adminEndpoints()).hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.accessDeniedHandler((request, response, ex) -> {
System.out.println("Access Denied: " + ex.getMessage());
response.sendError(HttpServletResponse.SC_FORBIDDEN);
});
return http.build();
}