diff --git a/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpSimpleSessionManager.java b/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpSimpleSessionManager.java new file mode 100644 index 000000000..fa50f79cb --- /dev/null +++ b/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpSimpleSessionManager.java @@ -0,0 +1,65 @@ +package com.quorum.tessera.key.vault.hashicorp; + +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; +import java.util.concurrent.locks.ReentrantLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.Assert; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.LoginToken; +import org.springframework.vault.authentication.SessionManager; +import org.springframework.vault.support.VaultToken; + +public class HashicorpSimpleSessionManager implements SessionManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(HashicorpSimpleSessionManager.class); + private final ClientAuthentication clientAuthentication; + + private final ReentrantLock lock = new ReentrantLock(); + + private volatile Optional token = Optional.empty(); + private Instant tokenStartTime; + + private final Duration safetyMarginInSeconds = Duration.ofSeconds(5); + + public HashicorpSimpleSessionManager(ClientAuthentication clientAuthentication) { + + Assert.notNull(clientAuthentication, "ClientAuthentication must not be null"); + + this.clientAuthentication = clientAuthentication; + } + + private boolean isTokenEmptyOrExpired() { + if (this.token.isEmpty()) { + return true; + } + if (this.token.get() instanceof LoginToken) { + LoginToken loginToken = (LoginToken) this.token.get(); + Duration ttlAdjusted = loginToken.getLeaseDuration().minus(safetyMarginInSeconds); + return Duration.between(tokenStartTime, Instant.now()).getSeconds() + >= ttlAdjusted.getSeconds(); + } + return false; + } + + @Override + public VaultToken getSessionToken() { + + if (isTokenEmptyOrExpired()) { + this.lock.lock(); + try { + if (isTokenEmptyOrExpired()) { + this.token = Optional.of(this.clientAuthentication.login()); + this.tokenStartTime = Instant.now(); + LOGGER.info("Successfully retrieved new vault token."); + } + } finally { + this.lock.unlock(); + } + } + + return this.token.orElseThrow(() -> new IllegalStateException("Cannot obtain VaultToken")); + } +} diff --git a/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpVaultServiceFactory.java b/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpVaultServiceFactory.java index 2817413cd..00023b0d8 100644 --- a/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpVaultServiceFactory.java +++ b/key-vault/hashicorp-key-vault/src/main/java/com/quorum/tessera/key/vault/hashicorp/HashicorpVaultServiceFactory.java @@ -18,7 +18,6 @@ import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.vault.authentication.ClientAuthentication; import org.springframework.vault.authentication.SessionManager; -import org.springframework.vault.authentication.SimpleSessionManager; import org.springframework.vault.client.RestTemplateBuilder; import org.springframework.vault.client.VaultEndpoint; import org.springframework.vault.core.VaultOperations; @@ -115,7 +114,7 @@ R create( envVarHashicorpSecretId, envVarHashicorpToken); - SessionManager sessionManager = new SimpleSessionManager(clientAuthentication); + SessionManager sessionManager = new HashicorpSimpleSessionManager(clientAuthentication); VaultOperations vaultOperations = getVaultOperations(