Skip to content

Commit be423de

Browse files
edeandreajzheaux
authored andcommitted
ServerAuthenticationConverter should be configurable
Fixes gh-6186
1 parent 63f2b60 commit be423de

File tree

2 files changed

+72
-18
lines changed

2 files changed

+72
-18
lines changed

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package org.springframework.security.config.web.server;
1818

19+
import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
20+
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
21+
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.notMatch;
22+
1923
import java.io.IOException;
2024
import java.io.PrintWriter;
2125
import java.io.StringWriter;
@@ -155,10 +159,6 @@
155159
import org.springframework.web.server.WebFilter;
156160
import org.springframework.web.server.WebFilterChain;
157161

158-
import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
159-
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
160-
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.notMatch;
161-
162162
/**
163163
* A {@link ServerHttpSecurity} is similar to Spring Security's {@code HttpSecurity} but for WebFlux.
164164
* It allows configuring web based security for specific http requests. By default it will be applied
@@ -883,6 +883,7 @@ public OAuth2ResourceServerSpec oauth2ResourceServer() {
883883
public class OAuth2ResourceServerSpec {
884884
private ServerAuthenticationEntryPoint entryPoint = new BearerTokenServerAuthenticationEntryPoint();
885885
private ServerAccessDeniedHandler accessDeniedHandler = new BearerTokenServerAccessDeniedHandler();
886+
private ServerAuthenticationConverter bearerTokenConverter = new ServerBearerTokenAuthenticationConverter();
886887

887888
private JwtSpec jwt;
888889

@@ -915,6 +916,20 @@ public OAuth2ResourceServerSpec authenticationEntryPoint(ServerAuthenticationEnt
915916
return this;
916917
}
917918

919+
/**
920+
* Configures the {@link ServerAuthenticationConverter} to use for requests authenticating with
921+
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer Token</a>s.
922+
*
923+
* @param bearerTokenConverter The {@link ServerAuthenticationConverter} to use
924+
* @return The {@link OAuth2ResourceServerSpec} for additional configuration
925+
* @since 5.2
926+
*/
927+
public OAuth2ResourceServerSpec bearerTokenConverter(ServerAuthenticationConverter bearerTokenConverter) {
928+
Assert.notNull(bearerTokenConverter, "bearerTokenConverter cannot be null");
929+
this.bearerTokenConverter = bearerTokenConverter;
930+
return this;
931+
}
932+
918933
public JwtSpec jwt() {
919934
if (this.jwt == null) {
920935
this.jwt = new JwtSpec();
@@ -1003,8 +1018,6 @@ public OAuth2ResourceServerSpec and() {
10031018
}
10041019

10051020
protected void configure(ServerHttpSecurity http) {
1006-
ServerBearerTokenAuthenticationConverter bearerTokenConverter =
1007-
new ServerBearerTokenAuthenticationConverter();
10081021
this.bearerTokenServerWebExchangeMatcher.setBearerTokenConverter(bearerTokenConverter);
10091022

10101023
registerDefaultAccessDeniedHandler(http);
@@ -1083,7 +1096,7 @@ private void registerDefaultCsrfOverride(ServerHttpSecurity http) {
10831096
}
10841097

10851098
private class BearerTokenServerWebExchangeMatcher implements ServerWebExchangeMatcher {
1086-
ServerBearerTokenAuthenticationConverter bearerTokenConverter;
1099+
ServerAuthenticationConverter bearerTokenConverter;
10871100

10881101
@Override
10891102
public Mono<MatchResult> matches(ServerWebExchange exchange) {
@@ -1092,7 +1105,7 @@ public Mono<MatchResult> matches(ServerWebExchange exchange) {
10921105
.onErrorResume(e -> notMatch());
10931106
}
10941107

1095-
public void setBearerTokenConverter(ServerBearerTokenAuthenticationConverter bearerTokenConverter) {
1108+
public void setBearerTokenConverter(ServerAuthenticationConverter bearerTokenConverter) {
10961109
Assert.notNull(bearerTokenConverter, "bearerTokenConverter cannot be null");
10971110
this.bearerTokenConverter = bearerTokenConverter;
10981111
}

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

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
*/
1616
package org.springframework.security.config.web.server;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThatCode;
20+
import static org.hamcrest.core.StringStartsWith.startsWith;
21+
import static org.mockito.ArgumentMatchers.any;
22+
import static org.mockito.ArgumentMatchers.anyString;
23+
import static org.mockito.Mockito.mock;
24+
import static org.mockito.Mockito.verify;
25+
import static org.mockito.Mockito.when;
26+
1827
import java.io.IOException;
1928
import java.math.BigInteger;
2029
import java.security.KeyFactory;
@@ -27,14 +36,14 @@
2736
import java.util.Collections;
2837
import java.util.stream.Collectors;
2938
import java.util.stream.Stream;
39+
3040
import javax.annotation.PreDestroy;
3141

32-
import okhttp3.mockwebserver.MockResponse;
33-
import okhttp3.mockwebserver.MockWebServer;
3442
import org.apache.http.HttpHeaders;
3543
import org.junit.Rule;
3644
import org.junit.Test;
3745
import org.junit.runner.RunWith;
46+
3847
import reactor.core.publisher.Mono;
3948

4049
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -56,10 +65,12 @@
5665
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
5766
import org.springframework.security.oauth2.jwt.Jwt;
5867
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
68+
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
5969
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
6070
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
6171
import org.springframework.security.web.server.SecurityWebFilterChain;
6272
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
73+
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
6374
import org.springframework.security.web.server.authorization.HttpStatusServerAccessDeniedHandler;
6475
import org.springframework.test.context.junit4.SpringRunner;
6576
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -70,14 +81,8 @@
7081
import org.springframework.web.reactive.DispatcherHandler;
7182
import org.springframework.web.reactive.config.EnableWebFlux;
7283

73-
import static org.assertj.core.api.Assertions.assertThat;
74-
import static org.assertj.core.api.Assertions.assertThatCode;
75-
import static org.hamcrest.core.StringStartsWith.startsWith;
76-
import static org.mockito.ArgumentMatchers.any;
77-
import static org.mockito.ArgumentMatchers.anyString;
78-
import static org.mockito.Mockito.mock;
79-
import static org.mockito.Mockito.verify;
80-
import static org.mockito.Mockito.when;
84+
import okhttp3.mockwebserver.MockResponse;
85+
import okhttp3.mockwebserver.MockWebServer;
8186

8287
/**
8388
* Tests for {@link org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec}
@@ -225,6 +230,16 @@ public void postWhenMissingTokenThenReturnsForbidden() {
225230
.expectStatus().isForbidden();
226231
}
227232

233+
@Test
234+
public void getWhenCustomBearerTokenServerAuthenticationConverterThenResponds() {
235+
this.spring.register(CustomBearerTokenServerAuthenticationConverter.class, RootController.class).autowire();
236+
237+
this.client.get()
238+
.cookie("TOKEN", this.messageReadToken)
239+
.exchange()
240+
.expectStatus().isOk();
241+
}
242+
228243
@Test
229244
public void getWhenSignedAndCustomConverterThenConverts() {
230245
this.spring.register(CustomJwtAuthenticationConverterConfig.class, RootController.class).autowire();
@@ -429,6 +444,32 @@ ReactiveAuthenticationManager authenticationManager() {
429444
}
430445
}
431446

447+
@EnableWebFlux
448+
@EnableWebFluxSecurity
449+
static class CustomBearerTokenServerAuthenticationConverter {
450+
@Bean
451+
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) throws Exception {
452+
// @formatter:off
453+
http
454+
.authorizeExchange()
455+
.anyExchange().hasAuthority("SCOPE_message:read")
456+
.and()
457+
.oauth2ResourceServer()
458+
.bearerTokenConverter(bearerTokenAuthenticationConverter())
459+
.jwt()
460+
.publicKey(publicKey());
461+
// @formatter:on
462+
463+
return http.build();
464+
}
465+
466+
@Bean
467+
ServerAuthenticationConverter bearerTokenAuthenticationConverter() {
468+
return exchange -> Mono.justOrEmpty(exchange.getRequest().getCookies().getFirst("TOKEN").getValue())
469+
.map(BearerTokenAuthenticationToken::new);
470+
}
471+
}
472+
432473
@EnableWebFlux
433474
@EnableWebFluxSecurity
434475
static class CustomJwtAuthenticationConverterConfig {

0 commit comments

Comments
 (0)