ServerAuthenticationConverter should be configurable

Fixes gh-6186
This commit is contained in:
Eric Deandrea 2018-11-29 12:57:58 -05:00 committed by Josh Cummings
parent 97e549a27a
commit 83953249a9
No known key found for this signature in database
GPG Key ID: 49EF60DD7FF83443
2 changed files with 59 additions and 8 deletions

View File

@ -16,6 +16,10 @@
package org.springframework.security.config.web.server;
import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.notMatch;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
@ -155,10 +159,6 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.notMatch;
/**
* A {@link ServerHttpSecurity} is similar to Spring Security's {@code HttpSecurity} but for WebFlux.
* It allows configuring web based security for specific http requests. By default it will be applied
@ -883,9 +883,24 @@ public class ServerHttpSecurity {
public class OAuth2ResourceServerSpec {
private BearerTokenServerAuthenticationEntryPoint entryPoint = new BearerTokenServerAuthenticationEntryPoint();
private BearerTokenServerAccessDeniedHandler accessDeniedHandler = new BearerTokenServerAccessDeniedHandler();
private ServerAuthenticationConverter bearerTokenConverter = new ServerBearerTokenAuthenticationConverter();
private JwtSpec jwt;
/**
* Configures the {@link ServerAuthenticationConverter} to use for requests authenticating with
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer Token</a>s.
*
* @param bearerTokenConverter The {@link ServerAuthenticationConverter} to use
* @return The {@link OAuth2ResourceServerSpec} for additional configuration
* @since 5.1.5
*/
public OAuth2ResourceServerSpec bearerTokenConverter(ServerAuthenticationConverter bearerTokenConverter) {
Assert.notNull(bearerTokenConverter, "bearerTokenConverter cannot be null");
this.bearerTokenConverter = bearerTokenConverter;
return this;
}
public JwtSpec jwt() {
if (this.jwt == null) {
this.jwt = new JwtSpec();
@ -974,8 +989,6 @@ public class ServerHttpSecurity {
}
protected void configure(ServerHttpSecurity http) {
ServerBearerTokenAuthenticationConverter bearerTokenConverter =
new ServerBearerTokenAuthenticationConverter();
this.bearerTokenServerWebExchangeMatcher.setBearerTokenConverter(bearerTokenConverter);
registerDefaultAccessDeniedHandler(http);
@ -1054,7 +1067,7 @@ public class ServerHttpSecurity {
}
private class BearerTokenServerWebExchangeMatcher implements ServerWebExchangeMatcher {
ServerBearerTokenAuthenticationConverter bearerTokenConverter;
ServerAuthenticationConverter bearerTokenConverter;
@Override
public Mono<MatchResult> matches(ServerWebExchange exchange) {
@ -1063,7 +1076,7 @@ public class ServerHttpSecurity {
.onErrorResume(e -> notMatch());
}
public void setBearerTokenConverter(ServerBearerTokenAuthenticationConverter bearerTokenConverter) {
public void setBearerTokenConverter(ServerAuthenticationConverter bearerTokenConverter) {
Assert.notNull(bearerTokenConverter, "bearerTokenConverter cannot be null");
this.bearerTokenConverter = bearerTokenConverter;
}

View File

@ -55,9 +55,11 @@ import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.bind.annotation.GetMapping;
@ -222,6 +224,16 @@ public class OAuth2ResourceServerSpecTests {
.expectStatus().isForbidden();
}
@Test
public void getWhenCustomBearerTokenServerAuthenticationConverterThenResponds() {
this.spring.register(CustomBearerTokenServerAuthenticationConverter.class, RootController.class).autowire();
this.client.get()
.cookie("TOKEN", this.messageReadToken)
.exchange()
.expectStatus().isOk();
}
@Test
public void getWhenSignedAndCustomConverterThenConverts() {
this.spring.register(CustomJwtAuthenticationConverterConfig.class, RootController.class).autowire();
@ -405,6 +417,32 @@ public class OAuth2ResourceServerSpecTests {
}
}
@EnableWebFlux
@EnableWebFluxSecurity
static class CustomBearerTokenServerAuthenticationConverter {
@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeExchange()
.anyExchange().hasAuthority("SCOPE_message:read")
.and()
.oauth2ResourceServer()
.bearerTokenConverter(bearerTokenAuthenticationConverter())
.jwt()
.publicKey(publicKey());
// @formatter:on
return http.build();
}
@Bean
ServerAuthenticationConverter bearerTokenAuthenticationConverter() {
return exchange -> Mono.justOrEmpty(exchange.getRequest().getCookies().getFirst("TOKEN").getValue())
.map(BearerTokenAuthenticationToken::new);
}
}
@EnableWebFlux
@EnableWebFluxSecurity
static class CustomJwtAuthenticationConverterConfig {