This commit is contained in:
Phillip Webb 2017-11-28 16:21:09 -08:00
parent 2319d01feb
commit 960083bd33
10 changed files with 60 additions and 45 deletions

View File

@ -23,7 +23,6 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@ -71,24 +70,31 @@ class ReactiveTokenValidator {
}
private Mono<Void> validateKeyIdAndSignature(Token token) {
String keyId = token.getKeyId();
Map<String, String> localCachedTokenKeys = new HashMap<>(this.cachedTokenKeys);
return Mono.just(localCachedTokenKeys)
.filter((tokenKeys) -> tokenKeys.containsKey(keyId))
.switchIfEmpty(this.securityService.fetchTokenKeys()
.doOnSuccess((fetchedTokenKeys) -> {
this.cachedTokenKeys.clear();
this.cachedTokenKeys.putAll(fetchedTokenKeys);
}).filter((tokenKeys) -> tokenKeys.containsKey(keyId))
.switchIfEmpty((Mono.error(new CloudFoundryAuthorizationException(
Reason.INVALID_KEY_ID,
"Key Id present in token header does not match")))))
.filter((tokenKeys) -> hasValidSignature(token, tokenKeys.get(keyId)))
return getTokenKey(token).filter((tokenKey) -> hasValidSignature(token, tokenKey))
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(
Reason.INVALID_SIGNATURE, "RSA Signature did not match content")))
.then();
}
private Mono<String> getTokenKey(Token token) {
String keyId = token.getKeyId();
String cached = this.cachedTokenKeys.get(keyId);
if (cached != null) {
return Mono.just(cached);
}
return this.securityService.fetchTokenKeys().doOnSuccess(this::cacheTokenKeys)
.filter((tokenKeys) -> tokenKeys.containsKey(keyId))
.map((tokenKeys) -> tokenKeys.get(keyId))
.switchIfEmpty(Mono.error(
new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,
"Key Id present in token header does not match")));
}
private void cacheTokenKeys(Map<String, String> tokenKeys) {
this.cachedTokenKeys.clear();
this.cachedTokenKeys.putAll(tokenKeys);
}
private boolean hasValidSignature(Token token, String key) {
try {
PublicKey publicKey = getPublicKey(key);

View File

@ -28,8 +28,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesC
* @author Jon Schneider
* @author Phillip Webb
*/
class AtlasPropertiesConfigAdapter extends
PropertiesConfigAdapter<AtlasProperties> implements AtlasConfig {
class AtlasPropertiesConfigAdapter extends PropertiesConfigAdapter<AtlasProperties>
implements AtlasConfig {
AtlasPropertiesConfigAdapter(AtlasProperties properties) {
super(properties);

View File

@ -30,8 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesC
* @author Jon Schneider
* @author Phillip Webb
*/
class GangliaPropertiesConfigAdapter
extends PropertiesConfigAdapter<GangliaProperties>
class GangliaPropertiesConfigAdapter extends PropertiesConfigAdapter<GangliaProperties>
implements GangliaConfig {
GangliaPropertiesConfigAdapter(GangliaProperties properties) {

View File

@ -30,8 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesC
* @author Jon Schneider
* @author Phillip Webb
*/
class GraphitePropertiesConfigAdapter
extends PropertiesConfigAdapter<GraphiteProperties>
class GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphiteProperties>
implements GraphiteConfig {
GraphitePropertiesConfigAdapter(GraphiteProperties properties) {

View File

@ -28,9 +28,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesC
* @author Jon Schneider
* @author Phillip Webb
*/
class PrometheusPropertiesConfigAdapter
extends PropertiesConfigAdapter<PrometheusProperties>
implements PrometheusConfig {
class PrometheusPropertiesConfigAdapter extends
PropertiesConfigAdapter<PrometheusProperties> implements PrometheusConfig {
PrometheusPropertiesConfigAdapter(PrometheusProperties properties) {
super(properties);

View File

@ -28,8 +28,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesC
* @author Jon Schneider
* @since 2.0.0
*/
public class SimplePropertiesConfigAdapter extends
PropertiesConfigAdapter<SimpleProperties> implements SimpleConfig {
public class SimplePropertiesConfigAdapter
extends PropertiesConfigAdapter<SimpleProperties> implements SimpleConfig {
public SimplePropertiesConfigAdapter(SimpleProperties properties) {
super(properties);

View File

@ -29,8 +29,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesC
* @author Jon Schneider
* @since 2.0.0
*/
public class StatsdPropertiesConfigAdapter extends
PropertiesConfigAdapter<StatsdProperties> implements StatsdConfig {
public class StatsdPropertiesConfigAdapter
extends PropertiesConfigAdapter<StatsdProperties> implements StatsdConfig {
public StatsdPropertiesConfigAdapter(StatsdProperties properties) {
super(properties);

View File

@ -93,8 +93,10 @@ public class ReactiveTokenValidatorTests {
}
@Test
public void validateTokenWhenKidValidationFailsTwiceShouldThrowException() throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));
public void validateTokenWhenKidValidationFailsTwiceShouldThrowException()
throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe
.of(Mono.just(VALID_KEYS));
ReflectionTestUtils.setField(this.tokenValidator, "cachedTokenKeys", VALID_KEYS);
given(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());
given(this.securityService.getUaaUrl())
@ -110,15 +112,19 @@ public class ReactiveTokenValidatorTests {
assertThat(((CloudFoundryAuthorizationException) ex).getReason())
.isEqualTo(Reason.INVALID_KEY_ID);
}).verify();
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator, "cachedTokenKeys");
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator,
"cachedTokenKeys");
assertThat(cachedTokenKeys).isEqualTo(VALID_KEYS);
fetchTokenKeys.assertWasSubscribed();
}
@Test
public void validateTokenWhenKidValidationSucceedsInTheSecondAttempt() throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));
ReflectionTestUtils.setField(this.tokenValidator, "cachedTokenKeys", INVALID_KEYS);
public void validateTokenWhenKidValidationSucceedsInTheSecondAttempt()
throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe
.of(Mono.just(VALID_KEYS));
ReflectionTestUtils.setField(this.tokenValidator, "cachedTokenKeys",
INVALID_KEYS);
given(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());
given(this.securityService.getUaaUrl())
.willReturn(Mono.just("http://localhost:8080/uaa"));
@ -128,14 +134,16 @@ public class ReactiveTokenValidatorTests {
.create(this.tokenValidator.validate(
new Token(getSignedToken(header.getBytes(), claims.getBytes()))))
.verifyComplete();
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator, "cachedTokenKeys");
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator,
"cachedTokenKeys");
assertThat(cachedTokenKeys).isEqualTo(VALID_KEYS);
fetchTokenKeys.assertWasSubscribed();
}
@Test
public void validateTokenWhenCacheIsEmptyShouldFetchTokenKeys() throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe
.of(Mono.just(VALID_KEYS));
given(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());
given(this.securityService.getUaaUrl())
.willReturn(Mono.just("http://localhost:8080/uaa"));
@ -145,14 +153,17 @@ public class ReactiveTokenValidatorTests {
.create(this.tokenValidator.validate(
new Token(getSignedToken(header.getBytes(), claims.getBytes()))))
.verifyComplete();
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator, "cachedTokenKeys");
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator,
"cachedTokenKeys");
assertThat(cachedTokenKeys).isEqualTo(VALID_KEYS);
fetchTokenKeys.assertWasSubscribed();
}
@Test
public void validateTokenWhenCacheEmptyAndInvalidKeyShouldThrowException() throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));
public void validateTokenWhenCacheEmptyAndInvalidKeyShouldThrowException()
throws Exception {
PublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe
.of(Mono.just(VALID_KEYS));
given(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());
given(this.securityService.getUaaUrl())
.willReturn(Mono.just("http://localhost:8080/uaa"));
@ -167,7 +178,8 @@ public class ReactiveTokenValidatorTests {
assertThat(((CloudFoundryAuthorizationException) ex).getReason())
.isEqualTo(Reason.INVALID_KEY_ID);
}).verify();
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator, "cachedTokenKeys");
Object cachedTokenKeys = ReflectionTestUtils.getField(this.tokenValidator,
"cachedTokenKeys");
assertThat(cachedTokenKeys).isEqualTo(VALID_KEYS);
fetchTokenKeys.assertWasSubscribed();
}

View File

@ -42,8 +42,8 @@ public class CouchbaseHealthIndicatorTests {
public void couchbaseIsUp() {
CouchbaseOperations couchbaseOperations = mock(CouchbaseOperations.class);
ClusterInfo clusterInfo = mock(ClusterInfo.class);
given(clusterInfo.getAllVersions()).willReturn(
Arrays.asList(new Version(1, 2, 3)));
given(clusterInfo.getAllVersions())
.willReturn(Arrays.asList(new Version(1, 2, 3)));
given(couchbaseOperations.getCouchbaseClusterInfo()).willReturn(clusterInfo);
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(
couchbaseOperations);
@ -56,8 +56,8 @@ public class CouchbaseHealthIndicatorTests {
@Test
public void couchbaseIsDown() {
CouchbaseOperations couchbaseOperations = mock(CouchbaseOperations.class);
given(couchbaseOperations.getCouchbaseClusterInfo()).willThrow(
new IllegalStateException("test, expected"));
given(couchbaseOperations.getCouchbaseClusterInfo())
.willThrow(new IllegalStateException("test, expected"));
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(
couchbaseOperations);
Health health = healthIndicator.health();

View File

@ -19,7 +19,7 @@ package org.springframework.boot.autoconfigure.data.alt.couchbase;
import org.springframework.boot.autoconfigure.data.couchbase.city.City;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface ReactiveCityCouchbaseRepository extends
ReactiveCrudRepository<City, Long> {
public interface ReactiveCityCouchbaseRepository
extends ReactiveCrudRepository<City, Long> {
}