From 3055b7ca9b0897d56c8a81c2083fd9fa7dcc083e Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Sat, 8 Mar 2025 12:26:29 +0200 Subject: [PATCH 1/7] Fixed builders --- .../tokens/jwt/JsonwebtokenResolverTests.java | 2 +- .../security/vault/VaultServiceTokenTests.java | 14 +++++++------- .../security/tokens/jwt/JwksKeyLocator.java | 6 ++++++ .../security/vault/VaultServiceRolesInstaller.java | 6 +++++- .../security/vault/VaultServiceTokenSupplier.java | 6 +++++- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tests/src/test/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolverTests.java b/tests/src/test/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolverTests.java index bc8a3f5..665e9af 100644 --- a/tests/src/test/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolverTests.java +++ b/tests/src/test/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolverTests.java @@ -29,7 +29,7 @@ void testResolveTokenSuccessfully(VaultEnvironment vaultEnvironment) throws Exce final var jwtToken = new JsonwebtokenResolver( - new JwksKeyLocator.Builder() + JwksKeyLocator.builder() .jwksUri(vaultEnvironment.jwksUri()) .connectTimeout(Duration.ofSeconds(3)) .requestTimeout(Duration.ofSeconds(3)) diff --git a/tests/src/test/java/io/scalecube/security/vault/VaultServiceTokenTests.java b/tests/src/test/java/io/scalecube/security/vault/VaultServiceTokenTests.java index f5d07a9..fb09fb5 100644 --- a/tests/src/test/java/io/scalecube/security/vault/VaultServiceTokenTests.java +++ b/tests/src/test/java/io/scalecube/security/vault/VaultServiceTokenTests.java @@ -30,7 +30,7 @@ public class VaultServiceTokenTests { void testGetServiceTokenUsingWrongCredentials(VaultEnvironment vaultEnvironment) throws Exception { final var serviceTokenSupplier = - new VaultServiceTokenSupplier.Builder() + VaultServiceTokenSupplier.builder() .vaultAddress(vaultEnvironment.vaultAddr()) .vaultTokenSupplier(() -> completedFuture(randomAlphabetic(16))) .serviceRole(randomAlphabetic(16)) @@ -52,7 +52,7 @@ void testGetNonExistingServiceToken(VaultEnvironment vaultEnvironment) throws Ex final var nonExistingServiceRole = "non-existing-role-" + System.currentTimeMillis(); final var serviceTokenSupplier = - new VaultServiceTokenSupplier.Builder() + VaultServiceTokenSupplier.builder() .vaultAddress(vaultEnvironment.vaultAddr()) .vaultTokenSupplier(() -> completedFuture(vaultEnvironment.login())) .serviceRole(nonExistingServiceRole) @@ -76,7 +76,7 @@ void testGetServiceTokenByWrongServiceRole(VaultEnvironment vaultEnvironment) th final var serviceRole2 = "role2-" + now; final var serviceRole3 = "role3-" + now; - new VaultServiceRolesInstaller.Builder() + VaultServiceRolesInstaller.builder() .vaultAddress(vaultEnvironment.vaultAddr()) .vaultTokenSupplier(() -> completedFuture(vaultEnvironment.login())) .keyNameSupplier(() -> "key-" + now) @@ -94,7 +94,7 @@ void testGetServiceTokenByWrongServiceRole(VaultEnvironment vaultEnvironment) th .install(); final var serviceTokenSupplier = - new VaultServiceTokenSupplier.Builder() + VaultServiceTokenSupplier.builder() .vaultAddress(vaultEnvironment.vaultAddr()) .vaultTokenSupplier(() -> completedFuture(vaultEnvironment.login())) .serviceRole(serviceRole1) @@ -117,7 +117,7 @@ void testGetServiceTokenSuccessfully(VaultEnvironment vaultEnvironment) throws E final var serviceRole = "role-" + now; final var tags = Map.of("type", "ops", "ns", "develop"); - new VaultServiceRolesInstaller.Builder() + VaultServiceRolesInstaller.builder() .vaultAddress(vaultEnvironment.vaultAddr()) .vaultTokenSupplier(() -> completedFuture(vaultEnvironment.login())) .keyNameSupplier(() -> "key-" + now) @@ -128,7 +128,7 @@ void testGetServiceTokenSuccessfully(VaultEnvironment vaultEnvironment) throws E .install(); final var serviceTokenSupplier = - new VaultServiceTokenSupplier.Builder() + VaultServiceTokenSupplier.builder() .vaultAddress(vaultEnvironment.vaultAddr()) .vaultTokenSupplier(() -> completedFuture(vaultEnvironment.login())) .serviceRole(serviceRole) @@ -142,7 +142,7 @@ void testGetServiceTokenSuccessfully(VaultEnvironment vaultEnvironment) throws E final var jwtToken = new JsonwebtokenResolver( - new JwksKeyLocator.Builder().jwksUri(vaultEnvironment.jwksUri()).build()) + JwksKeyLocator.builder().jwksUri(vaultEnvironment.jwksUri()).build()) .resolve(serviceToken) .get(3, TimeUnit.SECONDS); diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java index a29ad34..fc3c0fd 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java @@ -47,6 +47,10 @@ private JwksKeyLocator(Builder builder) { this.keyTtl = builder.keyTtl; } + public static Builder builder() { + return new Builder(); + } + @Override protected Key locate(JwsHeader header) { try { @@ -160,6 +164,8 @@ public static class Builder { private Duration requestTimeout = Duration.ofSeconds(10); private int keyTtl = 60 * 1000; + private Builder() {} + /** * Setter for JWKS URI. The JWKS URI typically follows a well-known pattern, such as * https://server_domain/.well-known/jwks.json. This endpoint is a read-only URL that responds diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java index 977d3ab..e876abb 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java @@ -62,6 +62,10 @@ private VaultServiceRolesInstaller(Builder builder) { this.timeUnit = builder.timeUnit; } + public static Builder builder() { + return new Builder(); + } + /** * Builds vault oidc micro-infrastructure (identity roles and keys) to use it for * machine-to-machine authentication. @@ -363,7 +367,7 @@ public static class Builder { private long timeout = 10; private TimeUnit timeUnit = TimeUnit.SECONDS; - public Builder() {} + private Builder() {} public Builder vaultAddress(String vaultAddress) { this.vaultAddress = vaultAddress; diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceTokenSupplier.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceTokenSupplier.java index 1cfcee6..ea35136 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceTokenSupplier.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceTokenSupplier.java @@ -33,6 +33,10 @@ private VaultServiceTokenSupplier(Builder builder) { Objects.requireNonNull(builder.serviceTokenNameBuilder, "serviceTokenNameBuilder"); } + public static Builder builder() { + return new Builder(); + } + /** * Obtains vault service token (aka identity token or oidc token). * @@ -98,7 +102,7 @@ public static class Builder { private Supplier> vaultTokenSupplier; private BiFunction, String> serviceTokenNameBuilder; - public Builder() {} + private Builder() {} /** * Setter for {@code vaultAddress}. From b1a7b7043e3ad95e51155bedebe0cb16afd833c1 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Sat, 8 Mar 2025 12:41:35 +0200 Subject: [PATCH 2/7] Enhanced VaultServiceRolesInstaller --- .../security/vault/VaultServiceRolesInstaller.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java index e876abb..c64c0b6 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java @@ -93,7 +93,7 @@ public void install() { createVaultIdentityKey(rest.url(vaultIdentityKeyUri(keyName)), keyName); for (var role : serviceRoles.roles) { - String roleName = roleNameBuilder.apply(role.role); + final var roleName = roleNameBuilder.apply(role.role); createVaultIdentityRole( rest.url(vaultIdentityRoleUri(roleName)), keyName, @@ -153,7 +153,7 @@ private void createVaultIdentityRole( final byte[] body = Json.object() .add("key", keyName) - .add("template", createTemplate(permissions)) + .add("template", createTemplate(roleName, permissions)) .add("ttl", roleTtl) .toString() .getBytes(); @@ -166,10 +166,14 @@ private void createVaultIdentityRole( } } - private static String createTemplate(List permissions) { + private static String createTemplate(String roleName, List permissions) { return Base64.getUrlEncoder() .encodeToString( - Json.object().add("permissions", String.join(",", permissions)).toString().getBytes()); + Json.object() + .add("role", roleName) + .add("permissions", String.join(",", permissions)) + .toString() + .getBytes()); } private String vaultIdentityKeyUri(String keyName) { From 2d29e2d3b27d9d090a274f82abc292a42085c2e7 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Sat, 8 Mar 2025 15:00:15 +0200 Subject: [PATCH 3/7] Fixed identity-role generation --- .../io/scalecube/security/vault/VaultServiceRolesInstaller.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java index c64c0b6..32ca9f5 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java @@ -97,7 +97,7 @@ public void install() { createVaultIdentityRole( rest.url(vaultIdentityRoleUri(roleName)), keyName, - roleName, + role.role, role.permissions); } From 69a6d4d7322ec513b996d85a8996f82ae424dd1b Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Mon, 10 Mar 2025 09:17:49 +0200 Subject: [PATCH 4/7] Minor changes --- .../security/vault/VaultServiceRolesInstaller.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java index 32ca9f5..95ab81f 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Collections; import java.util.List; @@ -138,7 +139,7 @@ private void createVaultIdentityKey(Rest rest, String keyName) { .add("allowed_client_ids", "*") .add("algorithm", keyAlgorithm) .toString() - .getBytes(); + .getBytes(StandardCharsets.UTF_8); try { awaitSuccess(rest.body(body).post().getStatus()); @@ -156,7 +157,7 @@ private void createVaultIdentityRole( .add("template", createTemplate(roleName, permissions)) .add("ttl", roleTtl) .toString() - .getBytes(); + .getBytes(StandardCharsets.UTF_8); try { awaitSuccess(rest.body(body).post().getStatus()); @@ -173,7 +174,7 @@ private static String createTemplate(String roleName, List permissions) .add("role", roleName) .add("permissions", String.join(",", permissions)) .toString() - .getBytes()); + .getBytes(StandardCharsets.UTF_8)); } private String vaultIdentityKeyUri(String keyName) { From c67535caa544ceaf586af3b3427654f9af2c03a9 Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Tue, 18 Mar 2025 21:46:31 +0200 Subject: [PATCH 5/7] Added constructor validations to prevent NPEs --- .../security/tokens/jwt/JsonwebtokenResolver.java | 3 ++- .../io/scalecube/security/tokens/jwt/JwksKeyLocator.java | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolver.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolver.java index 2108370..60e6489 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolver.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JsonwebtokenResolver.java @@ -3,6 +3,7 @@ import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Locator; import java.security.Key; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +15,7 @@ public class JsonwebtokenResolver implements JwtTokenResolver { private final Locator keyLocator; public JsonwebtokenResolver(Locator keyLocator) { - this.keyLocator = keyLocator; + this.keyLocator = Objects.requireNonNull(keyLocator, "keyLocator"); } @Override diff --git a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java index fc3c0fd..f617e48 100644 --- a/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java +++ b/tokens/src/main/java/io/scalecube/security/tokens/jwt/JwksKeyLocator.java @@ -25,6 +25,7 @@ import java.time.Duration; import java.util.Base64; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -41,9 +42,9 @@ public class JwksKeyLocator extends LocatorAdapter { private final ReentrantLock cleanupLock = new ReentrantLock(); private JwksKeyLocator(Builder builder) { - this.jwksUri = builder.jwksUri; - this.connectTimeout = builder.connectTimeout; - this.requestTimeout = builder.requestTimeout; + this.jwksUri = Objects.requireNonNull(builder.jwksUri, "jwksUri"); + this.connectTimeout = Objects.requireNonNull(builder.connectTimeout, "connectTimeout"); + this.requestTimeout = Objects.requireNonNull(builder.requestTimeout, "requestTimeout"); this.keyTtl = builder.keyTtl; } From 7bba39e788374ccad40b973127269f32d0748b4b Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Tue, 18 Mar 2025 21:58:45 +0200 Subject: [PATCH 6/7] Added constructor validations to prevent NPEs --- .../vault/VaultServiceRolesInstaller.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java index 95ab81f..48109ba 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java @@ -50,15 +50,18 @@ public class VaultServiceRolesInstaller { private final TimeUnit timeUnit; private VaultServiceRolesInstaller(Builder builder) { - this.vaultAddress = builder.vaultAddress; - this.vaultTokenSupplier = builder.vaultTokenSupplier; - this.keyNameSupplier = builder.keyNameSupplier; - this.roleNameBuilder = builder.roleNameBuilder; - this.serviceRolesSources = builder.serviceRolesSources; - this.keyAlgorithm = builder.keyAlgorithm; - this.keyRotationPeriod = builder.keyRotationPeriod; - this.keyVerificationTtl = builder.keyVerificationTtl; - this.roleTtl = builder.roleTtl; + this.vaultAddress = Objects.requireNonNull(builder.vaultAddress, "vaultAddress"); + this.vaultTokenSupplier = + Objects.requireNonNull(builder.vaultTokenSupplier, "vaultTokenSupplier"); + this.keyNameSupplier = Objects.requireNonNull(builder.keyNameSupplier, "keyNameSupplier"); + this.roleNameBuilder = Objects.requireNonNull(builder.roleNameBuilder, "roleNameBuilder"); + this.serviceRolesSources = + Objects.requireNonNull(builder.serviceRolesSources, "serviceRolesSources"); + this.keyAlgorithm = Objects.requireNonNull(builder.keyAlgorithm, "keyAlgorithm"); + this.keyRotationPeriod = Objects.requireNonNull(builder.keyRotationPeriod, "keyRotationPeriod"); + this.keyVerificationTtl = + Objects.requireNonNull(builder.keyVerificationTtl, "keyVerificationTtl"); + this.roleTtl = Objects.requireNonNull(builder.roleTtl, "roleTtl"); this.timeout = builder.timeout; this.timeUnit = builder.timeUnit; } From f3f6278d54924f138985172e87fe02a5f0dfc1ad Mon Sep 17 00:00:00 2001 From: Artem Vysochyn Date: Wed, 9 Apr 2025 08:54:27 +0300 Subject: [PATCH 7/7] Fixed audit logs --- .../security/vault/VaultServiceRolesInstaller.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java index 48109ba..795e2c4 100644 --- a/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java +++ b/vault/src/main/java/io/scalecube/security/vault/VaultServiceRolesInstaller.java @@ -76,13 +76,13 @@ public static Builder builder() { */ public void install() { if (isNullOrNoneOrEmpty(vaultAddress)) { - LOGGER.debug("Skipping serviceRoles installation, vaultAddress not set"); + LOGGER.debug("Skipping service roles installation, vault address not set"); return; } final ServiceRoles serviceRoles = loadServiceRoles(); if (serviceRoles == null || serviceRoles.roles.isEmpty()) { - LOGGER.debug("Skipping serviceRoles installation, serviceRoles not set"); + LOGGER.debug("Skipping service roles installation, service roles not set"); return; } @@ -95,6 +95,7 @@ public void install() { final var keyName = keyNameSupplier.get(); createVaultIdentityKey(rest.url(vaultIdentityKeyUri(keyName)), keyName); + LOGGER.debug("Vault identity key: {}", keyName); for (var role : serviceRoles.roles) { final var roleName = roleNameBuilder.apply(role.role); @@ -103,9 +104,10 @@ public void install() { keyName, role.role, role.permissions); + LOGGER.debug("Vault identity role: {}", roleName); } - LOGGER.debug("Installed serviceRoles ({})", serviceRoles); + LOGGER.debug("Installed service roles: {}", serviceRoles); }) .get(timeout, timeUnit); } catch (Exception e) { @@ -114,10 +116,6 @@ public void install() { } private ServiceRoles loadServiceRoles() { - if (serviceRolesSources == null) { - return null; - } - for (Supplier serviceRolesSource : serviceRolesSources) { final ServiceRoles serviceRoles = serviceRolesSource.get(); if (serviceRoles != null) { @@ -146,7 +144,6 @@ private void createVaultIdentityKey(Rest rest, String keyName) { try { awaitSuccess(rest.body(body).post().getStatus()); - LOGGER.debug("Created vault identity key: {}", keyName); } catch (RestException e) { throw new RuntimeException("Failed to create vault identity key: " + keyName, e); } @@ -164,7 +161,6 @@ private void createVaultIdentityRole( try { awaitSuccess(rest.body(body).post().getStatus()); - LOGGER.debug("Created vault identity role: {}", roleName); } catch (RestException e) { throw new RuntimeException("Failed to create vault identity role: " + roleName, e); }