Skip to content

Commit

Permalink
Load ReactiveJwtAuthenticationConverter bean in OAuth2 Resource Serve…
Browse files Browse the repository at this point in the history
…r config

When a bean of type ReactiveJwtAuthenticationConverter is defined,
the OAuth2 Resource Server configuration will use it automatically
when no other converter is defined through the DSL.

Closes gh-9698
  • Loading branch information
ThomasVitale committed Jun 15, 2021
1 parent 65239e9 commit 5584680
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 6 deletions.
Expand Up @@ -91,10 +91,9 @@
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.access.server.BearerTokenServerAccessDeniedHandler;
Expand Down Expand Up @@ -1497,6 +1496,13 @@ private <T> T getBeanOrNull(ResolvableType type) {
return null;
}

private <T> String[] getBeanNamesForTypeOrEmpty(Class<T> beanClass) {
if (this.context == null) {
return new String[0];
}
return this.context.getBeanNamesForType(beanClass);
}

protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
Expand Down Expand Up @@ -3813,8 +3819,7 @@ public class JwtSpec {

private ReactiveJwtDecoder jwtDecoder;

private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverterAdapter(
new JwtAuthenticationConverter());
private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter;

/**
* Configures the {@link ReactiveAuthenticationManager} to use
Expand Down Expand Up @@ -3892,7 +3897,16 @@ protected ReactiveJwtDecoder getJwtDecoder() {
}

protected Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> getJwtAuthenticationConverter() {
return this.jwtAuthenticationConverter;
if (this.jwtAuthenticationConverter != null) {
return this.jwtAuthenticationConverter;
}

if (getBeanNamesForTypeOrEmpty(ReactiveJwtAuthenticationConverter.class).length > 0) {
return getBean(ReactiveJwtAuthenticationConverter.class);
}
else {
return new ReactiveJwtAuthenticationConverter();
}
}

private ReactiveAuthenticationManager getAuthenticationManager() {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -64,6 +64,7 @@
import org.springframework.security.oauth2.jwt.TestJwts;
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.ReactiveJwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
Expand Down Expand Up @@ -478,6 +479,58 @@ public void getJwtDecoderWhenNoBeansAndNoDslWiredThenWiringException() {
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> jwt.getJwtDecoder());
}

@Test
public void getJwtAuthenticationConverterWhenBeanWiredAndDslWiredThenDslTakesPrecedence() {
GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
ServerHttpSecurity http = new ServerHttpSecurity();
http.setApplicationContext(context);
ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
ReactiveJwtAuthenticationConverter dslWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
context.registerBean(ReactiveJwtAuthenticationConverter.class, () -> beanWiredJwtAuthenticationConverter);
ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter);
assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter);
}

@Test
public void getJwtAuthenticationConverterWhenTwoBeansWiredAndDslWiredThenDslTakesPrecedence() {
GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
ServerHttpSecurity http = new ServerHttpSecurity();
http.setApplicationContext(context);
ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
ReactiveJwtAuthenticationConverter dslWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
context.registerBean("firstJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
() -> beanWiredJwtAuthenticationConverter);
context.registerBean("secondJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
() -> beanWiredJwtAuthenticationConverter);
ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter);
assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter);
}

@Test
public void getJwtAuthenticationConverterWhenTwoBeansWiredThenThrowsWiringException() {
GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
ServerHttpSecurity http = new ServerHttpSecurity();
http.setApplicationContext(context);
ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
context.registerBean("firstJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
() -> beanWiredJwtAuthenticationConverter);
context.registerBean("secondJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
() -> beanWiredJwtAuthenticationConverter);
ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(jwt::getJwtAuthenticationConverter);
}

@Test
public void getJwtAuthenticationConverterWhenNoBeansAndNoDslWiredThenDefaultConverter() {
GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
ServerHttpSecurity http = new ServerHttpSecurity();
http.setApplicationContext(context);
ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
assertThat(jwt.getJwtAuthenticationConverter()).isInstanceOf(ReactiveJwtAuthenticationConverter.class);
}

@Test
public void introspectWhenValidThenReturnsOk() {
this.spring.register(IntrospectionConfig.class, RootController.class).autowire();
Expand Down

0 comments on commit 5584680

Please sign in to comment.