mirror of
https://github.com/valitydev/adapter-common-lib.git
synced 2024-11-06 02:05:18 +00:00
add write method with CAS for vault (#59)
* add write method with CAS for vault * fix review --------- Co-authored-by: ggmaleva <ggmaleva@yandex.ru>
This commit is contained in:
parent
68ec296ea6
commit
7f23818021
2
pom.xml
2
pom.xml
@ -12,7 +12,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>adapter-common-lib</artifactId>
|
||||
<version>1.2.12</version>
|
||||
<version>1.2.13</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>adapter-common-lib</name>
|
||||
|
@ -0,0 +1,10 @@
|
||||
package dev.vality.adapter.common.exception;
|
||||
|
||||
public class SecretAlreadyModifyException extends RuntimeException {
|
||||
|
||||
public static final String CAS_ERROR_MESSAGE = "check-and-set parameter did not match the current version";
|
||||
|
||||
public SecretAlreadyModifyException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
package dev.vality.adapter.common.secret;
|
||||
|
||||
import dev.vality.adapter.common.exception.HexDecodeException;
|
||||
import dev.vality.adapter.common.exception.SecretNotFoundException;
|
||||
import dev.vality.adapter.common.exception.SecretPathNotFoundException;
|
||||
import dev.vality.adapter.common.exception.SecretsNotFoundException;
|
||||
import dev.vality.adapter.common.exception.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -83,4 +80,16 @@ public interface SecretService {
|
||||
*/
|
||||
Integer writeVersionSecret(String serviceName, SecretObj secretObj);
|
||||
|
||||
/**
|
||||
* Сохраняет секреты для терминала, используя CAS (Check-And-Set)
|
||||
*
|
||||
* @param serviceName - имя сервиса, для которого сохраняются секреты. Хранится в настройках сервиса.
|
||||
* @param secretObj - объект с секретами, {@link SecretObj}
|
||||
* @param version - значение текущей версии секретов, которая требует обновления.
|
||||
* @return Возвращает обновленную версию хранилища для терминала
|
||||
* @throws SecretAlreadyModifyException в случае некорректной версии
|
||||
*/
|
||||
Integer writeWithCas(String serviceName, SecretObj secretObj, Integer version)
|
||||
throws SecretAlreadyModifyException;
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
package dev.vality.adapter.common.secret;
|
||||
|
||||
import dev.vality.adapter.common.exception.HexDecodeException;
|
||||
import dev.vality.adapter.common.exception.SecretNotFoundException;
|
||||
import dev.vality.adapter.common.exception.SecretPathNotFoundException;
|
||||
import dev.vality.adapter.common.exception.SecretsNotFoundException;
|
||||
import dev.vality.adapter.common.exception.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.Versioned;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.vality.adapter.common.exception.SecretAlreadyModifyException.CAS_ERROR_MESSAGE;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class VaultSecretService implements SecretService {
|
||||
|
||||
@ -77,6 +78,24 @@ public class VaultSecretService implements SecretService {
|
||||
return metadata.getVersion().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer writeWithCas(String serviceName, SecretObj secretObj, Integer version) {
|
||||
try {
|
||||
var versionedBody = Versioned.create(secretObj.getValues(), Versioned.Version.from(version));
|
||||
var metadata = vaultTemplate.opsForVersionedKeyValue(serviceName).put(secretObj.getPath(), versionedBody);
|
||||
return metadata.getVersion().getVersion();
|
||||
} catch (VaultException e) {
|
||||
if (isCasError(e)) {
|
||||
throw new SecretAlreadyModifyException(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCasError(VaultException e) {
|
||||
return Objects.nonNull(e.getMessage()) && e.getMessage().contains(CAS_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
private String getSecretString(String serviceName, SecretRef secretRef) throws SecretNotFoundException {
|
||||
var map = vaultTemplate.opsForVersionedKeyValue(serviceName).get(secretRef.getPath());
|
||||
if (map == null || map.getData() == null || map.getData().get(secretRef.getKey()) == null) {
|
||||
|
@ -1,9 +1,6 @@
|
||||
package dev.vality.adapter.common.secret;
|
||||
|
||||
import dev.vality.adapter.common.exception.HexDecodeException;
|
||||
import dev.vality.adapter.common.exception.SecretNotFoundException;
|
||||
import dev.vality.adapter.common.exception.SecretPathNotFoundException;
|
||||
import dev.vality.adapter.common.exception.SecretsNotFoundException;
|
||||
import dev.vality.adapter.common.exception.*;
|
||||
import dev.vality.adapter.common.utils.HmacEncryption;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@ -163,4 +160,52 @@ public class VaultSecretServiceTest {
|
||||
assertEquals(TOKEN_VALUE, versionSecrets.getSecretes().get(TOKEN).getValue());
|
||||
assertEquals(TOKEN_EXP_DATE_VALUE, versionSecrets.getSecretes().get(TOKEN_EXP_DATE).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeMultipleWithCasError() {
|
||||
SecretObj secretObj = new SecretObj(
|
||||
TEST_TOKEN_PATH,
|
||||
Map.of(
|
||||
TOKEN, TOKEN_VALUE,
|
||||
TOKEN_EXP_DATE, TOKEN_EXP_DATE_VALUE
|
||||
)
|
||||
);
|
||||
Integer version = vaultService.writeVersionSecret(SERVICE_NAME, secretObj);
|
||||
SecretObj updatedSecretObj = new SecretObj(
|
||||
TEST_TOKEN_PATH,
|
||||
Map.of(
|
||||
TOKEN, TOKEN_VALUE + "refresh",
|
||||
TOKEN_EXP_DATE, TOKEN_EXP_DATE_VALUE
|
||||
)
|
||||
);
|
||||
int wrongVersion = version + 1;
|
||||
|
||||
assertThrows(SecretAlreadyModifyException.class,
|
||||
() -> vaultService.writeWithCas(SERVICE_NAME, updatedSecretObj, wrongVersion));
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeMultipleWithCasSuccess() {
|
||||
SecretObj secretObj = new SecretObj(
|
||||
TEST_TOKEN_PATH,
|
||||
Map.of(
|
||||
TOKEN, TOKEN_VALUE,
|
||||
TOKEN_EXP_DATE, TOKEN_EXP_DATE_VALUE
|
||||
)
|
||||
);
|
||||
Integer version = vaultService.writeVersionSecret(SERVICE_NAME, secretObj);
|
||||
SecretObj updatedSecretObj = new SecretObj(
|
||||
TEST_TOKEN_PATH,
|
||||
Map.of(
|
||||
TOKEN, TOKEN_VALUE + "refresh",
|
||||
TOKEN_EXP_DATE, TOKEN_EXP_DATE_VALUE
|
||||
)
|
||||
);
|
||||
|
||||
Integer newVersion = vaultService.writeWithCas(SERVICE_NAME, updatedSecretObj, version);
|
||||
|
||||
assertNotNull(newVersion);
|
||||
assertEquals(version + 1, newVersion);
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user