From 31735515bfb083a4d604a62ead9362d62eb0829c Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 00:50:40 +0200 Subject: [PATCH 1/9] Enhanced exceptions hierarchy for jwt-key resolution --- .../security/jwt/DefaultJwtAuthenticator.java | 18 +++++------ .../security/jwt/JwtAuthenticator.java | 1 + pom.xml | 6 ++++ tokens/pom.xml | 20 +++--------- .../security/tokens/jwt/JwksKeyProvider.java | 14 +++++--- .../tokens/jwt/JwtTokenResolverImpl.java | 6 ++-- .../tokens/jwt/KeyNotFoundException.java | 18 +++++++++++ .../tokens/jwt/KeyProviderException.java | 10 ++---- .../tokens/jwt/JwtTokenResolverTests.java | 32 ++++--------------- .../security/tokens/jwt/JwtTokenWithKey.java | 22 +++++++++++++ 10 files changed, 81 insertions(+), 66 deletions(-) create mode 100644 tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyNotFoundException.java create mode 100644 tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenWithKey.java diff --git a/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java b/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java index 093aa4c..6262f56 100644 --- a/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java +++ b/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java @@ -20,18 +20,18 @@ public DefaultJwtAuthenticator(JwtKeyResolver jwtKeyResolver) { @Override public Mono authenticate(String token) { return Mono.defer( - () -> { - String tokenWithoutSignature = token.substring(0, token.lastIndexOf(".") + 1); + () -> { + String tokenWithoutSignature = token.substring(0, token.lastIndexOf(".") + 1); - JwtParser parser = Jwts.parser(); + JwtParser parser = Jwts.parser(); - Jwt claims = parser.parseClaimsJwt(tokenWithoutSignature); + Jwt claims = parser.parseClaimsJwt(tokenWithoutSignature); - return jwtKeyResolver - .resolve((Map) claims.getHeader()) - .map(key -> parser.setSigningKey(key).parseClaimsJws(token).getBody()) - .map(this::profileFromClaims); - }) + return jwtKeyResolver + .resolve((Map) claims.getHeader()) + .map(key -> parser.setSigningKey(key).parseClaimsJws(token).getBody()) + .map(this::profileFromClaims); + }) .onErrorMap(AuthenticationException::new); } } diff --git a/jwt/src/main/java/io/scalecube/security/jwt/JwtAuthenticator.java b/jwt/src/main/java/io/scalecube/security/jwt/JwtAuthenticator.java index 984e337..eae5d3f 100644 --- a/jwt/src/main/java/io/scalecube/security/jwt/JwtAuthenticator.java +++ b/jwt/src/main/java/io/scalecube/security/jwt/JwtAuthenticator.java @@ -17,6 +17,7 @@ public interface JwtAuthenticator extends Authenticator { /** * Create a profile from claims. + * * @param tokenClaims the claims to parse * @return a profile from the claims */ diff --git a/pom.xml b/pom.xml index 7ced344..df937d6 100644 --- a/pom.xml +++ b/pom.xml @@ -127,6 +127,12 @@ ${hamcrest.version} test + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + io.projectreactor reactor-test diff --git a/tokens/pom.xml b/tokens/pom.xml index f1e0829..7ee51d1 100644 --- a/tokens/pom.xml +++ b/tokens/pom.xml @@ -11,6 +11,10 @@ scalecube-security-tokens + + io.projectreactor + reactor-core + io.jsonwebtoken jjwt-api @@ -23,21 +27,11 @@ io.jsonwebtoken jjwt-jackson - - io.projectreactor - reactor-core - org.slf4j slf4j-api - - org.junit.jupiter - junit-jupiter - ${junit-jupiter.version} - test - org.testcontainers vault @@ -50,12 +44,6 @@ ${vault-java-driver.version} test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java index cb4074e..5224b44 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java @@ -18,6 +18,7 @@ import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reactor.core.Exceptions; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; @@ -26,6 +27,9 @@ public final class JwksKeyProvider implements KeyProvider { private static final Logger LOGGER = LoggerFactory.getLogger(JwksKeyProvider.class); + private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(10); + private static final Duration READ_TIMEOUT = Duration.ofSeconds(10); + private static final ObjectMapper OBJECT_MAPPER = newObjectMapper(); private final Scheduler scheduler; @@ -39,7 +43,7 @@ public final class JwksKeyProvider implements KeyProvider { * @param jwksUri jwksUri */ public JwksKeyProvider(String jwksUri) { - this(jwksUri, newScheduler(), Duration.ofSeconds(10), Duration.ofSeconds(10)); + this(jwksUri, newScheduler(), CONNECT_TIMEOUT, READ_TIMEOUT); } /** @@ -63,10 +67,10 @@ public Mono findKey(String kid) { return Mono.defer(this::callJwksUri) .map(this::toKeyList) .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) - .switchIfEmpty(Mono.error(new KeyProviderException("Key was not found, kid: " + kid))) + .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)) + .switchIfEmpty(Mono.error(new KeyNotFoundException("Key was not found, kid: " + kid))) .doOnSubscribe(s -> LOGGER.debug("[findKey] Looking up key in jwks, kid: {}", kid)) - .subscribeOn(scheduler) - .publishOn(scheduler); + .subscribeOn(scheduler); } private Mono callJwksUri() { @@ -91,7 +95,7 @@ private JwkInfoList toKeyList(InputStream stream) { return OBJECT_MAPPER.readValue(inputStream, JwkInfoList.class); } catch (IOException e) { LOGGER.error("[toKeyList] Exception occurred: {}", e.toString()); - throw new KeyProviderException(e); + throw Exceptions.propagate(e); } } diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwtTokenResolverImpl.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwtTokenResolverImpl.java index a0ca216..dec2fb9 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwtTokenResolverImpl.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwtTokenResolverImpl.java @@ -18,6 +18,8 @@ public final class JwtTokenResolverImpl implements JwtTokenResolver { private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenResolver.class); + private static final Duration CLEANUP_INTERVAL = Duration.ofSeconds(60); + private final KeyProvider keyProvider; private final JwtTokenParserFactory tokenParserFactory; private final Scheduler scheduler; @@ -31,7 +33,7 @@ public final class JwtTokenResolverImpl implements JwtTokenResolver { * @param keyProvider key provider */ public JwtTokenResolverImpl(KeyProvider keyProvider) { - this(keyProvider, new JsonwebtokenParserFactory(), newScheduler(), Duration.ofSeconds(60)); + this(keyProvider, new JsonwebtokenParserFactory(), newScheduler(), CLEANUP_INTERVAL); } /** @@ -49,8 +51,8 @@ public JwtTokenResolverImpl( Duration cleanupInterval) { this.keyProvider = keyProvider; this.tokenParserFactory = tokenParserFactory; - this.cleanupInterval = cleanupInterval; this.scheduler = scheduler; + this.cleanupInterval = cleanupInterval; } @Override diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyNotFoundException.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyNotFoundException.java new file mode 100644 index 0000000..8e683ed --- /dev/null +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyNotFoundException.java @@ -0,0 +1,18 @@ +package io.scalecube.security.tokens.jwt; + +public final class KeyNotFoundException extends RuntimeException { + + public KeyNotFoundException(String s) { + super(s); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{errorMessage=" + getMessage() + '}'; + } +} diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyProviderException.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyProviderException.java index 512eab3..2bb298b 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyProviderException.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/KeyProviderException.java @@ -2,18 +2,12 @@ public final class KeyProviderException extends RuntimeException { - public KeyProviderException() {} - public KeyProviderException(String s) { super(s); } - public KeyProviderException(String s, Throwable throwable) { - super(s, throwable); - } - - public KeyProviderException(Throwable throwable) { - super(throwable); + public KeyProviderException(Throwable cause) { + super(cause); } @Override diff --git a/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenResolverTests.java b/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenResolverTests.java index c97c240..1536931 100644 --- a/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenResolverTests.java +++ b/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenResolverTests.java @@ -1,12 +1,8 @@ package io.scalecube.security.tokens.jwt; -import static io.scalecube.security.tokens.jwt.Utils.toRsaPublicKey; - -import java.security.Key; import java.time.Duration; import java.util.Collections; import java.util.Map; -import java.util.Properties; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; @@ -20,7 +16,7 @@ class JwtTokenResolverTests { @Test void testTokenResolver() throws Exception { - TokenWithKey tokenWithKey = new TokenWithKey("token-and-pubkey.properties"); + JwtTokenWithKey tokenWithKey = new JwtTokenWithKey("token-and-pubkey.properties"); JwtTokenParser tokenParser = Mockito.mock(JwtTokenParser.class); Mockito.when(tokenParser.parseToken()) @@ -51,9 +47,9 @@ void testTokenResolver() throws Exception { @Test void testTokenResolverWithRotatingKey() throws Exception { - TokenWithKey tokenWithKey = new TokenWithKey("token-and-pubkey.properties"); - TokenWithKey tokenWithKeyAfterRotation = - new TokenWithKey("token-and-pubkey.after-rotation.properties"); + JwtTokenWithKey tokenWithKey = new JwtTokenWithKey("token-and-pubkey.properties"); + JwtTokenWithKey tokenWithKeyAfterRotation = + new JwtTokenWithKey("token-and-pubkey.after-rotation.properties"); JwtTokenParser tokenParser = Mockito.mock(JwtTokenParser.class); Mockito.when(tokenParser.parseToken()) @@ -98,7 +94,7 @@ void testTokenResolverWithRotatingKey() throws Exception { @Test void testTokenResolverWithWrongKey() throws Exception { - TokenWithKey tokenWithWrongKey = new TokenWithKey("token-and-wrong-pubkey.properties"); + JwtTokenWithKey tokenWithWrongKey = new JwtTokenWithKey("token-and-wrong-pubkey.properties"); JwtTokenParser tokenParser = Mockito.mock(JwtTokenParser.class); Mockito.when(tokenParser.parseToken()) @@ -128,7 +124,7 @@ void testTokenResolverWithWrongKey() throws Exception { @Test void testTokenResolverWhenKeyProviderFailing() throws Exception { - TokenWithKey tokenWithKey = new TokenWithKey("token-and-pubkey.properties"); + JwtTokenWithKey tokenWithKey = new JwtTokenWithKey("token-and-pubkey.properties"); JwtTokenParser tokenParser = Mockito.mock(JwtTokenParser.class); Mockito.when(tokenParser.parseToken()) @@ -153,20 +149,4 @@ void testTokenResolverWhenKeyProviderFailing() throws Exception { // failed resolution not stored => keyProvider must have been called 2 times Mockito.verify(keyProvider, Mockito.times(2)).findKey(tokenWithKey.kid); } - - static class TokenWithKey { - - final String token; - final Key key; - final String kid; - - TokenWithKey(String s) throws Exception { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Properties props = new Properties(); - props.load(classLoader.getResourceAsStream(s)); - this.token = props.getProperty("token"); - this.kid = props.getProperty("kid"); - this.key = toRsaPublicKey(props.getProperty("n"), props.getProperty("e")); - } - } } diff --git a/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenWithKey.java b/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenWithKey.java new file mode 100644 index 0000000..a04d666 --- /dev/null +++ b/tokens/src/test/java/io/scalecube/security/tokens/jwt/JwtTokenWithKey.java @@ -0,0 +1,22 @@ +package io.scalecube.security.tokens.jwt; + +import static io.scalecube.security.tokens.jwt.Utils.toRsaPublicKey; + +import java.security.Key; +import java.util.Properties; + +class JwtTokenWithKey { + + final String token; + final Key key; + final String kid; + + JwtTokenWithKey(String s) throws Exception { + Properties props = new Properties(); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + props.load(classLoader.getResourceAsStream(s)); + this.token = props.getProperty("token"); + this.kid = props.getProperty("kid"); + this.key = toRsaPublicKey(props.getProperty("n"), props.getProperty("e")); + } +} From f6bd131568ff2d61d284710fbbd0ec19a1b7d3e7 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 00:57:08 +0200 Subject: [PATCH 2/9] Fixed checkstyle --- .../security/jwt/DefaultJwtAuthenticator.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java b/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java index 6262f56..98fc2c0 100644 --- a/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java +++ b/jwt/src/main/java/io/scalecube/security/jwt/DefaultJwtAuthenticator.java @@ -19,19 +19,19 @@ public DefaultJwtAuthenticator(JwtKeyResolver jwtKeyResolver) { @Override public Mono authenticate(String token) { - return Mono.defer( - () -> { - String tokenWithoutSignature = token.substring(0, token.lastIndexOf(".") + 1); + return Mono.defer(() -> authenticate0(token)).onErrorMap(AuthenticationException::new); + } + + private Mono authenticate0(String token) { + String tokenWithoutSignature = token.substring(0, token.lastIndexOf(".") + 1); - JwtParser parser = Jwts.parser(); + JwtParser parser = Jwts.parser(); - Jwt claims = parser.parseClaimsJwt(tokenWithoutSignature); + Jwt claims = parser.parseClaimsJwt(tokenWithoutSignature); - return jwtKeyResolver - .resolve((Map) claims.getHeader()) - .map(key -> parser.setSigningKey(key).parseClaimsJws(token).getBody()) - .map(this::profileFromClaims); - }) - .onErrorMap(AuthenticationException::new); + return jwtKeyResolver + .resolve((Map) claims.getHeader()) + .map(key -> parser.setSigningKey(key).parseClaimsJws(token).getBody()) + .map(this::profileFromClaims); } } From eea519b64ed2c6de276b692265312ab8f4101639 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:00:58 +0200 Subject: [PATCH 3/9] Fixed test --- .../java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java index 5224b44..c96b816 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java @@ -67,8 +67,8 @@ public Mono findKey(String kid) { return Mono.defer(this::callJwksUri) .map(this::toKeyList) .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) - .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)) .switchIfEmpty(Mono.error(new KeyNotFoundException("Key was not found, kid: " + kid))) + .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)) .doOnSubscribe(s -> LOGGER.debug("[findKey] Looking up key in jwks, kid: {}", kid)) .subscribeOn(scheduler); } From 294640023a9e23043ddfaca95a04dbc6ea1414df Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:03:00 +0200 Subject: [PATCH 4/9] Cosmetic change --- .../io/scalecube/security/tokens/jwt/Utils.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/Utils.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/Utils.java index 0f0ca3d..2c84b36 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/Utils.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/Utils.java @@ -15,14 +15,7 @@ private Utils() { // Do not instantiate } - /** - * Turns b64 url encoded {@code n} and {@code e} into RSA public key. - * - * @param n modulus (b64 url encoded) - * @param e exponent (b64 url encoded) - * @return RSA public key instance - */ - public static Key toRsaPublicKey(String n, String e) { + static Key toRsaPublicKey(String n, String e) { Decoder b64Decoder = Base64.getUrlDecoder(); BigInteger modulus = new BigInteger(1, b64Decoder.decode(n)); BigInteger exponent = new BigInteger(1, b64Decoder.decode(e)); @@ -34,13 +27,7 @@ public static Key toRsaPublicKey(String n, String e) { } } - /** - * Mask sensitive data by replacing part of string with an asterisk symbol. - * - * @param data sensitive data to be masked - * @return masked data - */ - public static String mask(String data) { + static String mask(String data) { if (data == null || data.isEmpty() || data.length() < 5) { return "*****"; } From 511c6ebd5e5cf4d8a7bb1657649ebd2d32d31ee0 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:11:17 +0200 Subject: [PATCH 5/9] Fixing test --- .../security/tokens/jwt/JwksKeyProvider.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java index c96b816..2246cca 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java @@ -64,16 +64,15 @@ public JwksKeyProvider( @Override public Mono findKey(String kid) { - return Mono.defer(this::callJwksUri) - .map(this::toKeyList) + return Mono.defer(this::computeKeyList) .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) - .switchIfEmpty(Mono.error(new KeyNotFoundException("Key was not found, kid: " + kid))) .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)) + .switchIfEmpty(Mono.error(new KeyNotFoundException("Key was not found, kid: " + kid))) .doOnSubscribe(s -> LOGGER.debug("[findKey] Looking up key in jwks, kid: {}", kid)) .subscribeOn(scheduler); } - private Mono callJwksUri() { + private Mono computeKeyList() { return Mono.fromCallable( () -> { HttpURLConnection httpClient = (HttpURLConnection) new URL(jwksUri).openConnection(); @@ -82,15 +81,16 @@ private Mono callJwksUri() { int responseCode = httpClient.getResponseCode(); if (responseCode != 200) { - LOGGER.error("[callJwksUri][{}] Not expected response code: {}", jwksUri, responseCode); + LOGGER.error( + "[computeKeyList][{}] Not expected response code: {}", jwksUri, responseCode); throw new KeyProviderException("Not expected response code: " + responseCode); } - return httpClient.getInputStream(); + return toKeyList(httpClient.getInputStream()); }); } - private JwkInfoList toKeyList(InputStream stream) { + private static JwkInfoList toKeyList(InputStream stream) { try (InputStream inputStream = new BufferedInputStream(stream)) { return OBJECT_MAPPER.readValue(inputStream, JwkInfoList.class); } catch (IOException e) { From b5a7e20085b07acdcde602fff9388da284c8b8bd Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:18:40 +0200 Subject: [PATCH 6/9] Fixing test --- .../security/tokens/jwt/JwksKeyProvider.java | 36 +++++++++---------- .../tokens/jwt/VaultJwksKeyProviderTests.java | 6 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java index 2246cca..272f0b2 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java @@ -64,30 +64,30 @@ public JwksKeyProvider( @Override public Mono findKey(String kid) { - return Mono.defer(this::computeKeyList) - .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) - .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)) + return computeKey(kid) .switchIfEmpty(Mono.error(new KeyNotFoundException("Key was not found, kid: " + kid))) .doOnSubscribe(s -> LOGGER.debug("[findKey] Looking up key in jwks, kid: {}", kid)) .subscribeOn(scheduler); } - private Mono computeKeyList() { + private Mono computeKey(String kid) { return Mono.fromCallable( - () -> { - HttpURLConnection httpClient = (HttpURLConnection) new URL(jwksUri).openConnection(); - httpClient.setConnectTimeout((int) connectTimeoutMillis); - httpClient.setReadTimeout((int) readTimeoutMillis); - - int responseCode = httpClient.getResponseCode(); - if (responseCode != 200) { - LOGGER.error( - "[computeKeyList][{}] Not expected response code: {}", jwksUri, responseCode); - throw new KeyProviderException("Not expected response code: " + responseCode); - } - - return toKeyList(httpClient.getInputStream()); - }); + () -> { + HttpURLConnection httpClient = (HttpURLConnection) new URL(jwksUri).openConnection(); + httpClient.setConnectTimeout((int) connectTimeoutMillis); + httpClient.setReadTimeout((int) readTimeoutMillis); + + int responseCode = httpClient.getResponseCode(); + if (responseCode != 200) { + LOGGER.error( + "[computeKey][{}] Not expected response code: {}", jwksUri, responseCode); + throw new KeyProviderException("Not expected response code: " + responseCode); + } + + return toKeyList(httpClient.getInputStream()); + }) + .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) + .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)); } private static JwkInfoList toKeyList(InputStream stream) { diff --git a/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java b/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java index 4480613..17a458c 100644 --- a/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java +++ b/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java @@ -15,7 +15,7 @@ import io.jsonwebtoken.Jwts; import java.time.Duration; import java.util.UUID; -import org.junit.Assert; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -70,7 +70,7 @@ void testFindNonExistentKey() throws Exception { .expectErrorSatisfies( throwable -> { Assertions.assertEquals(throwable.getClass(), KeyProviderException.class); - Assert.assertThat(throwable.getMessage(), startsWith("Key was not found")); + MatcherAssert.assertThat(throwable.getMessage(), startsWith("Key was not found")); }) .verify(TIMEOUT); } @@ -84,7 +84,7 @@ void testKeyNotFoundOnEmptyEnvironment() { .expectErrorSatisfies( throwable -> { Assertions.assertEquals(throwable.getClass(), KeyProviderException.class); - Assert.assertThat(throwable.getMessage(), startsWith("Key was not found")); + MatcherAssert.assertThat(throwable.getMessage(), startsWith("Key was not found")); }) .verify(TIMEOUT); } From 44b2d6466ab5e1fa4934d9effd75f07576820a90 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:23:14 +0200 Subject: [PATCH 7/9] Fixed style --- .../security/tokens/jwt/JwksKeyProvider.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java index 272f0b2..4583a3d 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java @@ -71,25 +71,25 @@ public Mono findKey(String kid) { } private Mono computeKey(String kid) { - return Mono.fromCallable( - () -> { - HttpURLConnection httpClient = (HttpURLConnection) new URL(jwksUri).openConnection(); - httpClient.setConnectTimeout((int) connectTimeoutMillis); - httpClient.setReadTimeout((int) readTimeoutMillis); - - int responseCode = httpClient.getResponseCode(); - if (responseCode != 200) { - LOGGER.error( - "[computeKey][{}] Not expected response code: {}", jwksUri, responseCode); - throw new KeyProviderException("Not expected response code: " + responseCode); - } - - return toKeyList(httpClient.getInputStream()); - }) + return Mono.fromCallable(this::computeKey0) .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)); } + private JwkInfoList computeKey0() throws IOException { + HttpURLConnection httpClient = (HttpURLConnection) new URL(jwksUri).openConnection(); + httpClient.setConnectTimeout((int) connectTimeoutMillis); + httpClient.setReadTimeout((int) readTimeoutMillis); + + int responseCode = httpClient.getResponseCode(); + if (responseCode != 200) { + LOGGER.error("[computeKey][{}] Not expected response code: {}", jwksUri, responseCode); + throw new KeyProviderException("Not expected response code: " + responseCode); + } + + return toKeyList(httpClient.getInputStream()); + } + private static JwkInfoList toKeyList(InputStream stream) { try (InputStream inputStream = new BufferedInputStream(stream)) { return OBJECT_MAPPER.readValue(inputStream, JwkInfoList.class); From 39a8883739ff59078d9a05a19acc7903135b83a8 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:27:41 +0200 Subject: [PATCH 8/9] Fixed test --- .../security/tokens/jwt/VaultJwksKeyProviderTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java b/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java index 17a458c..25bdd04 100644 --- a/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java +++ b/tokens/src/test/java/io/scalecube/security/tokens/jwt/VaultJwksKeyProviderTests.java @@ -69,7 +69,7 @@ void testFindNonExistentKey() throws Exception { StepVerifier.create(keyProvider.findKey(UUID.randomUUID().toString())) .expectErrorSatisfies( throwable -> { - Assertions.assertEquals(throwable.getClass(), KeyProviderException.class); + Assertions.assertEquals(KeyNotFoundException.class, throwable.getClass()); MatcherAssert.assertThat(throwable.getMessage(), startsWith("Key was not found")); }) .verify(TIMEOUT); @@ -83,7 +83,7 @@ void testKeyNotFoundOnEmptyEnvironment() { StepVerifier.create(keyProvider.findKey(UUID.randomUUID().toString())) .expectErrorSatisfies( throwable -> { - Assertions.assertEquals(throwable.getClass(), KeyProviderException.class); + Assertions.assertEquals(KeyNotFoundException.class, throwable.getClass()); MatcherAssert.assertThat(throwable.getMessage(), startsWith("Key was not found")); }) .verify(TIMEOUT); From 3d121496965d4e300ded1032299ee46040d3bba7 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 30 Dec 2020 01:28:18 +0200 Subject: [PATCH 9/9] Cosmetic change --- .../io/scalecube/security/tokens/jwt/JwksKeyProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java index 4583a3d..3df74e1 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyProvider.java @@ -71,12 +71,12 @@ public Mono findKey(String kid) { } private Mono computeKey(String kid) { - return Mono.fromCallable(this::computeKey0) + return Mono.fromCallable(this::computeKeyList) .flatMap(list -> Mono.justOrEmpty(findRsaKey(list, kid))) .onErrorMap(th -> th instanceof KeyProviderException ? th : new KeyProviderException(th)); } - private JwkInfoList computeKey0() throws IOException { + private JwkInfoList computeKeyList() throws IOException { HttpURLConnection httpClient = (HttpURLConnection) new URL(jwksUri).openConnection(); httpClient.setConnectTimeout((int) connectTimeoutMillis); httpClient.setReadTimeout((int) readTimeoutMillis);