Allow Customization of Bearer Token Resolution

Closes gh-8535
This commit is contained in:
Arvid Ottenberg 2020-10-29 22:26:15 +01:00 committed by Josh Cummings
parent 9d1637d2cd
commit d0d655e18d
No known key found for this signature in database
GPG Key ID: 49EF60DD7FF83443
4 changed files with 91 additions and 4 deletions

View File

@ -65,7 +65,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat
private final AuthenticationManagerResolver<String> issuerAuthenticationManagerResolver;
private final Converter<HttpServletRequest, String> issuerConverter = new JwtClaimIssuerConverter();
private Converter<HttpServletRequest, String> issuerConverter = new JwtClaimIssuerConverter();
/**
* Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided
@ -130,9 +130,28 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat
return authenticationManager;
}
/**
* Set a custom bearer token resolver
*
* @since 5.5
*/
public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
this.issuerConverter = new JwtClaimIssuerConverter(bearerTokenResolver);
}
private static class JwtClaimIssuerConverter implements Converter<HttpServletRequest, String> {
private final BearerTokenResolver resolver = new DefaultBearerTokenResolver();
private final BearerTokenResolver resolver;
JwtClaimIssuerConverter() {
this(new DefaultBearerTokenResolver());
}
JwtClaimIssuerConverter(BearerTokenResolver bearerTokenResolver) {
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
this.resolver = bearerTokenResolver;
}
@Override
public String convert(@NonNull HttpServletRequest request) {

View File

@ -65,7 +65,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver
private final ReactiveAuthenticationManagerResolver<String> issuerAuthenticationManagerResolver;
private final Converter<ServerWebExchange, Mono<String>> issuerConverter = new JwtClaimIssuerConverter();
private Converter<ServerWebExchange, Mono<String>> issuerConverter = new JwtClaimIssuerConverter();
/**
* Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the
@ -131,9 +131,31 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver
// @formatter:on
}
/**
* Set a custom server bearer token authentication converter
*
* @since 5.5
*/
public void setServerBearerTokenAuthenticationConverter(
ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) {
Assert.notNull(serverBearerTokenAuthenticationConverter,
"serverBearerTokenAuthenticationConverter cannot be null");
this.issuerConverter = new JwtClaimIssuerConverter(serverBearerTokenAuthenticationConverter);
}
private static class JwtClaimIssuerConverter implements Converter<ServerWebExchange, Mono<String>> {
private final ServerBearerTokenAuthenticationConverter converter = new ServerBearerTokenAuthenticationConverter();
private final ServerBearerTokenAuthenticationConverter converter;
JwtClaimIssuerConverter() {
this(new ServerBearerTokenAuthenticationConverter());
}
JwtClaimIssuerConverter(ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) {
Assert.notNull(serverBearerTokenAuthenticationConverter,
"serverBearerTokenAuthenticationConverter cannot be null");
this.converter = serverBearerTokenAuthenticationConverter;
}
@Override
public Mono<String> convert(@NonNull ServerWebExchange exchange) {

View File

@ -21,6 +21,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
@ -39,11 +41,15 @@ import org.springframework.security.authentication.AuthenticationManagerResolver
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jose.TestKeys;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link JwtIssuerAuthenticationManagerResolver}
@ -113,6 +119,19 @@ public class JwtIssuerAuthenticationManagerResolverTests {
assertThat(authenticationManagerResolver.resolve(request)).isSameAs(authenticationManager);
}
@Test
public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverAndCustomBearerTokenResolverThenUses() {
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver(
(issuer) -> authenticationManager);
BearerTokenResolver bearerTokenResolverSpy = spy(new TestBearerTokenResolver());
authenticationManagerResolver.setBearerTokenResolver(bearerTokenResolverSpy);
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Bearer " + this.jwt);
assertThat(authenticationManagerResolver.resolve(request)).isSameAs(authenticationManager);
verify(bearerTokenResolverSpy).resolve(any());
}
@Test
public void resolveWhenUsingExternalSourceThenRespondsToChanges() {
MockHttpServletRequest request = new MockHttpServletRequest();
@ -196,4 +215,13 @@ public class JwtIssuerAuthenticationManagerResolverTests {
return jwt.serialize();
}
static class TestBearerTokenResolver implements BearerTokenResolver {
@Override
public String resolve(HttpServletRequest request) {
return "eyJhbGciOiJub25lIn0.eyJpc3MiOiJ0cnVzdGVkIn0.";
}
}
}

View File

@ -41,11 +41,15 @@ import org.springframework.security.authentication.ReactiveAuthenticationManager
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jose.TestKeys;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link JwtIssuerReactiveAuthenticationManagerResolver}
@ -111,6 +115,20 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
assertThat(authenticationManagerResolver.resolve(exchange).block()).isSameAs(authenticationManager);
}
@Test
public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverAndCustomServerBearerTokenAuthenticationConverterThenUses() {
ReactiveAuthenticationManager authenticationManager = mock(ReactiveAuthenticationManager.class);
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(
(issuer) -> Mono.just(authenticationManager));
ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverterSpy = spy(
new ServerBearerTokenAuthenticationConverter());
authenticationManagerResolver
.setServerBearerTokenAuthenticationConverter(serverBearerTokenAuthenticationConverterSpy);
MockServerWebExchange exchange = withBearerToken(this.jwt);
assertThat(authenticationManagerResolver.resolve(exchange).block()).isSameAs(authenticationManager);
verify(serverBearerTokenAuthenticationConverterSpy).convert(any());
}
@Test
public void resolveWhenUsingExternalSourceThenRespondsToChanges() {
MockServerWebExchange exchange = withBearerToken(this.jwt);