Skip to content

Commit 8a20b22

Browse files
Update NimbusReactiveJwtDecoder to use a reactive JwtValidator and process non-reactive JwtValidators on the BoundedElastic scheduler
Signed-off-by: Iain Henderson <Iain.henderson@mac.com>
1 parent 5a7d93e commit 8a20b22

1 file changed

Lines changed: 25 additions & 2 deletions

File tree

oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import com.nimbusds.jwt.proc.JWTProcessor;
5858
import reactor.core.publisher.Flux;
5959
import reactor.core.publisher.Mono;
60+
import reactor.core.scheduler.Schedulers;
6061
import reactor.util.function.Tuple2;
6162
import reactor.util.function.Tuples;
6263

@@ -96,7 +97,7 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
9697

9798
private final Converter<JWT, Mono<JWTClaimsSet>> jwtProcessor;
9899

99-
private OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefault();
100+
private Converter<Jwt, Mono<Jwt>> jwtValidator;
100101

101102
private Converter<Map<String, Object>, Map<String, Object>> claimSetConverter = MappedJwtClaimSetConverter
102103
.withDefaults(Collections.emptyMap());
@@ -126,13 +127,35 @@ public NimbusReactiveJwtDecoder(RSAPublicKey publicKey) {
126127
*/
127128
public NimbusReactiveJwtDecoder(Converter<JWT, Mono<JWTClaimsSet>> jwtProcessor) {
128129
this.jwtProcessor = jwtProcessor;
130+
setJwtValidator(JwtValidators.createDefault());
129131
}
130132

131133
/**
132134
* Use the provided {@link OAuth2TokenValidator} to validate incoming {@link Jwt}s.
133135
* @param jwtValidator the {@link OAuth2TokenValidator} to use
134136
*/
135137
public void setJwtValidator(OAuth2TokenValidator<Jwt> jwtValidator) {
138+
Assert.notNull(jwtValidator, "jwtValidator cannot be null");
139+
this.jwtValidator = jwt -> Mono.fromSupplier(() -> jwtValidator.validate(jwt))
140+
.subscribeOn(Schedulers.boundedElastic())
141+
.handle((result, sink) -> {
142+
if (result.hasErrors()) {
143+
Collection<OAuth2Error> errors = result.getErrors();
144+
String validationErrorString = getJwtValidationExceptionMessage(errors);
145+
sink.error(new JwtValidationException(validationErrorString, errors));
146+
}
147+
else {
148+
sink.next(jwt);
149+
}
150+
});
151+
}
152+
153+
/**
154+
* Use the provided {@link Converter} to validate incoming {@link Jwt}s.
155+
* This overrides the {@link OAuth2TokenValidator}, but allows for reactive validation.
156+
* @param jwtValidator the {@link Converter} to use
157+
*/
158+
public void setJwtValidator(Converter<Jwt, Mono<Jwt>> jwtValidator) {
136159
Assert.notNull(jwtValidator, "jwtValidator cannot be null");
137160
this.jwtValidator = jwtValidator;
138161
}
@@ -166,7 +189,7 @@ private Mono<Jwt> decode(JWT parsedToken) {
166189
// @formatter:off
167190
return this.jwtProcessor.convert(parsedToken)
168191
.map((set) -> createJwt(parsedToken, set))
169-
.map(this::validateJwt)
192+
.flatMap(jwtValidator::convert)
170193
.onErrorMap((ex) -> !(ex instanceof IllegalStateException) && !(ex instanceof JwtException),
171194
(ex) -> new JwtException("An error occurred while attempting to decode the Jwt: ", ex));
172195
// @formatter:on

0 commit comments

Comments
 (0)