Tested with spring-boot-3.4.0
For endpoints that are configured for anonymous access, even if a Basic Authentication header is sent, the access is still granted. In reality.
But in unit tests, those fail with a 401 Unauthorized. I want to test this case exactly, because it may happen that a client-user tries to access the anonymous endpoint, but forgets to remove their basic authentication credentials for whatever reason. The endpoint should still be accessible, which it is in reality using curl or similar. But tests fail.
It seems that TestRestTemplate.withBasicAuth() causes some internal test security validation to intercept and reject the call.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoServletTest {
@Autowired
private TestRestTemplate testRestTemplate;
//this test fails, but would work in a live application
@Test
public void testAnonymousAccess() {
ResponseEntity<String> rsp = testRestTemplate.withBasicAuth("u", "p").getForEntity("/anonymous/files", String.class);
assertEquals(HttpStatus.OK, rsp.getStatusCode()); //NOK
}
}
@RestController
public class DemoServlet {
@GetMapping("/restricted")
public String restricted() {
return "restricted files";
}
@GetMapping("/anonymous/files")
public String free() {
return "anonymous files";
}
}
@Configuration
public class SecurityConfiguration {
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password("{noop}password") // {noop} disables password encoding
.build()
);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.securityMatcher("/restricted", "/anonymous/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/restricted").authenticated()
.requestMatchers("/anonymous/**").permitAll())
.httpBasic(Customizer.withDefaults())
.build();
}
}
Comment From: mdeinum
This is what I would expect, as you are passing invalid credentials. Authentication happens before anything else and fails because the username/password combination isn't valid. Testing curl/httpie results in the exact same result (using invalid credentials leads to a 401).
A common misconception is that permitAll means don't do any checks and allow all access but this isn't the case. If headers are detected (in case of BASIC AUTH) the authentication still proceeds.
Comment From: mhalbritter
For endpoints that are configured for anonymous access, even if a Basic Authentication header is sent, the access is still granted. In reality.
This isn't true. Using your application, if i execute a request with basic auth, i get a 401:
> curl -u k:x http://localhost:8080/anonymous/files
{"timestamp":"2024-12-10T07:45:06.155+00:00","status":401,"error":"Unauthorized","path":"/anonymous/files"}
If I remove the basic auth, I get a 200:
curl http://localhost:8080/anonymous/files
anonymous files
So the test behaves as your application does. If you don't like that behavior, you have to open an issue on the Spring Security issue tracker.