diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 1dd83da3..bc21391f 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -17,29 +17,7 @@ jobs:
java:
- 11
vault:
- - 1.1.3
- - 1.9.0
- - 1.9.1
- - 1.9.2
- - 1.9.3
- - 1.9.4
- - 1.9.5
- - 1.9.6
- - 1.9.7
- - 1.9.8
- - 1.9.9
- - 1.9.10
- - 1.10.0
- - 1.10.1
- - 1.10.2
- - 1.10.3
- - 1.10.4
- - 1.10.5
- - 1.10.6
- - 1.10.7
- - 1.10.8
- - 1.10.9
- - 1.10.10
+ - 1.10.11
- 1.11.0
- 1.11.1
- 1.11.2
@@ -48,10 +26,13 @@ jobs:
- 1.11.5
- 1.11.6
- 1.11.7
+ - 1.11.8
- 1.12.0
- 1.12.1
- 1.12.2
- 1.12.3
+ - 1.12.4
+ - 1.13.0
- latest
os:
- ubuntu-latest
@@ -64,9 +45,10 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Set up JDK ${{ matrix.java }}
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
+ distribution: temurin
- name: Build with Gradle
uses: gradle/gradle-build-action@v2
with:
diff --git a/src/main/java/io/github/jopenlibs/vault/Vault.java b/src/main/java/io/github/jopenlibs/vault/Vault.java
index 51efdfdd..649ccfc8 100644
--- a/src/main/java/io/github/jopenlibs/vault/Vault.java
+++ b/src/main/java/io/github/jopenlibs/vault/Vault.java
@@ -2,12 +2,13 @@
import io.github.jopenlibs.vault.api.Auth;
import io.github.jopenlibs.vault.api.Debug;
-import io.github.jopenlibs.vault.api.Leases;
import io.github.jopenlibs.vault.api.Logical;
-import io.github.jopenlibs.vault.api.Seal;
import io.github.jopenlibs.vault.api.database.Database;
-import io.github.jopenlibs.vault.api.mounts.Mounts;
import io.github.jopenlibs.vault.api.pki.Pki;
+import io.github.jopenlibs.vault.api.sys.Leases;
+import io.github.jopenlibs.vault.api.sys.Seal;
+import io.github.jopenlibs.vault.api.sys.Sys;
+import io.github.jopenlibs.vault.api.sys.mounts.Mounts;
import io.github.jopenlibs.vault.json.Json;
import io.github.jopenlibs.vault.json.JsonObject;
import io.github.jopenlibs.vault.json.JsonValue;
@@ -182,6 +183,16 @@ public Auth auth() {
return new Auth(vaultConfig);
}
+ /**
+ * Returns the implementing class for operations on Vault's /v1/sys/* REST
+ * endpoints
+ *
+ * @return The implementing class for Vault's auth operations.
+ */
+ public Sys sys() {
+ return new Sys(vaultConfig);
+ }
+
/**
* Returns the implementing class for Vault's PKI secret backend (i.e. /v1/pki/*
* REST endpoints).
@@ -227,9 +238,8 @@ public Database database(final String mountPath) {
}
/**
- * Returns the implementing class for Vault's lease operations (e.g. revoke, revoke-prefix).
- *
- * @return The implementing class for Vault's lease operations (e.g. revoke, revoke-prefix).
+ * @see Sys#leases()
+ * @deprecated This method is deprecated and in future it will be removed
*/
public Leases leases() {
return new Leases(vaultConfig);
@@ -245,19 +255,16 @@ public Debug debug() {
}
/**
- * Returns the implementing class for Vault's sys mounts operations (i.e.
- * /v1/sys/mounts/* REST endpoints).
- *
- * @return the implementing class for Vault's sys mounts operations
+ * @see Sys#mounts()
+ * @deprecated This method is deprecated and in future it will be removed
*/
public Mounts mounts() {
return new Mounts(vaultConfig);
}
/**
- * Returns the implementing class for Vault's seal operations (e.g. seal, unseal, sealStatus).
- *
- * @return The implementing class for Vault's seal operations (e.g. seal, unseal, sealStatus).
+ * @see Sys#seal()
+ * @deprecated This method is deprecated and in future it will be removed
*/
public Seal seal() {
return new Seal(vaultConfig);
diff --git a/src/main/java/io/github/jopenlibs/vault/api/Auth.java b/src/main/java/io/github/jopenlibs/vault/api/Auth.java
index d9800f38..4949be70 100644
--- a/src/main/java/io/github/jopenlibs/vault/api/Auth.java
+++ b/src/main/java/io/github/jopenlibs/vault/api/Auth.java
@@ -3,6 +3,7 @@
import io.github.jopenlibs.vault.Vault;
import io.github.jopenlibs.vault.VaultConfig;
import io.github.jopenlibs.vault.VaultException;
+import io.github.jopenlibs.vault.api.sys.Sys;
import io.github.jopenlibs.vault.json.Json;
import io.github.jopenlibs.vault.json.JsonObject;
import io.github.jopenlibs.vault.response.AuthResponse;
@@ -16,7 +17,6 @@
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.UUID;
@@ -840,8 +840,9 @@ public AuthResponse loginByAwsEc2(final String role, final String pkcs7, final S
* login fails.
* @param iamRequestUrl PKCS7 signature of the identity document with all \n characters
* removed.Base64-encoded HTTP URL used in the signed request. Most likely just
- * aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8= (base64-encoding of https://sts.amazonaws.com/) as most
- * requests will probably use POST with an empty URI.
+ * aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8= (base64-encoding of https://sts.amazonaws.com/) as most requests will
+ * probably use POST with an empty URI.
* @param iamRequestBody Base64-encoded body of the signed request. Most likely
* QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNQ== which is the base64 encoding of
* Action=GetCallerIdentity&Version=2011-06-15.
@@ -1280,118 +1281,31 @@ public LookupResponse lookupSelf(final String tokenAuthMount) throws VaultExcept
}
/**
- *
Returns information about the current client token for a wrapped token, for which the - * lookup endpoint is at "sys/wrapping/lookup". Example usage:
- * - *
- * {@code
- * final String wrappingToken = "...";
- * final VaultConfig config = new VaultConfig().address(...).token(wrappingToken).build();
- * final Vault vault = new Vault(config);
- * final LogicalResponse response = vault.auth().lookupWarp();
- * // Then you can validate "path" for example ...
- * final String path = response.getData().get("path");
- * }
- *
- *
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#lookupWrap()
+ * @deprecated This method is deprecated and in future it will be removed
*/
public LogicalResponse lookupWrap() throws VaultException {
- return lookupWrap(config.getToken(), false);
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().lookupWrap(config.getToken(), false);
}
/**
- * Returns information about the a wrapped token when authorization is needed for lookup, - * for which the lookup endpoint is at "sys/wrapping/lookup". Example usage:
- * - *
- * {@code
- * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
- * final Vault vault = new Vault(config);
- * ...
- * final String wrappingToken = "...";
- * final LogicalResponse response = vault.auth().lookupWarp(wrappingToken);
- * // Then you can validate "path" for example ...
- * final String path = response.getData().get("path");
- * }
- *
- *
- * @param wrappedToken Wrapped token.
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#lookupWrap(String)
+ * @deprecated This method is deprecated and in future it will be removed
*/
public LogicalResponse lookupWrap(final String wrappedToken) throws VaultException {
- return lookupWrap(wrappedToken, true);
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().lookupWrap(wrappedToken, true);
}
/**
- * Returns information about the a wrapped token, - * for which the lookup endpoint is at "sys/wrapping/lookup". Example usage:
- * - *
- * {@code
- * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
- * final Vault vault = new Vault(config);
- * ...
- * final String wrappingToken = "...";
- * final LogicalResponse response = vault.auth().lookupWarp(wrappingToken);
- * // Then you can validate "path" for example ...
- * final String path = response.getData().get("path");
- * }
- *
- *
- * @param wrappedToken Wrapped token.
- * @param inBody When {@code true} the token value placed in the body request:
- * {@code {"token": "$wrappedToken"}}, otherwise, set the token into header:
- * {@code "X-Vault-Token: $wrappedToken"}.
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#lookupWrap(String, boolean)
+ * @deprecated This method is deprecated and in future it will be removed
*/
public LogicalResponse lookupWrap(final String wrappedToken, boolean inBody)
throws VaultException {
- final String requestJson =
- inBody ? Json.object().add("token", wrappedToken).toString() : null;
-
- return retry(attempt -> {
- // HTTP request to Vault
- Rest rest = new Rest()//NOPMD
- .url(config.getAddress() + "/v1/sys/wrapping/lookup")
- .header("X-Vault-Namespace", this.nameSpace)
- .header("X-Vault-Request", "true")
- .connectTimeoutSeconds(config.getOpenTimeout())
- .readTimeoutSeconds(config.getReadTimeout())
- .sslVerification(config.getSslConfig().isVerify())
- .sslContext(config.getSslConfig().getSslContext());
-
- if (inBody) {
- rest = rest
- .header("X-Vault-Token", config.getToken())
- .body(requestJson.getBytes(StandardCharsets.UTF_8));
- } else {
- rest = rest.header("X-Vault-Token", wrappedToken);
- }
-
- final RestResponse restResponse = rest.post();
-
- // Validate restResponse
- if (restResponse.getStatus() != 200) {
- throw new VaultException(
- "Vault responded with HTTP status code: " + restResponse.getStatus() +
- "\nResponse body: " + new String(restResponse.getBody(),
- StandardCharsets.UTF_8),
- restResponse.getStatus());
- }
-
- final String mimeType = restResponse.getMimeType();
- if (!"application/json".equals(mimeType)) {
- throw new VaultException("Vault responded with MIME type: " + mimeType,
- restResponse.getStatus());
- }
-
- return new LogicalResponse(restResponse, attempt,
- Logical.logicalOperations.authentication);
- });
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().lookupWrap(wrappedToken, inBody);
}
/**
@@ -1440,356 +1354,47 @@ public void revokeSelf(final String tokenAuthMount) throws VaultException {
}
/**
- * Returns the original response inside the wrapped auth token. This method is useful if you - * need to unwrap a token without being authenticated. See {@link #unwrap(String)} if you need - * to do that authenticated.
- * - *In the example below, you cannot use twice the {@code VaultConfig}, since - * after the first usage of the {@code wrappingToken}, it is not usable anymore. You need to use - * the {@code unwrappedToken} in a new vault configuration to continue. Example usage:
- * - *
- * {@code
- * final String wrappingToken = "...";
- * final VaultConfig config = new VaultConfig().address(...).token(wrappingToken).build();
- * final Vault vault = new Vault(config);
- * final AuthResponse response = vault.auth().unwrap();
- * final String unwrappedToken = response.getAuthClientToken();
- * }
- *
- *
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
- * @see #unwrap(String)
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#unwrap()
+ * @deprecated This method is deprecated and in future it will be removed
*/
public UnwrapResponse unwrap() throws VaultException {
- return unwrap(config.getToken(), false);
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().unwrap(config.getToken(), false);
}
/**
- * Provide access to the {@code /sys/wrapping/unwrap} endpoint.
- * - *Returns the original response inside the given wrapping token. Unlike simply reading - * {@code cubbyhole/response} (which is deprecated), this endpoint provides additional - * validation checks on the token, returns the original value on the wire rather than a JSON - * string representation of it, and ensures that the response is properly audit-logged.
- * - *This endpoint can be used by using a wrapping token as the client token in the API call, - * in which case the token parameter is not required; or, a different token with permissions to - * access this endpoint can make the call and pass in the wrapping token in the token parameter. - * Do not use the wrapping token in both locations; this will cause the wrapping token to be - * revoked but the value to be unable to be looked up, as it will basically be a double-use of - * the token!
- * - *In the example below, {@code authToken} is NOT your wrapped token, and should have - * unwrapping permissions. The unwrapped data in {@link UnwrapResponse#getData()}. Example - * usage:
- * - *
- * {@code
- * final String authToken = "...";
- * final String wrappingToken = "...";
- * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
- * final Vault vault = new Vault(config);
- *
- * final WrapResponse wrapResponse = vault.auth().wrap(
- * // Data to wrap
- * new JsonObject()
- * .add("foo", "bar")
- * .add("zoo", "zar"),
- *
- * // TTL of the response-wrapping token
- * 60
- * );
- *
- * final UnwrapResponse unwrapResponse = vault.auth().unwrap(wrapResponse.getToken());
- * final JsonObject unwrappedData = response.getData(); // original data
- * }
- *
- *
- * @param wrappedToken Specifies the wrapping token ID, do NOT also put this in your
- * {@link VaultConfig#getToken()}, if token is {@code null}, this method will unwrap the auth
- * token in {@link VaultConfig#getToken()}
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
- * @see #wrap(JsonObject, int)
- * @see #unwrap()
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#unwrap(String)
+ * @deprecated This method is deprecated and in future it will be removed
*/
public UnwrapResponse unwrap(final String wrappedToken) throws VaultException {
- return unwrap(wrappedToken, true);
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().unwrap(wrappedToken, true);
}
/**
- * Provide access to the {@code /sys/wrapping/unwrap} endpoint.
- * - *Returns the original response inside the given wrapping token. Unlike simply reading - * {@code cubbyhole/response} (which is deprecated), this endpoint provides additional - * validation checks on the token, returns the original value on the wire rather than a JSON - * string representation of it, and ensures that the response is properly audit-logged.
- * - *This endpoint can be used by using a wrapping token as the client token in the API call, - * in which case the token parameter is not required; or, a different token with permissions to - * access this endpoint can make the call and pass in the wrapping token in the token parameter. - * Do not use the wrapping token in both locations; this will cause the wrapping token to be - * revoked but the value to be unable to be looked up, as it will basically be a double-use of - * the token!
- * - *In the example below, {@code authToken} is NOT your wrapped token, and should have - * unwrapping permissions. The unwrapped data in {@link UnwrapResponse#getData()}. Example - * usage:
- * - *
- * {@code
- * final String authToken = "...";
- * final String wrappingToken = "...";
- * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
- * final Vault vault = new Vault(config);
- *
- * final WrapResponse wrapResponse = vault.auth().wrap(
- * // Data to wrap
- * new JsonObject()
- * .add("foo", "bar")
- * .add("zoo", "zar"),
- *
- * // TTL of the response-wrapping token
- * 60
- * );
- *
- * final UnwrapResponse unwrapResponse = vault.auth().unwrap(wrapResponse.getToken(), true);
- * final JsonObject unwrappedData = response.getData(); // original data
- * }
- *
- *
- * @param wrappedToken Specifies the wrapping token ID, do NOT also put this in your
- * {@link VaultConfig#getToken()}, if token is {@code null}, this method will unwrap the auth
- * token in {@link VaultConfig#getToken()}
- * @param inBody When {@code true} the token value placed in the body request:
- * {@code {"token": "$wrappedToken"}}, otherwise, set the token into header:
- * {@code "X-Vault-Token: $wrappedToken"}.
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
- * @see #wrap(JsonObject, int)
- * @see #unwrap()
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#unwrap(String, boolean)
+ * @deprecated This method is deprecated and in future it will be removed
*/
public UnwrapResponse unwrap(final String wrappedToken, boolean inBody) throws VaultException {
- Objects.requireNonNull(wrappedToken, "Wrapped token is null");
-
- return retry(attempt -> {
- final String url = config.getAddress() + "/v1/sys/wrapping/unwrap";
-
- // HTTP request to Vault
- Rest rest = new Rest()
- .url(url)
- .header("X-Vault-Namespace", this.nameSpace)
- .header("X-Vault-Request", "true")
- .connectTimeoutSeconds(config.getOpenTimeout())
- .readTimeoutSeconds(config.getReadTimeout())
- .sslVerification(config.getSslConfig().isVerify())
- .sslContext(config.getSslConfig().getSslContext());
-
- if (inBody) {
- final String requestJson = Json.object().add("token", wrappedToken).toString();
- rest = rest
- .header("X-Vault-Token", config.getToken())
- .body(requestJson.getBytes(StandardCharsets.UTF_8));
- } else {
- rest = rest
- .header("X-Vault-Token", wrappedToken);
- }
-
- RestResponse restResponse = rest.post();
-
- // Validate restResponse
- if (restResponse.getStatus() != 200) {
- throw new VaultException(
- "Vault responded with HTTP status code: " + restResponse.getStatus()
- + "\nResponse body: " + new String(restResponse.getBody(),
- StandardCharsets.UTF_8),
- restResponse.getStatus());
- }
-
- final String mimeType =
- restResponse.getMimeType() == null ? "null" : restResponse.getMimeType();
-
- if (!mimeType.equals("application/json")) {
- throw new VaultException("Vault responded with MIME type: " + mimeType,
- restResponse.getStatus());
- }
-
- return new UnwrapResponse(restResponse, attempt);
- });
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().unwrap(wrappedToken, inBody);
}
/**
- * Provide access to the {@code /sys/wrapping/wrap} endpoint.
- * - *This provides a powerful mechanism for information sharing in many environments. - * In the types of scenarios, often the best practical option is to provide cover for the secret - * information, be able to detect malfeasance (interception, tampering), and limit lifetime of - * the secret's exposure. Response wrapping performs all three of these duties:
- * - *
- * {@code
- * final String authToken = "...";
- * final String wrappingToken = "...";
- * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
- * final Vault vault = new Vault(config);
- *
- * final WrapResponse wrapResponse = vault.auth().wrap(
- * // Data to wrap
- * new JsonObject()
- * .add("foo", "bar")
- * .add("zoo", "zar"),
- *
- * // TTL of the response-wrapping token
- * 60
- * );
- *
- * final UnwrapResponse unwrapResponse = vault.auth().unwrap(wrapResponse.getToken());
- * final JsonObject unwrappedData = response.getData(); // original data
- * }
- *
- *
- * @param jsonObject User data to wrap.
- * @param ttlInSec Wrap TTL in seconds
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
- * @see #unwrap(String)
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#wrap(JsonObject, int)
+ * @deprecated This method is deprecated and in future it will be removed
*/
public WrapResponse wrap(final JsonObject jsonObject, int ttlInSec) throws VaultException {
- Objects.requireNonNull(jsonObject);
-
- return retry(attempt -> {
- // Parse parameters to JSON
- final String requestJson = jsonObject.toString();
- final String url = config.getAddress() + "/v1/sys/wrapping/wrap";
-
- // HTTP request to Vault
- final RestResponse restResponse = new Rest()
- .url(url)
- .header("X-Vault-Token", config.getToken())
- .header("X-Vault-Wrap-TTL", Integer.toString(ttlInSec))
- .header("X-Vault-Namespace", this.nameSpace)
- .header("X-Vault-Request", "true")
- .body(requestJson.getBytes(StandardCharsets.UTF_8))
- .connectTimeoutSeconds(config.getOpenTimeout())
- .readTimeoutSeconds(config.getReadTimeout())
- .sslVerification(config.getSslConfig().isVerify())
- .sslContext(config.getSslConfig().getSslContext())
- .post();
-
- // Validate restResponse
- if (restResponse.getStatus() != 200) {
- throw new VaultException(
- "Vault responded with HTTP status code: " + restResponse.getStatus()
- + "\nResponse body: " + new String(restResponse.getBody(),
- StandardCharsets.UTF_8),
- restResponse.getStatus());
- }
-
- final String mimeType =
- restResponse.getMimeType() == null ? "null" : restResponse.getMimeType();
- if (!mimeType.equals("application/json")) {
- throw new VaultException("Vault responded with MIME type: " + mimeType,
- restResponse.getStatus());
- }
-
- return new WrapResponse(restResponse, attempt);
- });
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().wrap(jsonObject, ttlInSec);
}
/**
- * Provide access to the {@code /sys/wrapping/rewrap} endpoint. This endpoint rewraps a - * response-wrapped token. The new token will use the same creation TTL as the original token - * and contain the same response. The old token will be invalidated. This can be used for - * long-term storage of a secret in a response-wrapped token when rotation is a - * requirement.
- * - *
- * {@code
- * final String authToken = "...";
- * final String wrappingToken = "...";
- * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
- * final Vault vault = new Vault(config);
- *
- * final WrapResponse wrapResponse = vault.auth().wrap(
- * // Data to wrap
- * new JsonObject()
- * .add("foo", "bar")
- * .add("zoo", "zar"),
- *
- * // TTL of the response-wrapping token
- * 60
- * );
- * ...
- * final WrapResponse wrapResponse2 = vault.auth().rewrap(wrapResponse.getToken());
- *
- * final UnwrapResponse unwrapResponse = vault.auth().unwrap(wrapResponse2.getToken());
- * final JsonObject unwrappedData = response.getData(); // original data
- * }
- *
- *
- * @param wrappedToken Wrapped token ID to re-wrap.
- * @return The response information returned from Vault
- * @throws VaultException If any error occurs, or unexpected response received from Vault
- * @see #wrap(JsonObject, int)
+ * @see io.github.jopenlibs.vault.api.sys.Wrapping#rewrap(String)
+ * @deprecated This method is deprecated and in future it will be removed
*/
public WrapResponse rewrap(final String wrappedToken) throws VaultException {
- Objects.requireNonNull(wrappedToken);
-
- return retry(attempt -> {
- // Parse parameters to JSON
- final String requestJson = Json.object().add("token", wrappedToken).toString();
- final String url = config.getAddress() + "/v1/sys/wrapping/rewrap";
-
- // HTTP request to Vault
- final RestResponse restResponse = new Rest()
- .url(url)
-// .header("X-Vault-Token", wrappedToken)
- .header("X-Vault-Token", config.getToken())
- .header("X-Vault-Namespace", this.nameSpace)
- .header("X-Vault-Request", "true")
- .body(requestJson.getBytes(StandardCharsets.UTF_8))
- .connectTimeoutSeconds(config.getOpenTimeout())
- .readTimeoutSeconds(config.getReadTimeout())
- .sslVerification(config.getSslConfig().isVerify())
- .sslContext(config.getSslConfig().getSslContext())
- .post();
-
- // Validate restResponse
- if (restResponse.getStatus() != 200) {
- throw new VaultException(
- "Vault responded with HTTP status code: " + restResponse.getStatus()
- + "\nResponse body: " + new String(restResponse.getBody(),
- StandardCharsets.UTF_8),
- restResponse.getStatus());
- }
-
- final String mimeType =
- restResponse.getMimeType() == null ? "null" : restResponse.getMimeType();
- if (!mimeType.equals("application/json")) {
- throw new VaultException("Vault responded with MIME type: " + mimeType,
- restResponse.getStatus());
- }
-
- return new WrapResponse(restResponse, attempt);
- });
+ Sys sys = new Sys(this.config);
+ return sys.wrapping().rewrap(wrappedToken);
}
}
diff --git a/src/main/java/io/github/jopenlibs/vault/api/Seal.java b/src/main/java/io/github/jopenlibs/vault/api/Seal.java
deleted file mode 100644
index fa016e64..00000000
--- a/src/main/java/io/github/jopenlibs/vault/api/Seal.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package io.github.jopenlibs.vault.api;
-
-import io.github.jopenlibs.vault.VaultConfig;
-import io.github.jopenlibs.vault.VaultException;
-import io.github.jopenlibs.vault.json.Json;
-import io.github.jopenlibs.vault.response.SealResponse;
-import io.github.jopenlibs.vault.rest.Rest;
-import io.github.jopenlibs.vault.rest.RestResponse;
-import java.nio.charset.StandardCharsets;
-
-/**
- * The implementing class for operations on REST endpoints, under the "seal/unseal/seal-status" - * section of the Vault HTTP API docs (https://www.vaultproject.io/api/system/index.html).
- * - *This class is not intended to be constructed directly. Rather, it is meant to used by way of
- * Vault in a DSL-style builder pattern. See the Javadoc comments of each
- * public method for usage examples.
Seal the Vault.
- * - * @throws VaultException If any error occurs, or unexpected response received from Vault - */ - public void seal() throws VaultException { - int retryCount = 0; - while (true) { - try { - // HTTP request to Vault - final RestResponse restResponse = new Rest()//NOPMD - .url(config.getAddress() + "/v1/sys/seal") - .header("X-Vault-Token", config.getToken()) - .header("X-Vault-Namespace", this.nameSpace) - .header("X-Vault-Request", "true") - .connectTimeoutSeconds(config.getOpenTimeout()) - .readTimeoutSeconds(config.getReadTimeout()) - .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()) - .post(); - - // Validate restResponse - if (restResponse.getStatus() != 204) { - throw new VaultException( - "Vault responded with HTTP status code: " + restResponse.getStatus(), - restResponse.getStatus()); - } - return; - } catch (Exception e) { - // If there are retries to perform, then pause for the configured interval and then execute the loop again... - if (retryCount < config.getMaxRetries()) { - retryCount++; - try { - final int retryIntervalMilliseconds = config.getRetryIntervalMilliseconds(); - Thread.sleep(retryIntervalMilliseconds); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - } else if (e instanceof VaultException) { - // ... otherwise, give up. - throw (VaultException) e; - } else { - throw new VaultException(e); - } - } - } - } - - /** - *Enter a single master key share to progress the unsealing of the Vault.
- * - * @param key Single master key share - * @return The response information returned from Vault - * @throws VaultException If any error occurs, or unexpected response received from Vault - */ - public SealResponse unseal(final String key) throws VaultException { - return unseal(key, false); - } - - - /** - *Enter a single master key share to progress the unsealing of the Vault.
- * - * @param key Single master key share - * @param reset Specifies if previously-provided unseal keys are discarded and the unseal - * process is reset - * @return The response information returned from Vault - * @throws VaultException If any error occurs, or unexpected response received from Vault - */ - public SealResponse unseal(final String key, final Boolean reset) throws VaultException { - int retryCount = 0; - while (true) { - try { - // HTTP request to Vault - final String requestJson = Json.object().add("key", key).add("reset", reset) - .toString(); - final RestResponse restResponse = new Rest()//NOPMD - .url(config.getAddress() + "/v1/sys/unseal") - .header("X-Vault-Namespace", this.nameSpace) - .header("X-Vault-Request", "true") - .body(requestJson.getBytes(StandardCharsets.UTF_8)) - .connectTimeoutSeconds(config.getOpenTimeout()) - .readTimeoutSeconds(config.getReadTimeout()) - .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()) - .post(); - - // Validate restResponse - return getSealResponse(retryCount, restResponse); - } catch (Exception e) { - // If there are retries to perform, then pause for the configured interval and then execute the loop again... - if (retryCount < config.getMaxRetries()) { - retryCount++; - try { - final int retryIntervalMilliseconds = config.getRetryIntervalMilliseconds(); - Thread.sleep(retryIntervalMilliseconds); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - } else if (e instanceof VaultException) { - // ... otherwise, give up. - throw (VaultException) e; - } else { - throw new VaultException(e); - } - } - } - } - - /** - *Check progress of unsealing the Vault.
- * - * @return The response information returned from Vault - * @throws VaultException If any error occurs, or unexpected response received from Vault - */ - public SealResponse sealStatus() throws VaultException { - int retryCount = 0; - while (true) { - try { - // HTTP request to Vault - final RestResponse restResponse = new Rest()//NOPMD - .url(config.getAddress() + "/v1/sys/seal-status") - .header("X-Vault-Namespace", this.nameSpace) - .header("X-Vault-Request", "true") - .connectTimeoutSeconds(config.getOpenTimeout()) - .readTimeoutSeconds(config.getReadTimeout()) - .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()) - .get(); - - // Validate restResponse - return getSealResponse(retryCount, restResponse); - } catch (Exception e) { - // If there are retries to perform, then pause for the configured interval and then execute the loop again... - if (retryCount < config.getMaxRetries()) { - retryCount++; - try { - final int retryIntervalMilliseconds = config.getRetryIntervalMilliseconds(); - Thread.sleep(retryIntervalMilliseconds); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - } else if (e instanceof VaultException) { - // ... otherwise, give up. - throw (VaultException) e; - } else { - throw new VaultException(e); - } - } - } - } - - private SealResponse getSealResponse(final int retryCount, final RestResponse restResponse) - throws VaultException { - if (restResponse.getStatus() != 200) { - throw new VaultException( - "Vault responded with HTTP status code: " + restResponse.getStatus(), - restResponse.getStatus()); - } - final String mimeType = - restResponse.getMimeType() == null ? "null" : restResponse.getMimeType(); - if (!mimeType.equals("application/json")) { - throw new VaultException("Vault responded with MIME type: " + mimeType, - restResponse.getStatus()); - } - return new SealResponse(restResponse, retryCount); - } -} diff --git a/src/main/java/io/github/jopenlibs/vault/api/Leases.java b/src/main/java/io/github/jopenlibs/vault/api/sys/Leases.java similarity index 99% rename from src/main/java/io/github/jopenlibs/vault/api/Leases.java rename to src/main/java/io/github/jopenlibs/vault/api/sys/Leases.java index 12b85013..30aa71d8 100644 --- a/src/main/java/io/github/jopenlibs/vault/api/Leases.java +++ b/src/main/java/io/github/jopenlibs/vault/api/sys/Leases.java @@ -1,7 +1,8 @@ -package io.github.jopenlibs.vault.api; +package io.github.jopenlibs.vault.api.sys; import io.github.jopenlibs.vault.VaultConfig; import io.github.jopenlibs.vault.VaultException; +import io.github.jopenlibs.vault.api.OperationsBase; import io.github.jopenlibs.vault.json.Json; import io.github.jopenlibs.vault.response.VaultResponse; import io.github.jopenlibs.vault.rest.Rest; diff --git a/src/main/java/io/github/jopenlibs/vault/api/sys/Seal.java b/src/main/java/io/github/jopenlibs/vault/api/sys/Seal.java new file mode 100644 index 00000000..0f4d92e5 --- /dev/null +++ b/src/main/java/io/github/jopenlibs/vault/api/sys/Seal.java @@ -0,0 +1,144 @@ +package io.github.jopenlibs.vault.api.sys; + +import io.github.jopenlibs.vault.VaultConfig; +import io.github.jopenlibs.vault.VaultException; +import io.github.jopenlibs.vault.api.OperationsBase; +import io.github.jopenlibs.vault.json.Json; +import io.github.jopenlibs.vault.response.SealResponse; +import io.github.jopenlibs.vault.rest.Rest; +import io.github.jopenlibs.vault.rest.RestResponse; +import java.nio.charset.StandardCharsets; + +/** + *The implementing class for operations on REST endpoints, under the "seal/unseal/seal-status" + * section of the Vault HTTP API docs (https://www.vaultproject.io/api/system/index.html). + *
+ * + *This class is not intended to be constructed directly. Rather, it is meant to used by way of
+ * Vault in a DSL-style builder pattern. See the Javadoc comments of each
+ * public method for usage examples.
Seal the Vault.
+ * + * @return The response information returned from Vault + * @throws VaultException If any error occurs, or unexpected response received from Vault + */ + public SealResponse seal() throws VaultException { + return retry((attempt) -> { + // HTTP request to Vault + final RestResponse restResponse = new Rest()//NOPMD + .url(config.getAddress() + "/v1/sys/seal") + .header("X-Vault-Token", config.getToken()) + .header("X-Vault-Namespace", this.nameSpace) + .header("X-Vault-Request", "true") + .connectTimeoutSeconds(config.getOpenTimeout()) + .readTimeoutSeconds(config.getReadTimeout()) + .sslVerification(config.getSslConfig().isVerify()) + .sslContext(config.getSslConfig().getSslContext()) + .post(); + + return getSealResponse(attempt, restResponse, 204); + }); + } + + /** + *Enter a single master key share to progress the unsealing of the Vault.
+ * + * @param key Single master key share + * @return The response information returned from Vault + * @throws VaultException If any error occurs, or unexpected response received from Vault + */ + public SealResponse unseal(final String key) throws VaultException { + return unseal(key, false); + } + + + /** + *Enter a single master key share to progress the unsealing of the Vault.
+ * + * @param key Single master key share + * @param reset Specifies if previously-provided unseal keys are discarded and the unseal + * process is reset + * @return The response information returned from Vault + * @throws VaultException If any error occurs, or unexpected response received from Vault + */ + public SealResponse unseal(final String key, final Boolean reset) throws VaultException { + return retry((attempt) -> { + // HTTP request to Vault + final String requestJson = Json.object().add("key", key).add("reset", reset) + .toString(); + final RestResponse restResponse = new Rest()//NOPMD + .url(config.getAddress() + "/v1/sys/unseal") + .header("X-Vault-Namespace", this.nameSpace) + .header("X-Vault-Request", "true") + .body(requestJson.getBytes(StandardCharsets.UTF_8)) + .connectTimeoutSeconds(config.getOpenTimeout()) + .readTimeoutSeconds(config.getReadTimeout()) + .sslVerification(config.getSslConfig().isVerify()) + .sslContext(config.getSslConfig().getSslContext()) + .post(); + + // Validate restResponse + return getSealResponse(attempt, restResponse, 200); + }); + } + + /** + *Check progress of unsealing the Vault.
+ * + * @return The response information returned from Vault + * @throws VaultException If any error occurs, or unexpected response received from Vault + */ + public SealResponse sealStatus() throws VaultException { + return retry((attempt) -> { + // HTTP request to Vault + final RestResponse restResponse = new Rest()//NOPMD + .url(config.getAddress() + "/v1/sys/seal-status") + .header("X-Vault-Namespace", this.nameSpace) + .header("X-Vault-Request", "true") + .connectTimeoutSeconds(config.getOpenTimeout()) + .readTimeoutSeconds(config.getReadTimeout()) + .sslVerification(config.getSslConfig().isVerify()) + .sslContext(config.getSslConfig().getSslContext()) + .get(); + + // Validate restResponse + return getSealResponse(attempt, restResponse, 200); + }); + } + + private SealResponse getSealResponse(final int retryCount, final RestResponse restResponse, + final int expectedResponse) throws VaultException { + if (restResponse.getStatus() != expectedResponse) { + throw new VaultException( + "Vault responded with HTTP status code: " + restResponse.getStatus(), + restResponse.getStatus()); + } + + final String mimeType = String.valueOf(restResponse.getMimeType()); + if (!mimeType.equals("application/json")) { + throw new VaultException("Vault responded with MIME type: " + mimeType, + restResponse.getStatus()); + } + return new SealResponse(restResponse, retryCount); + } +} diff --git a/src/main/java/io/github/jopenlibs/vault/api/sys/Sys.java b/src/main/java/io/github/jopenlibs/vault/api/sys/Sys.java new file mode 100644 index 00000000..f18f5317 --- /dev/null +++ b/src/main/java/io/github/jopenlibs/vault/api/sys/Sys.java @@ -0,0 +1,71 @@ +package io.github.jopenlibs.vault.api.sys; + +import io.github.jopenlibs.vault.Vault; +import io.github.jopenlibs.vault.VaultConfig; +import io.github.jopenlibs.vault.api.OperationsBase; +import io.github.jopenlibs.vault.api.sys.mounts.Mounts; + +/** + *The implementing class for operations on Vault's /v1/sys/* REST endpoints.
This class is not intended to be constructed directly. Rather, it is meant to used by way of
+ * Vault in a DSL-style builder pattern. See the Javadoc comments of each
+ * public method for usage examples.
/v1/sys/wrapping/* REST endpoints
+ *
+ * @return The implementing class for wrapping operations
+ */
+ public Wrapping wrapping() {
+ return new Wrapping(this.config);
+ }
+
+ /**
+ * Returns the implementing class for Vault's seal operations (e.g. seal, unseal, sealStatus).
+ *
+ * @return The implementing class for Vault's seal operations (e.g. seal, unseal, sealStatus).
+ */
+ public Seal seal() {
+ return new Seal(this.config);
+ }
+
+ /**
+ * Returns the implementing class for Vault's sys mounts operations (i.e.
+ * /v1/sys/mounts/* REST endpoints).
+ *
+ * @return the implementing class for Vault's sys mounts operations
+ */
+ public Mounts mounts() {
+ return new Mounts(this.config);
+ }
+
+ /**
+ * Returns the implementing class for Vault's lease operations /v1/sys/leases/*
+ * REST endpoints).
+ *
+ * @return The implementing class for Vault's lease operations
+ */
+ public Leases leases() {
+ return new Leases(this.config);
+ }
+}
diff --git a/src/main/java/io/github/jopenlibs/vault/api/sys/Wrapping.java b/src/main/java/io/github/jopenlibs/vault/api/sys/Wrapping.java
new file mode 100644
index 00000000..08ff1fd9
--- /dev/null
+++ b/src/main/java/io/github/jopenlibs/vault/api/sys/Wrapping.java
@@ -0,0 +1,505 @@
+package io.github.jopenlibs.vault.api.sys;
+
+import io.github.jopenlibs.vault.VaultConfig;
+import io.github.jopenlibs.vault.VaultException;
+import io.github.jopenlibs.vault.api.Logical;
+import io.github.jopenlibs.vault.api.OperationsBase;
+import io.github.jopenlibs.vault.json.Json;
+import io.github.jopenlibs.vault.json.JsonObject;
+import io.github.jopenlibs.vault.response.LogicalResponse;
+import io.github.jopenlibs.vault.response.UnwrapResponse;
+import io.github.jopenlibs.vault.response.WrapResponse;
+import io.github.jopenlibs.vault.rest.Rest;
+import io.github.jopenlibs.vault.rest.RestResponse;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+/**
+ * The implementing class for /v1/sys/wrapping/* REST endpoints
This class is not intended to be constructed directly. Rather, it is meant to used by way of
+ * Vault in a DSL-style builder pattern. See the Javadoc comments of each
+ * public method for usage examples.
Returns information about the current client token for a wrapped token, for which the + * lookup endpoint is at "sys/wrapping/lookup". Example usage:
+ * + *
+ * {@code
+ * final String wrappingToken = "...";
+ * final VaultConfig config = new VaultConfig().address(...).token(wrappingToken).build();
+ * final Vault vault = new Vault(config);
+ * final LogicalResponse response = vault.sys().wrapping().lookupWarp();
+ * // Then you can validate "path" for example ...
+ * final String path = response.getData().get("path");
+ * }
+ *
+ *
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ */
+ public LogicalResponse lookupWrap() throws VaultException {
+ return lookupWrap(config.getToken(), false);
+ }
+
+ /**
+ * Returns information about the a wrapped token when authorization is needed for lookup, + * for which the lookup endpoint is at "sys/wrapping/lookup". Example usage:
+ * + *
+ * {@code
+ * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
+ * final Vault vault = new Vault(config);
+ * ...
+ * final String wrappingToken = "...";
+ * final LogicalResponse response = vault.sys().wrapping().lookupWarp(wrappingToken);
+ * // Then you can validate "path" for example ...
+ * final String path = response.getData().get("path");
+ * }
+ *
+ *
+ * @param wrappedToken Wrapped token.
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ */
+ public LogicalResponse lookupWrap(final String wrappedToken) throws VaultException {
+ return lookupWrap(wrappedToken, true);
+ }
+
+ /**
+ * Returns information about the a wrapped token, + * for which the lookup endpoint is at "sys/wrapping/lookup". Example usage:
+ * + *
+ * {@code
+ * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
+ * final Vault vault = new Vault(config);
+ * ...
+ * final String wrappingToken = "...";
+ * final LogicalResponse response = vault.sys().wrapping().lookupWarp(wrappingToken);
+ * // Then you can validate "path" for example ...
+ * final String path = response.getData().get("path");
+ * }
+ *
+ *
+ * @param wrappedToken Wrapped token.
+ * @param inBody When {@code true} the token value placed in the body request:
+ * {@code {"token": "$wrappedToken"}}, otherwise, set the token into header:
+ * {@code "X-Vault-Token: $wrappedToken"}.
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ */
+ public LogicalResponse lookupWrap(final String wrappedToken, boolean inBody)
+ throws VaultException {
+ final String requestJson =
+ inBody ? Json.object().add("token", wrappedToken).toString() : null;
+
+ return retry(attempt -> {
+ // HTTP request to Vault
+ Rest rest = new Rest()//NOPMD
+ .url(config.getAddress() + "/v1/sys/wrapping/lookup")
+ .header("X-Vault-Namespace", this.nameSpace)
+ .header("X-Vault-Request", "true")
+ .connectTimeoutSeconds(config.getOpenTimeout())
+ .readTimeoutSeconds(config.getReadTimeout())
+ .sslVerification(config.getSslConfig().isVerify())
+ .sslContext(config.getSslConfig().getSslContext());
+
+ if (inBody) {
+ rest = rest
+ .header("X-Vault-Token", config.getToken())
+ .body(requestJson.getBytes(StandardCharsets.UTF_8));
+ } else {
+ rest = rest.header("X-Vault-Token", wrappedToken);
+ }
+
+ final RestResponse restResponse = rest.post();
+
+ // Validate restResponse
+ if (restResponse.getStatus() != 200) {
+ throw new VaultException(
+ "Vault responded with HTTP status code: " + restResponse.getStatus() +
+ "\nResponse body: " + new String(restResponse.getBody(),
+ StandardCharsets.UTF_8),
+ restResponse.getStatus());
+ }
+
+ final String mimeType = restResponse.getMimeType();
+ if (!"application/json".equals(mimeType)) {
+ throw new VaultException("Vault responded with MIME type: " + mimeType,
+ restResponse.getStatus());
+ }
+
+ return new LogicalResponse(restResponse, attempt,
+ Logical.logicalOperations.authentication);
+ });
+ }
+
+ /**
+ * Provide access to the {@code /sys/wrapping/wrap} endpoint.
+ * + *This provides a powerful mechanism for information sharing in many environments. + * In the types of scenarios, often the best practical option is to provide cover for the secret + * information, be able to detect malfeasance (interception, tampering), and limit lifetime of + * the secret's exposure. Response wrapping performs all three of these duties:
+ * + *
+ * {@code
+ * final String authToken = "...";
+ * final String wrappingToken = "...";
+ * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
+ * final Vault vault = new Vault(config);
+ *
+ * final WrapResponse wrapResponse = vault.sys().wrapping().wrap(
+ * // Data to wrap
+ * new JsonObject()
+ * .add("foo", "bar")
+ * .add("zoo", "zar"),
+ *
+ * // TTL of the response-wrapping token
+ * 60
+ * );
+ *
+ * final UnwrapResponse unwrapResponse = vault.sys().wrapping().unwrap(wrapResponse.getToken());
+ * final JsonObject unwrappedData = response.getData(); // original data
+ * }
+ *
+ *
+ * @param jsonObject User data to wrap.
+ * @param ttlInSec Wrap TTL in seconds
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see #unwrap(String)
+ */
+ public WrapResponse wrap(final JsonObject jsonObject, int ttlInSec) throws VaultException {
+ Objects.requireNonNull(jsonObject);
+
+ return retry(attempt -> {
+ // Parse parameters to JSON
+ final String requestJson = jsonObject.toString();
+ final String url = config.getAddress() + "/v1/sys/wrapping/wrap";
+
+ // HTTP request to Vault
+ final RestResponse restResponse = new Rest()
+ .url(url)
+ .header("X-Vault-Token", config.getToken())
+ .header("X-Vault-Wrap-TTL", Integer.toString(ttlInSec))
+ .header("X-Vault-Namespace", this.nameSpace)
+ .header("X-Vault-Request", "true")
+ .body(requestJson.getBytes(StandardCharsets.UTF_8))
+ .connectTimeoutSeconds(config.getOpenTimeout())
+ .readTimeoutSeconds(config.getReadTimeout())
+ .sslVerification(config.getSslConfig().isVerify())
+ .sslContext(config.getSslConfig().getSslContext())
+ .post();
+
+ // Validate restResponse
+ if (restResponse.getStatus() != 200) {
+ throw new VaultException(
+ "Vault responded with HTTP status code: " + restResponse.getStatus()
+ + "\nResponse body: " + new String(restResponse.getBody(),
+ StandardCharsets.UTF_8),
+ restResponse.getStatus());
+ }
+
+ final String mimeType =
+ restResponse.getMimeType() == null ? "null" : restResponse.getMimeType();
+ if (!mimeType.equals("application/json")) {
+ throw new VaultException("Vault responded with MIME type: " + mimeType,
+ restResponse.getStatus());
+ }
+
+ return new WrapResponse(restResponse, attempt);
+ });
+ }
+
+ /**
+ * Returns the original response inside the wrapped auth token. This method is useful if you + * need to unwrap a token without being authenticated. See {@link #unwrap(String)} if you need + * to do that authenticated.
+ * + *In the example below, you cannot use twice the {@code VaultConfig}, since + * after the first usage of the {@code wrappingToken}, it is not usable anymore. You need to use + * the {@code unwrappedToken} in a new vault configuration to continue. Example usage:
+ * + *
+ * {@code
+ * final String wrappingToken = "...";
+ * final VaultConfig config = new VaultConfig().address(...).token(wrappingToken).build();
+ * final Vault vault = new Vault(config);
+ * final AuthResponse response = vault.sys().wrapping().unwrap();
+ * final String unwrappedToken = response.getAuthClientToken();
+ * }
+ *
+ *
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see #unwrap(String)
+ */
+ public UnwrapResponse unwrap() throws VaultException {
+ return unwrap(config.getToken(), false);
+ }
+
+ /**
+ * Provide access to the {@code /sys/wrapping/unwrap} endpoint.
+ * + *Returns the original response inside the given wrapping token. Unlike simply reading + * {@code cubbyhole/response} (which is deprecated), this endpoint provides additional + * validation checks on the token, returns the original value on the wire rather than a JSON + * string representation of it, and ensures that the response is properly audit-logged.
+ * + *This endpoint can be used by using a wrapping token as the client token in the API call, + * in which case the token parameter is not required; or, a different token with permissions to + * access this endpoint can make the call and pass in the wrapping token in the token parameter. + * Do not use the wrapping token in both locations; this will cause the wrapping token to be + * revoked but the value to be unable to be looked up, as it will basically be a double-use of + * the token!
+ * + *In the example below, {@code authToken} is NOT your wrapped token, and should have + * unwrapping permissions. The unwrapped data in {@link UnwrapResponse#getData()}. Example + * usage:
+ * + *
+ * {@code
+ * final String authToken = "...";
+ * final String wrappingToken = "...";
+ * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
+ * final Vault vault = new Vault(config);
+ *
+ * final WrapResponse wrapResponse = vault.sys().wrapping().wrap(
+ * // Data to wrap
+ * new JsonObject()
+ * .add("foo", "bar")
+ * .add("zoo", "zar"),
+ *
+ * // TTL of the response-wrapping token
+ * 60
+ * );
+ *
+ * final UnwrapResponse unwrapResponse = vault.sys().wrapping().unwrap(wrapResponse.getToken());
+ * final JsonObject unwrappedData = response.getData(); // original data
+ * }
+ *
+ *
+ * @param wrappedToken Specifies the wrapping token ID, do NOT also put this in your
+ * {@link VaultConfig#getToken()}, if token is {@code null}, this method will unwrap the auth
+ * token in {@link VaultConfig#getToken()}
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see #wrap(JsonObject, int)
+ * @see #unwrap()
+ */
+ public UnwrapResponse unwrap(final String wrappedToken) throws VaultException {
+ return unwrap(wrappedToken, true);
+ }
+
+ /**
+ * Provide access to the {@code /sys/wrapping/unwrap} endpoint.
+ * + *Returns the original response inside the given wrapping token. Unlike simply reading + * {@code cubbyhole/response} (which is deprecated), this endpoint provides additional + * validation checks on the token, returns the original value on the wire rather than a JSON + * string representation of it, and ensures that the response is properly audit-logged.
+ * + *This endpoint can be used by using a wrapping token as the client token in the API call, + * in which case the token parameter is not required; or, a different token with permissions to + * access this endpoint can make the call and pass in the wrapping token in the token parameter. + * Do not use the wrapping token in both locations; this will cause the wrapping token to be + * revoked but the value to be unable to be looked up, as it will basically be a double-use of + * the token!
+ * + *In the example below, {@code authToken} is NOT your wrapped token, and should have + * unwrapping permissions. The unwrapped data in {@link UnwrapResponse#getData()}. Example + * usage:
+ * + *
+ * {@code
+ * final String authToken = "...";
+ * final String wrappingToken = "...";
+ * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
+ * final Vault vault = new Vault(config);
+ *
+ * final WrapResponse wrapResponse = vault.sys().wrapping().wrap(
+ * // Data to wrap
+ * new JsonObject()
+ * .add("foo", "bar")
+ * .add("zoo", "zar"),
+ *
+ * // TTL of the response-wrapping token
+ * 60
+ * );
+ *
+ * final UnwrapResponse unwrapResponse = vault.sys().wrapping().unwrap(wrapResponse.getToken(), true);
+ * final JsonObject unwrappedData = response.getData(); // original data
+ * }
+ *
+ *
+ * @param wrappedToken Specifies the wrapping token ID, do NOT also put this in your
+ * {@link VaultConfig#getToken()}, if token is {@code null}, this method will unwrap the auth
+ * token in {@link VaultConfig#getToken()}
+ * @param inBody When {@code true} the token value placed in the body request:
+ * {@code {"token": "$wrappedToken"}}, otherwise, set the token into header:
+ * {@code "X-Vault-Token: $wrappedToken"}.
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see #wrap(JsonObject, int)
+ * @see #unwrap()
+ */
+ public UnwrapResponse unwrap(final String wrappedToken, boolean inBody) throws VaultException {
+ Objects.requireNonNull(wrappedToken, "Wrapped token is null");
+
+ return retry(attempt -> {
+ final String url = config.getAddress() + "/v1/sys/wrapping/unwrap";
+
+ // HTTP request to Vault
+ Rest rest = new Rest()
+ .url(url)
+ .header("X-Vault-Namespace", this.nameSpace)
+ .header("X-Vault-Request", "true")
+ .connectTimeoutSeconds(config.getOpenTimeout())
+ .readTimeoutSeconds(config.getReadTimeout())
+ .sslVerification(config.getSslConfig().isVerify())
+ .sslContext(config.getSslConfig().getSslContext());
+
+ if (inBody) {
+ final String requestJson = Json.object().add("token", wrappedToken).toString();
+ rest = rest
+ .header("X-Vault-Token", config.getToken())
+ .body(requestJson.getBytes(StandardCharsets.UTF_8));
+ } else {
+ rest = rest
+ .header("X-Vault-Token", wrappedToken);
+ }
+
+ RestResponse restResponse = rest.post();
+
+ // Validate restResponse
+ if (restResponse.getStatus() != 200) {
+ throw new VaultException(
+ "Vault responded with HTTP status code: " + restResponse.getStatus()
+ + "\nResponse body: " + new String(restResponse.getBody(),
+ StandardCharsets.UTF_8),
+ restResponse.getStatus());
+ }
+
+ final String mimeType =
+ restResponse.getMimeType() == null ? "null" : restResponse.getMimeType();
+
+ if (!mimeType.equals("application/json")) {
+ throw new VaultException("Vault responded with MIME type: " + mimeType,
+ restResponse.getStatus());
+ }
+
+ return new UnwrapResponse(restResponse, attempt);
+ });
+ }
+
+ /**
+ * Provide access to the {@code /sys/wrapping/rewrap} endpoint. This endpoint rewraps a + * response-wrapped token. The new token will use the same creation TTL as the original token + * and contain the same response. The old token will be invalidated. This can be used for + * long-term storage of a secret in a response-wrapped token when rotation is a + * requirement.
+ * + *
+ * {@code
+ * final String authToken = "...";
+ * final String wrappingToken = "...";
+ * final VaultConfig config = new VaultConfig().address(...).token(authToken).build();
+ * final Vault vault = new Vault(config);
+ *
+ * final WrapResponse wrapResponse = vault.auth().wrap(
+ * // Data to wrap
+ * new JsonObject()
+ * .add("foo", "bar")
+ * .add("zoo", "zar"),
+ *
+ * // TTL of the response-wrapping token
+ * 60
+ * );
+ * ...
+ * final WrapResponse wrapResponse2 = vault.auth().rewrap(wrapResponse.getToken());
+ *
+ * final UnwrapResponse unwrapResponse = vault.auth().unwrap(wrapResponse2.getToken());
+ * final JsonObject unwrappedData = response.getData(); // original data
+ * }
+ *
+ *
+ * @param wrappedToken Wrapped token ID to re-wrap.
+ * @return The response information returned from Vault
+ * @throws VaultException If any error occurs, or unexpected response received from Vault
+ * @see #wrap(JsonObject, int)
+ */
+ public WrapResponse rewrap(final String wrappedToken) throws VaultException {
+ Objects.requireNonNull(wrappedToken);
+
+ return retry(attempt -> {
+ // Parse parameters to JSON
+ final String requestJson = Json.object().add("token", wrappedToken).toString();
+ final String url = config.getAddress() + "/v1/sys/wrapping/rewrap";
+
+ // HTTP request to Vault
+ final RestResponse restResponse = new Rest()
+ .url(url)
+ .header("X-Vault-Token", config.getToken())
+ .header("X-Vault-Namespace", this.nameSpace)
+ .header("X-Vault-Request", "true")
+ .body(requestJson.getBytes(StandardCharsets.UTF_8))
+ .connectTimeoutSeconds(config.getOpenTimeout())
+ .readTimeoutSeconds(config.getReadTimeout())
+ .sslVerification(config.getSslConfig().isVerify())
+ .sslContext(config.getSslConfig().getSslContext())
+ .post();
+
+ // Validate restResponse
+ if (restResponse.getStatus() != 200) {
+ throw new VaultException(
+ "Vault responded with HTTP status code: " + restResponse.getStatus()
+ + "\nResponse body: " + new String(restResponse.getBody(),
+ StandardCharsets.UTF_8),
+ restResponse.getStatus());
+ }
+
+ final String mimeType =
+ restResponse.getMimeType() == null ? "null" : restResponse.getMimeType();
+ if (!mimeType.equals("application/json")) {
+ throw new VaultException("Vault responded with MIME type: " + mimeType,
+ restResponse.getStatus());
+ }
+
+ return new WrapResponse(restResponse, attempt);
+ });
+ }
+}
diff --git a/src/main/java/io/github/jopenlibs/vault/api/mounts/Mount.java b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/Mount.java
similarity index 96%
rename from src/main/java/io/github/jopenlibs/vault/api/mounts/Mount.java
rename to src/main/java/io/github/jopenlibs/vault/api/sys/mounts/Mount.java
index c4fff712..4d1a2abc 100644
--- a/src/main/java/io/github/jopenlibs/vault/api/mounts/Mount.java
+++ b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/Mount.java
@@ -1,4 +1,4 @@
-package io.github.jopenlibs.vault.api.mounts;
+package io.github.jopenlibs.vault.api.sys.mounts;
import java.io.Serializable;
diff --git a/src/main/java/io/github/jopenlibs/vault/api/mounts/MountConfig.java b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountConfig.java
similarity index 98%
rename from src/main/java/io/github/jopenlibs/vault/api/mounts/MountConfig.java
rename to src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountConfig.java
index 15e16b3c..1d2a3d4f 100644
--- a/src/main/java/io/github/jopenlibs/vault/api/mounts/MountConfig.java
+++ b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountConfig.java
@@ -1,4 +1,4 @@
-package io.github.jopenlibs.vault.api.mounts;
+package io.github.jopenlibs.vault.api.sys.mounts;
import java.io.Serializable;
import java.util.ArrayList;
diff --git a/src/main/java/io/github/jopenlibs/vault/api/mounts/MountPayload.java b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountPayload.java
similarity index 99%
rename from src/main/java/io/github/jopenlibs/vault/api/mounts/MountPayload.java
rename to src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountPayload.java
index dc0522ae..00c4073c 100644
--- a/src/main/java/io/github/jopenlibs/vault/api/mounts/MountPayload.java
+++ b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountPayload.java
@@ -1,4 +1,4 @@
-package io.github.jopenlibs.vault.api.mounts;
+package io.github.jopenlibs.vault.api.sys.mounts;
import io.github.jopenlibs.vault.json.Json;
import io.github.jopenlibs.vault.json.JsonObject;
diff --git a/src/main/java/io/github/jopenlibs/vault/api/mounts/MountType.java b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountType.java
similarity index 95%
rename from src/main/java/io/github/jopenlibs/vault/api/mounts/MountType.java
rename to src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountType.java
index c44518f6..9f2b9afc 100644
--- a/src/main/java/io/github/jopenlibs/vault/api/mounts/MountType.java
+++ b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/MountType.java
@@ -1,4 +1,4 @@
-package io.github.jopenlibs.vault.api.mounts;
+package io.github.jopenlibs.vault.api.sys.mounts;
import java.util.Arrays;
diff --git a/src/main/java/io/github/jopenlibs/vault/api/mounts/Mounts.java b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/Mounts.java
similarity index 98%
rename from src/main/java/io/github/jopenlibs/vault/api/mounts/Mounts.java
rename to src/main/java/io/github/jopenlibs/vault/api/sys/mounts/Mounts.java
index b9ea0c03..30d0ce36 100644
--- a/src/main/java/io/github/jopenlibs/vault/api/mounts/Mounts.java
+++ b/src/main/java/io/github/jopenlibs/vault/api/sys/mounts/Mounts.java
@@ -1,4 +1,4 @@
-package io.github.jopenlibs.vault.api.mounts;
+package io.github.jopenlibs.vault.api.sys.mounts;
import io.github.jopenlibs.vault.VaultConfig;
import io.github.jopenlibs.vault.VaultException;
@@ -13,9 +13,8 @@
* endpoints.
*
* This class is not intended to be constructed directly. Rather, it is meant to used by way of
- * Vault
- * in a DSL-style builder pattern. See the Javadoc comments of each public method for
- * usage examples.
Vault in a DSL-style builder pattern. See the Javadoc comments of each
+ * public method for usage examples.
*/
public class Mounts extends OperationsBase {
@@ -36,7 +35,7 @@ public Mounts(final VaultConfig config) {
* final VaultConfig config = new VaultConfig.address(...).token(...).build();
* final Vault vault = new Vault(config);
*
- * final MountResponse response = vault.mounts().list();
+ * final MountResponse response = vault.sys().mounts().list();
* final MapClasses implementing Vault's mounts system.
+ * + *The classes in this package are not meant to be instantiated directly. Rather, they should
+ * be used by way of the io.github.jopenlibs.vault.Vault driver class, in a DSL-style
+ * builder pattern approach.
Classes implementing the various endpoints of the Vault HTTP API.
+ * + *The classes in this package are not meant to be instantiated directly. Rather, they should
+ * be used by way of the io.github.jopenlibs.vault.Vault driver class, in a DSL-style
+ * builder pattern approach.