-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Description
Describe the bug
When ServerHttpSecurity.build() creates a SecurityWebFilterChain, it replaces the default entry point with the last delegating entry point in this.defaultEntryPoints.
Lines 1434 to 1445 in 3cba4ec
| private ServerAuthenticationEntryPoint getAuthenticationEntryPoint() { | |
| if (this.authenticationEntryPoint != null || this.defaultEntryPoints.isEmpty()) { | |
| return this.authenticationEntryPoint; | |
| } | |
| if (this.defaultEntryPoints.size() == 1) { | |
| return this.defaultEntryPoints.get(0).getEntryPoint(); | |
| } | |
| DelegatingServerAuthenticationEntryPoint result = new DelegatingServerAuthenticationEntryPoint( | |
| this.defaultEntryPoints); | |
| result.setDefaultEntryPoint(this.defaultEntryPoints.get(this.defaultEntryPoints.size() - 1).getEntryPoint()); | |
| return result; | |
| } |
Specifically:
result.setDefaultEntryPoint(this.defaultEntryPoints.get(this.defaultEntryPoints.size() - 1).getEntryPoint());Since delegating entry points should be applied conditionally, this breaks the contract for certain default entry points, such as OAuth2LoginSpec.setDefaultEntryponits, which are designed to be conditional. For example, the OAuth2LoginSpec is designed to not redirect on XHR requests but this behavior breaks that contract.
This cannot be worked around by configuring a new default entry point (e.g., .exceptionHandling().authenticationEntryPoint(...)) because doing so triggers another bug, which I'll open another issue about.
To Reproduce
The issue is reproducible most easily with OAuth2 login. However, the problem is not unique to this scenario.
- Configure Spring WebFlux security with OAuth2 login
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig
{
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http)
{
return http
.authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
.oauth2Login()
.and()
.build();
}
}- Make an XHR request to an endpoint requiring authentication with XHR headers expecting an HTTP 401.
@Test
void respondsWithHttp401()
{
client
.get()
.accept(MediaType.APPLICATION_JSON)
.header("X-Requested-With","XMLHttpRequest")
.exchange()
.expectStatus()
.isUnauthorized();
}-
Note a 302 redirect to the login provider is sent as the response instead of a 401.
[ERROR] Failures:
[ERROR] DemoApplicationTests.respondsWithHttp401:36 Status expected:<401 UNAUTHORIZED> but was:<302 FOUND>
Expected behavior
The web filter chain should return an HTTP 401, not redirect.
Sample
GitHub repository with minimal, reproducible sample.
Two ways to reproduce with sample:
- Run the test suite
- Start the server and cURL any endpoint