io.quarkus.vault.runtime.client.VertxVaultClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quarkus-vault Show documentation
Show all versions of quarkus-vault Show documentation
Store your credentials securely in HashiCorp Vault
package io.quarkus.vault.runtime.client;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import static io.quarkus.vault.runtime.client.MutinyVertxClientFactory.createHttpClient;
import static java.util.Collections.emptyMap;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.PreDestroy;
import javax.inject.Singleton;
import org.jboss.logging.Logger;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.runtime.TlsConfig;
import io.quarkus.vault.VaultException;
import io.quarkus.vault.runtime.VaultConfigHolder;
import io.quarkus.vault.runtime.config.VaultBootstrapConfig;
import io.smallrye.mutiny.Uni;
import io.vertx.core.http.HttpMethod;
import io.vertx.mutiny.core.Vertx;
import io.vertx.mutiny.core.buffer.Buffer;
import io.vertx.mutiny.ext.web.client.HttpRequest;
import io.vertx.mutiny.ext.web.client.HttpResponse;
import io.vertx.mutiny.ext.web.client.WebClient;
@Singleton
public class VertxVaultClient implements VaultClient {
private static final Logger log = Logger.getLogger(VertxVaultClient.class);
private static final List ROOT_NAMESPACE_API = Arrays.asList("sys/init", "sys/license", "sys/leader", "sys/health",
"sys/metrics", "sys/config/state", "sys/host-info", "sys/key-status", "sys/storage", "sys/storage/raft");
private final Vertx vertx;
private URL baseUrl;
private final TlsConfig tlsConfig;
private final VaultConfigHolder vaultConfigHolder;
private WebClient webClient;
ObjectMapper mapper = new ObjectMapper();
public VertxVaultClient(VaultConfigHolder vaultConfigHolder, TlsConfig tlsConfig) {
this.vaultConfigHolder = vaultConfigHolder;
this.tlsConfig = tlsConfig;
this.mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
this.mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
this.vertx = Vertx.vertx();
}
public void init() {
VaultBootstrapConfig config = vaultConfigHolder.getVaultBootstrapConfig();
this.webClient = createHttpClient(vertx, config, tlsConfig);
this.baseUrl = config.url.orElseThrow(() -> new VaultException("no vault url provided"));
}
@PreDestroy
@Override
public void close() {
try {
if (webClient != null) {
webClient.close();
}
} finally {
vertx.close();
}
}
// ---
public T put(String path, String token, Object body, int expectedCode) {
HttpRequest request = builder(path, token).method(HttpMethod.PUT);
return exec(request, body, null, expectedCode);
}
public T list(String path, String token, Class resultClass) {
HttpRequest request = builder(path, token).rawMethod("LIST");
return exec(request, resultClass);
}
public T delete(String path, String token, int expectedCode) {
HttpRequest request = builder(path, token).method(HttpMethod.DELETE);
return exec(request, expectedCode);
}
public T post(String path, String token, Object body, Class resultClass, int expectedCode) {
HttpRequest request = builder(path, token).method(HttpMethod.POST);
return exec(request, body, resultClass, expectedCode);
}
public T post(String path, String token, Object body, Class resultClass) {
return post(path, token, emptyMap(), body, resultClass);
}
public T post(String path, String token, Map headers, Object body, Class resultClass) {
HttpRequest request = builder(path, token).method(HttpMethod.POST);
headers.forEach(request::putHeader);
return exec(request, body, resultClass);
}
public T post(String path, String token, Object body, int expectedCode) {
HttpRequest request = builder(path, token).method(HttpMethod.POST);
return exec(request, body, null, expectedCode);
}
public T put(String path, String token, Object body, Class resultClass) {
HttpRequest request = builder(path, token).method(HttpMethod.PUT);
return exec(request, body, resultClass);
}
public T put(String path, Object body, Class resultClass) {
HttpRequest request = builder(path).method(HttpMethod.PUT);
return exec(request, body, resultClass);
}
public T get(String path, String token, Class resultClass) {
HttpRequest request = builder(path, token).method(HttpMethod.GET);
return exec(request, resultClass);
}
public T get(String path, Map queryParams, Class resultClass) {
final HttpRequest request = builder(path, queryParams).method(HttpMethod.GET);
return exec(request, resultClass);
}
public int head(String path) {
final HttpRequest request = builder(path).method(HttpMethod.HEAD);
return exec(request);
}
public int head(String path, Map queryParams) {
final HttpRequest request = builder(path, queryParams).method(HttpMethod.HEAD);
return exec(request);
}
private T exec(HttpRequest request, Class resultClass) {
return exec(request, null, resultClass, 200);
}
private T exec(HttpRequest request, int expectedCode) {
return exec(request, null, null, expectedCode);
}
private T exec(HttpRequest request, Object body, Class resultClass) {
return exec(request, body, resultClass, 200);
}
private T exec(HttpRequest request, Object body, Class resultClass, int expectedCode) {
try {
Uni> uni = body == null ? request.send()
: request.sendBuffer(Buffer.buffer(requestBody(body)));
HttpResponse response = uni.await().atMost(getRequestTimeout());
if (response.statusCode() != expectedCode) {
throwVaultException(response);
}
Buffer responseBuffer = response.body();
if (responseBuffer != null) {
return resultClass == null ? null : mapper.readValue(responseBuffer.toString(), resultClass);
} else {
return null;
}
} catch (JsonProcessingException e) {
throw new VaultException(e);
}
}
private Duration getRequestTimeout() {
return vaultConfigHolder.getVaultBootstrapConfig().readTimeout;
}
private int exec(HttpRequest request) {
return request.send().await().atMost(getRequestTimeout()).statusCode();
}
private void throwVaultException(HttpResponse response) {
String body = null;
try {
body = response.body().toString();
} catch (Exception e) {
// ignore
}
throw new VaultClientException(response.statusCode(), body);
}
private HttpRequest builder(String path, String token) {
HttpRequest request = builder(path);
if (token != null) {
request.putHeader(X_VAULT_TOKEN, token);
}
Optional namespace = vaultConfigHolder.getVaultBootstrapConfig().enterprise.namespace;
if (namespace.isPresent() && !isRootNamespaceAPI(path)) {
request.putHeader(X_VAULT_NAMESPACE, namespace.get());
}
return request;
}
private boolean isRootNamespaceAPI(String path) {
return ROOT_NAMESPACE_API.stream().anyMatch(path::startsWith);
}
private HttpRequest builder(String path) {
return webClient.getAbs(getUrl(path).toString());
}
private HttpRequest builder(String path, Map queryParams) {
HttpRequest request = builder(path);
if (queryParams != null) {
queryParams.forEach(request::addQueryParam);
}
return request;
}
private String requestBody(Object body) {
try {
return mapper.writeValueAsString(body);
} catch (JsonProcessingException e) {
throw new VaultException(e);
}
}
private URL getUrl(String path) {
try {
return new URL(baseUrl, API_VERSION + "/" + path);
} catch (MalformedURLException e) {
throw new VaultException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy