Skip to content

Commit c729fee

Browse files
committed
Malformed Bearer Token Returns 401 for WebFlux
Fixes gh-7668
1 parent 80ee662 commit c729fee

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.springframework.security.authorization.ReactiveAuthorizationManager;
5353
import org.springframework.security.config.Customizer;
5454
import org.springframework.security.core.Authentication;
55+
import org.springframework.security.core.AuthenticationException;
5556
import org.springframework.security.core.GrantedAuthority;
5657
import org.springframework.security.core.authority.AuthorityUtils;
5758
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
@@ -102,6 +103,7 @@
102103
import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
103104
import org.springframework.security.web.server.SecurityWebFilterChain;
104105
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
106+
import org.springframework.security.web.server.WebFilterExchange;
105107
import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilter;
106108
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
107109
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
@@ -1788,6 +1790,28 @@ private Mono<MatchResult> nullAuthentication(Authentication authentication) {
17881790
}
17891791
}
17901792

1793+
private class BearerTokenAuthenticationWebFilter extends AuthenticationWebFilter {
1794+
private ServerAuthenticationFailureHandler authenticationFailureHandler;
1795+
1796+
BearerTokenAuthenticationWebFilter(ReactiveAuthenticationManager authenticationManager) {
1797+
super(authenticationManager);
1798+
}
1799+
1800+
@Override
1801+
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
1802+
WebFilterExchange webFilterExchange = new WebFilterExchange(exchange, chain);
1803+
return super.filter(exchange, chain)
1804+
.onErrorResume(AuthenticationException.class, e -> this.authenticationFailureHandler
1805+
.onAuthenticationFailure(webFilterExchange, e));
1806+
}
1807+
1808+
@Override
1809+
public void setAuthenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {
1810+
super.setAuthenticationFailureHandler(authenticationFailureHandler);
1811+
this.authenticationFailureHandler = authenticationFailureHandler;
1812+
}
1813+
}
1814+
17911815
/**
17921816
* Configures JWT Resource Server Support
17931817
*/
@@ -1861,7 +1885,7 @@ public OAuth2ResourceServerSpec and() {
18611885

18621886
protected void configure(ServerHttpSecurity http) {
18631887
ReactiveAuthenticationManager authenticationManager = getAuthenticationManager();
1864-
AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);
1888+
AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager);
18651889
oauth2.setServerAuthenticationConverter(bearerTokenConverter);
18661890
oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
18671891
http
@@ -1967,7 +1991,7 @@ protected ReactiveOpaqueTokenIntrospector getIntrospector() {
19671991

19681992
protected void configure(ServerHttpSecurity http) {
19691993
ReactiveAuthenticationManager authenticationManager = getAuthenticationManager();
1970-
AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);
1994+
AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager);
19711995
oauth2.setServerAuthenticationConverter(bearerTokenConverter);
19721996
oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
19731997
http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION);

config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ public void getWhenUnsignedThenReturnsInvalidToken() {
172172
.expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer error=\"invalid_token\""));
173173
}
174174

175+
@Test
176+
public void getWhenEmptyBearerTokenThenReturnsInvalidToken() {
177+
this.spring.register(PublicKeyConfig.class).autowire();
178+
179+
this.client.get()
180+
.headers(headers -> headers.add("Authorization", "Bearer "))
181+
.exchange()
182+
.expectStatus().isUnauthorized()
183+
.expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer error=\"invalid_token\""));
184+
}
185+
175186
@Test
176187
public void getWhenValidTokenAndPublicKeyInLambdaThenReturnsOk() {
177188
this.spring.register(PublicKeyInLambdaConfig.class, RootController.class).autowire();

0 commit comments

Comments
 (0)