As the title says, When I try to access the page with wrong authority (with valid JWT token), I get 401 instead of 403.
Here is SecurityFilterChain
implementation:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http.csrf(csrf -> csrf.disable());
http.authorizeHttpRequests(
auth -> auth
.requestMatchers("/category/**").hasAnyAuthority("READ")
.requestMatchers("/user/login").authenticated()
// .anyRequest().authenticated()
);
// http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.sessionManagement(session -> {
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
});
http.addFilterAfter(new JWTTokenGeneratorFilter(), BasicAuthenticationFilter.class);
http.addFilterBefore(new JWTTokenValidatorFilter(), BasicAuthenticationFilter.class);
return http.build();
}
here is the JWTTokenGeneratorFilter
and JWTTokenValidatorFilter
:
JWTTokenGeneratorFilter
public class JWTTokenGeneratorFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(null != authentication){
SecretKey secretKey = Keys.hmacShaKeyFor(JwtUtil.getRawSecretKey().getBytes(StandardCharsets.UTF_8));
String jwt = Jwts.builder().setIssuer("psquared").setSubject(authentication.getName())
.claim("username", authentication.getName())
.claim("authorities", authentication.getAuthorities().stream().map(a -> a.getAuthority()).toArray(String[]::new))
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(secretKey).compact();
response.setHeader("Authorization", jwt);
}
filterChain.doFilter(request, response);
}
/**
* this will execute whenever
* the condition evaluates to false
*/
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return !request.getServletPath().equals("/user/login");
}
}
JWTTokenValidatorFilter
public class JWTTokenValidatorFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String jwt = request.getHeader("Authorization");
if (null != jwt) {
try {
SecretKey key = Keys.hmacShaKeyFor(
JwtUtil.getRawSecretKey().getBytes(StandardCharsets.UTF_8));
jwt = jwt.replace("Bearer ", "");
Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(jwt)
.getBody();
String username = String.valueOf(claims.get("username"));
List<String> authoritiesList = claims.get("authorities", ArrayList.class);
String authorities = String.join(",", authoritiesList);
Authentication auth = new UsernamePasswordAuthenticationToken(username, null,
AuthorityUtils.commaSeparatedStringToAuthorityList(authorities));
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (Exception e) {
throw new BadCredentialsException("Invalid Token received!");
}
}
filterChain.doFilter(request, response);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return request.getServletPath().equals("/user/login");
}
}
Login URL is /user/login
. Now, when I try to access /category/12
with a user with valid JWT token which doesn’t have authority of READ
. I get 401, instead of 403.
What’s the cause of the error?