Filter chaineasy0-2 years
A security config has `requestMatchers("/api/**").authenticated()` followed by `requestMatchers("/api/admin/**").hasRole("ADMIN")`, and any signed-in user can call the admin endpoints. After reordering, admins get 403 too — their user records grant the authority `ADMIN`. What are the two bugs?
First: URL rules are evaluated in the order written, and the first match wins. /api/admin/users matches /api/** first, so the rule that applies is 'any authenticated user', and the admin rule below it is never reached. Specific patterns go first; the broad one, and finally anyRequest(), go last. Second: hasRole("ADMIN") checks for the authority ROLE_ADMIN; it adds the ROLE_ prefix for you. The users were granted ADMIN with no prefix, so the rule compares ROLE_ADMIN against ADMIN and never matches. Either grant roles as roles (roles("ADMIN") produces ROLE_ADMIN) or check the authority as it actually is (hasAuthority("ADMIN")).
PreviousA controller checks `if (SecurityContextHolder.getContext().getAuthentication() != null)` to decide whether the caller is logged in, and it is always true — even with no credentials. Separately, the same endpoint returns 401 to one caller and 403 to another. Which filters explain both observations?Next A code review flags `csrf(csrf -> csrf.disable())` in two services. One is a stateless JSON API that authenticates with a bearer token in the `Authorization` header; the other is a server-rendered app that logs users in with a session cookie. Is the flag right for both, one, or neither?
A controller checks `if (SecurityContextHolder.getContext().getAuthentication() != null)` to decide whether the caller is logged in, and it is always true — even with no credentials. Separately, the same endpoint returns 401 to one caller and 403 to another. Which filters explain both observations?A service method guarded by `@PreAuthorize` used to return 403 to unauthorised callers and 401 to anonymous ones. After someone added a `@RestControllerAdvice` with `@ExceptionHandler(Exception.class)` that returns a generic 500 body, those calls now return 500. The exception is thrown long after the security filters have "run". How did it ever become a 403, and what changed?