Browse Source

Malformed Bearer Token Returns 401 for WebFlux

Fixes gh-7668
Josh Cummings 5 years ago
parent
commit
c729fee7bc

+ 26 - 2
config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

@@ -52,6 +52,7 @@ import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.authorization.ReactiveAuthorizationManager;
 import org.springframework.security.config.Customizer;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
@@ -102,6 +103,7 @@ import org.springframework.security.web.server.DelegatingServerAuthenticationEnt
 import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
 import org.springframework.security.web.server.SecurityWebFilterChain;
 import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
+import org.springframework.security.web.server.WebFilterExchange;
 import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilter;
 import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
 import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
@@ -1788,6 +1790,28 @@ public class ServerHttpSecurity {
 			}
 		}
 
+		private class BearerTokenAuthenticationWebFilter extends AuthenticationWebFilter {
+			private ServerAuthenticationFailureHandler authenticationFailureHandler;
+
+			BearerTokenAuthenticationWebFilter(ReactiveAuthenticationManager authenticationManager) {
+				super(authenticationManager);
+			}
+
+			@Override
+			public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
+				WebFilterExchange webFilterExchange = new WebFilterExchange(exchange, chain);
+				return super.filter(exchange, chain)
+						.onErrorResume(AuthenticationException.class, e -> this.authenticationFailureHandler
+								.onAuthenticationFailure(webFilterExchange, e));
+			}
+
+			@Override
+			public void setAuthenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {
+				super.setAuthenticationFailureHandler(authenticationFailureHandler);
+				this.authenticationFailureHandler = authenticationFailureHandler;
+			}
+		}
+
 		/**
 		 * Configures JWT Resource Server Support
 		 */
@@ -1861,7 +1885,7 @@ public class ServerHttpSecurity {
 
 			protected void configure(ServerHttpSecurity http) {
 				ReactiveAuthenticationManager authenticationManager = getAuthenticationManager();
-				AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);
+				AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager);
 				oauth2.setServerAuthenticationConverter(bearerTokenConverter);
 				oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
 				http
@@ -1967,7 +1991,7 @@ public class ServerHttpSecurity {
 
 			protected void configure(ServerHttpSecurity http) {
 				ReactiveAuthenticationManager authenticationManager = getAuthenticationManager();
-				AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);
+				AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager);
 				oauth2.setServerAuthenticationConverter(bearerTokenConverter);
 				oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
 				http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION);

+ 11 - 0
config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java

@@ -172,6 +172,17 @@ public class OAuth2ResourceServerSpecTests {
 				.expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer error=\"invalid_token\""));
 	}
 
+	@Test
+	public void getWhenEmptyBearerTokenThenReturnsInvalidToken() {
+		this.spring.register(PublicKeyConfig.class).autowire();
+
+		this.client.get()
+				.headers(headers -> headers.add("Authorization", "Bearer "))
+				.exchange()
+				.expectStatus().isUnauthorized()
+				.expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer error=\"invalid_token\""));
+	}
+
 	@Test
 	public void getWhenValidTokenAndPublicKeyInLambdaThenReturnsOk() {
 		this.spring.register(PublicKeyInLambdaConfig.class, RootController.class).autowire();