parent
a6b872dcf3
commit
5161712c35
|
@ -44,22 +44,23 @@ class ReactiveRemoteJWKSource implements ReactiveJWKSource {
|
||||||
private final AtomicReference<Mono<JWKSet>> cachedJWKSet = new AtomicReference<>(Mono.empty());
|
private final AtomicReference<Mono<JWKSet>> cachedJWKSet = new AtomicReference<>(Mono.empty());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cached url for jwk set.
|
* The cached JWK set URL.
|
||||||
*/
|
*/
|
||||||
private final AtomicReference<String> cachedJwkSetUrl = new AtomicReference<>();
|
private final AtomicReference<String> cachedJwkSetUrl = new AtomicReference<>();
|
||||||
|
|
||||||
private WebClient webClient = WebClient.create();
|
private WebClient webClient = WebClient.create();
|
||||||
|
|
||||||
private Mono<String> jwkSetURLProvider;
|
private final Mono<String> jwkSetUrlProvider;
|
||||||
|
|
||||||
ReactiveRemoteJWKSource(String jwkSetURL) {
|
ReactiveRemoteJWKSource(String jwkSetURL) {
|
||||||
Assert.hasText(jwkSetURL, "jwkSetURL cannot be empty");
|
Assert.hasText(jwkSetURL, "jwkSetURL cannot be empty");
|
||||||
this.cachedJwkSetUrl.set(jwkSetURL);
|
this.jwkSetUrlProvider = Mono.just(jwkSetURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactiveRemoteJWKSource(Mono<String> jwkSetURLProvider) {
|
ReactiveRemoteJWKSource(Mono<String> jwkSetUrlProvider) {
|
||||||
Assert.notNull(jwkSetURLProvider, "jwkSetURLProvider cannot be null");
|
Assert.notNull(jwkSetUrlProvider, "jwkSetUrlProvider cannot be null");
|
||||||
this.jwkSetURLProvider = jwkSetURLProvider;
|
this.jwkSetUrlProvider = Mono.fromCallable(this.cachedJwkSetUrl::get)
|
||||||
|
.switchIfEmpty(Mono.defer(() -> jwkSetUrlProvider.doOnNext(this.cachedJwkSetUrl::set)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -105,10 +106,7 @@ class ReactiveRemoteJWKSource implements ReactiveJWKSource {
|
||||||
*/
|
*/
|
||||||
private Mono<JWKSet> getJWKSet() {
|
private Mono<JWKSet> getJWKSet() {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
return Mono.justOrEmpty(this.cachedJwkSetUrl.get())
|
return this.jwkSetUrlProvider
|
||||||
.switchIfEmpty(Mono.defer(() -> this.jwkSetURLProvider
|
|
||||||
.doOnNext(this.cachedJwkSetUrl::set))
|
|
||||||
)
|
|
||||||
.flatMap((jwkSetURL) -> this.webClient.get()
|
.flatMap((jwkSetURL) -> this.webClient.get()
|
||||||
.uri(jwkSetURL)
|
.uri(jwkSetURL)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -32,15 +32,16 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.BDDMockito.willReturn;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.BDDMockito.willThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
|
@ -168,14 +169,14 @@ public class ReactiveRemoteJWKSourceTests {
|
||||||
@Test
|
@Test
|
||||||
public void getShouldRecoverAndReturnKeysAfterErrorCase() {
|
public void getShouldRecoverAndReturnKeysAfterErrorCase() {
|
||||||
given(this.matcher.matches(any())).willReturn(true);
|
given(this.matcher.matches(any())).willReturn(true);
|
||||||
this.source = new ReactiveRemoteJWKSource(Mono.fromSupplier(mockStringSupplier));
|
this.source = new ReactiveRemoteJWKSource(Mono.fromSupplier(this.mockStringSupplier));
|
||||||
doThrow(WebClientResponseException.ServiceUnavailable.class).when(this.mockStringSupplier).get();
|
willThrow(WebClientResponseException.ServiceUnavailable.class).given(this.mockStringSupplier).get();
|
||||||
// first case: id provider has error state
|
// first case: id provider has error state
|
||||||
assertThatThrownBy(() -> this.source.get(this.selector).block())
|
assertThatExceptionOfType(WebClientResponseException.ServiceUnavailable.class)
|
||||||
.isExactlyInstanceOf(WebClientResponseException.ServiceUnavailable.class);
|
.isThrownBy(() -> this.source.get(this.selector).block());
|
||||||
// second case: id provider is healthy again
|
// second case: id provider is healthy again
|
||||||
doReturn(this.server.url("/").toString()).when(this.mockStringSupplier).get();
|
willReturn(this.server.url("/").toString()).given(this.mockStringSupplier).get();
|
||||||
var actual = this.source.get(this.selector).block();
|
List<JWK> actual = this.source.get(this.selector).block();
|
||||||
assertThat(actual).isNotEmpty();
|
assertThat(actual).isNotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue