diff --git a/src/main/java/com/bettercloud/vault/Vault.java b/src/main/java/com/bettercloud/vault/Vault.java index 7214174b..6649b4c0 100644 --- a/src/main/java/com/bettercloud/vault/Vault.java +++ b/src/main/java/com/bettercloud/vault/Vault.java @@ -224,6 +224,7 @@ private Map collectSecretEngineVersions() { final RestResponse restResponse = new Rest()//NOPMD .url(vaultConfig.getAddress() + "/v1/sys/mounts") .header("X-Vault-Token", vaultConfig.getToken()) + .optionalHeader("X-Vault-Namespace", this.vaultConfig.getNameSpace()) .connectTimeoutSeconds(vaultConfig.getOpenTimeout()) .readTimeoutSeconds(vaultConfig.getReadTimeout()) .sslVerification(vaultConfig.getSslConfig().isVerify()) diff --git a/src/main/java/com/bettercloud/vault/VaultConfig.java b/src/main/java/com/bettercloud/vault/VaultConfig.java index 74bef93f..0f4ccf40 100644 --- a/src/main/java/com/bettercloud/vault/VaultConfig.java +++ b/src/main/java/com/bettercloud/vault/VaultConfig.java @@ -50,6 +50,8 @@ public class VaultConfig implements Serializable { private int retryIntervalMilliseconds; @Getter private Integer globalEngineVersion; + @Getter + private String nameSpace; private EnvironmentLoader environmentLoader; /** @@ -73,6 +75,20 @@ public VaultConfig environmentLoader(final EnvironmentLoader environmentLoader) return this; } + /** + *

Optional. Sets a global namespace to the Vault server instance, if desired. Otherwise, namespace can be applied individually to any read / write / auth call. + * + *

Namespace support requires Vault Enterprise Pro, please see https://learn.hashicorp.com/vault/operations/namespaces

+ * + * @param nameSpace The namespace to use globally in this VaultConfig instance. + * @return This object, with the namespace populated, ready for additional builder-pattern method calls or else + * finalization with the build() method + */ + public VaultConfig nameSpace(final String nameSpace) { + this.nameSpace = nameSpace; + return this; + } + /** *

Sets the KV Secrets Engine version of the Vault server instance. * diff --git a/src/main/java/com/bettercloud/vault/api/Auth.java b/src/main/java/com/bettercloud/vault/api/Auth.java index d901c94f..9c36ca78 100644 --- a/src/main/java/com/bettercloud/vault/api/Auth.java +++ b/src/main/java/com/bettercloud/vault/api/Auth.java @@ -147,6 +147,9 @@ public TokenRequest role(final String role) { public Auth(final VaultConfig config) { this.config = config; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } public Auth withNameSpace(final String nameSpace) { @@ -230,23 +233,16 @@ public AuthResponse createToken(final TokenRequest tokenRequest, final String to final String url = urlBuilder.toString(); // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(url) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -303,23 +299,16 @@ public AuthResponse loginByAppID(final String path, final String appId, final St while (true) { try { // HTTP request to Vault - final RestResponse restResponse; final String requestJson = Json.object().add("app_id", appId).add("user_id", userId).toString(); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + path) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -404,23 +393,16 @@ public AuthResponse loginByAppRole(final String path, final String roleId, final while (true) { try { // HTTP request to Vault - final RestResponse restResponse; final String requestJson = Json.object().add("role_id", roleId).add("secret_id", secretId).toString(); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + path + "/login") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -494,23 +476,16 @@ public AuthResponse loginByUserPass(final String username, final String password while (true) { try { // HTTP request to Vault - final RestResponse restResponse; final String requestJson = Json.object().add("password", password).toString(); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/login/" + username) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -624,22 +599,15 @@ public AuthResponse loginByAwsEc2(final String role, final String identity, fina } final String requestJson = request.toString(); - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/login") .body(requestJson.getBytes(StandardCharsets.UTF_8)) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -707,22 +675,15 @@ public AuthResponse loginByAwsEc2(final String role, final String pkcs7, final S request.add("nonce", nonce); } final String requestJson = request.toString(); - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/login") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -793,22 +754,15 @@ public AuthResponse loginByAwsIam(final String role, final String iamRequestUrl, request.add("role", role); } final String requestJson = request.toString(); - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/login") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -884,23 +838,16 @@ public AuthResponse loginByGithub(final String githubToken, final String githubA while (true) { try { // HTTP request to Vault - final RestResponse restResponse; final String requestJson = Json.object().add("token", githubToken).toString(); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/login") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -954,23 +901,16 @@ public AuthResponse loginByGCP(final String role, final String jwt) throws Vault while (true) { try { // HTTP request to Vault - final RestResponse restResponse; final String requestJson = Json.object().add("role", role).add("jwt", jwt).toString(); - final Rest rest = new Rest() + final RestResponse restResponse = new Rest() .url(config.getAddress() + "/v1/auth/gcp/login") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -1058,21 +998,15 @@ public AuthResponse loginByCert(final String certAuthMount) throws VaultExceptio final String mount = certAuthMount != null ? certAuthMount : "cert"; while (true) { try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/login") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); + .sslContext(config.getSslConfig().getSslContext()) + .post(); - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } // Validate restResponse if (restResponse.getStatus() != 200) { throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus(), @@ -1145,23 +1079,16 @@ public AuthResponse renewSelf(final long increment, final String tokenAuthMount) try { // HTTP request to Vault final String requestJson = Json.object().add("increment", increment).toString(); - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/renew-self") .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(increment < 0 ? null : requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -1215,22 +1142,15 @@ public LookupResponse lookupSelf(final String tokenAuthMount) throws VaultExcept while (true) { try { // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/lookup-self") .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .get(); - } else { - restResponse = rest.get(); - } + .sslContext(config.getSslConfig().getSslContext()) + .get(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -1284,22 +1204,15 @@ public LogicalResponse lookupWrap() throws VaultException { while (true) { try { // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/wrapping/lookup") .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .get(); - } else { - restResponse = rest.get(); - } + .sslContext(config.getSslConfig().getSslContext()) + .get(); // Validate restResponse if (restResponse.getStatus() != 200) { @@ -1353,22 +1266,15 @@ public void revokeSelf(final String tokenAuthMount) throws VaultException { while (true) { try { // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/auth/" + mount + "/revoke-self") .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 204) { @@ -1461,23 +1367,16 @@ public AuthResponse unwrap(final String wrappedToken) throws VaultException { final String url = config.getAddress() + "/v1/sys/wrapping/unwrap"; // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest() + final RestResponse restResponse = new Rest() .url(url) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 200) { diff --git a/src/main/java/com/bettercloud/vault/api/Debug.java b/src/main/java/com/bettercloud/vault/api/Debug.java index 4742fb8b..50ed7e27 100644 --- a/src/main/java/com/bettercloud/vault/api/Debug.java +++ b/src/main/java/com/bettercloud/vault/api/Debug.java @@ -27,6 +27,9 @@ public class Debug { public Debug(final VaultConfig config) { this.config = config; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } public Debug withNameSpace(final String nameSpace) { @@ -96,9 +99,7 @@ public HealthResponse health( if (config.getToken() != null) { rest.header("X-Vault-Token", config.getToken()); } - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - rest.header("X-Vault-Namespace", this.nameSpace); - } + rest.optionalHeader("X-Vault-Namespace", this.nameSpace); // Add params if present if (standbyOk != null) rest.parameter("standbyok", standbyOk.toString()); if (activeCode != null) rest.parameter("activecode", activeCode.toString()); diff --git a/src/main/java/com/bettercloud/vault/api/Leases.java b/src/main/java/com/bettercloud/vault/api/Leases.java index 2ca6e6f7..99a54ee8 100644 --- a/src/main/java/com/bettercloud/vault/api/Leases.java +++ b/src/main/java/com/bettercloud/vault/api/Leases.java @@ -26,6 +26,9 @@ public class Leases { public Leases(final VaultConfig config) { this.config = config; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } public Leases withNameSpace(final String nameSpace) { @@ -51,22 +54,15 @@ public VaultResponse revoke(final String leaseId) throws VaultException { int retryCount = 0; while (true) { try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/revoke/" + leaseId) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .put(); - } else { - restResponse = rest.put(); - } + .sslContext(config.getSslConfig().getSslContext()) + .put(); // Validate response if (restResponse.getStatus() != 204) { @@ -113,22 +109,15 @@ public VaultResponse revokePrefix(final String prefix) throws VaultException { int retryCount = 0; while (true) { try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/revoke-prefix/" + prefix) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .put(); - } else { - restResponse = rest.put(); - } + .sslContext(config.getSslConfig().getSslContext()) + .put(); // Validate response if (restResponse.getStatus() != 204) { @@ -178,22 +167,15 @@ public VaultResponse revokeForce(final String prefix) throws VaultException { int retryCount = 0; while (true) { try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/revoke-force/" + prefix) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .put(); - } else { - restResponse = rest.put(); - } + .sslContext(config.getSslConfig().getSslContext()) + .put(); // Validate response if (restResponse.getStatus() != 204) { @@ -248,23 +230,16 @@ public VaultResponse renew(final String leaseId, final long increment) throws Va while (true) { try { final String requestJson = Json.object().add("increment", increment).toString(); - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/renew/" + leaseId) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(increment < 0 ? null : requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate response if (restResponse.getStatus() != 200) { diff --git a/src/main/java/com/bettercloud/vault/api/Logical.java b/src/main/java/com/bettercloud/vault/api/Logical.java index e66effa4..35844282 100644 --- a/src/main/java/com/bettercloud/vault/api/Logical.java +++ b/src/main/java/com/bettercloud/vault/api/Logical.java @@ -18,6 +18,7 @@ import static com.bettercloud.vault.api.LogicalUtilities.*; + /** *

The implementing class for Vault's core/logical operations (e.g. read, write).

* @@ -34,7 +35,9 @@ public enum logicalOperations {authentication, deleteV1, deleteV2, destroy, list public Logical(final VaultConfig config) { this.config = config; - nameSpace = null; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } /** @@ -78,22 +81,15 @@ private LogicalResponse read(final String path, Boolean shouldRetry, final logic while (true) { try { // Make an HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, operation)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .get(); - } else { - restResponse = rest.get(); - } + .sslContext(config.getSslConfig().getSslContext()) + .get(); // Validate response if (restResponse.getStatus() != 200) { @@ -153,23 +149,16 @@ public LogicalResponse read(final String path, Boolean shouldRetry, final Intege while (true) { try { // Make an HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, logicalOperations.readV2)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .parameter("version", version.toString()) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .get(); - } else { - restResponse = rest.get(); - } + .sslContext(config.getSslConfig().getSslContext()) + .get(); // Validate response if (restResponse.getStatus() != 200) { @@ -259,23 +248,16 @@ private LogicalResponse write(final String path, final Map nameV } } // Make an HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, operation)) .body(jsonObjectToWriteFromEngineVersion(operation, requestJson).toString().getBytes(StandardCharsets.UTF_8)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // HTTP Status should be either 200 (with content - e.g. PKI write) or 204 (no content) final int restStatus = restResponse.getStatus(); @@ -371,22 +353,15 @@ private LogicalResponse delete(final String path, final Logical.logicalOperation while (true) { try { // Make an HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForDelete(path, operation)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .delete(); - } else { - restResponse = rest.delete(); - } + .sslContext(config.getSslConfig().getSslContext()) + .delete(); // Validate response if (restResponse.getStatus() != 204) { @@ -437,24 +412,17 @@ public LogicalResponse delete(final String path, final int[] versions) throws Va while (true) { try { // Make an HTTP request to Vault - final RestResponse restResponse; JsonObject versionsToDelete = new JsonObject().add("versions", versions); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForVersionDelete(path)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) .sslContext(config.getSslConfig().getSslContext()) - .body(versionsToDelete.toString().getBytes(StandardCharsets.UTF_8)); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .body(versionsToDelete.toString().getBytes(StandardCharsets.UTF_8)) + .post(); // Validate response return getLogicalResponse(retryCount, restResponse); @@ -515,24 +483,17 @@ public LogicalResponse unDelete(final String path, final int[] versions) throws while (true) { try { // Make an HTTP request to Vault - final RestResponse restResponse; JsonObject versionsToUnDelete = new JsonObject().add("versions", versions); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForVersionUnDelete(path)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) .sslContext(config.getSslConfig().getSslContext()) - .body(versionsToUnDelete.toString().getBytes(StandardCharsets.UTF_8)); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .body(versionsToUnDelete.toString().getBytes(StandardCharsets.UTF_8)) + .post(); // Validate response if (restResponse.getStatus() != 204) { @@ -581,24 +542,17 @@ public LogicalResponse destroy(final String path, final int[] versions) throws V while (true) { try { // Make an HTTP request to Vault - RestResponse restResponse; JsonObject versionsToDestroy = new JsonObject().add("versions", versions); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/" + adjustPathForVersionDestroy(path)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) .sslContext(config.getSslConfig().getSslContext()) - .body(versionsToDestroy.toString().getBytes(StandardCharsets.UTF_8)); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .body(versionsToDestroy.toString().getBytes(StandardCharsets.UTF_8)) + .post(); // Validate response return getLogicalResponse(retryCount, restResponse); @@ -639,24 +593,17 @@ public LogicalResponse upgrade(final String kvPath) throws VaultException { while (true) { try { // Make an HTTP request to Vault - RestResponse restResponse; JsonObject kvToUpgrade = new JsonObject().add("options", new JsonObject().add("version", 2)); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/mounts/" + (kvPath.replaceAll("/", "") + "/tune")) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) .sslContext(config.getSslConfig().getSslContext()) - .body(kvToUpgrade.toString().getBytes(StandardCharsets.UTF_8)); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .body(kvToUpgrade.toString().getBytes(StandardCharsets.UTF_8)) + .post(); // Validate response if (restResponse.getStatus() != 200) { diff --git a/src/main/java/com/bettercloud/vault/api/LogicalUtilities.java b/src/main/java/com/bettercloud/vault/api/LogicalUtilities.java index e59b70e1..d9057dc4 100644 --- a/src/main/java/com/bettercloud/vault/api/LogicalUtilities.java +++ b/src/main/java/com/bettercloud/vault/api/LogicalUtilities.java @@ -12,8 +12,8 @@ public class LogicalUtilities { /** * Convenience method to split a Vault path into its path segments. * - * @param path - * @return + * @param path The Vault path to check or mutate, based on the operation. + * @return The path potentially mutated, based on the operation */ private static List getPathSegments(final String path) { final List segments = new ArrayList<>(); @@ -26,11 +26,11 @@ private static List getPathSegments(final String path) { /** * Injects the supplied qualifier (either "data" or "metadata") into the second-from-the-root segment position, for a Vault - * path to be converted for use with a version 2 secret engine. + * path to be converted for use with a Version 2 secret engine. * - * @param segments - * @param qualifier - * @return + * @param segments The Vault path split into segments. + * @param qualifier The String to add to the path, based on the operation. + * @return The final path with the needed qualifier. */ public static String addQualifierToPath(final List segments, final String qualifier) { final StringBuilder adjustedPath = new StringBuilder(segments.get(0)).append('/').append(qualifier).append('/'); @@ -48,9 +48,9 @@ public static String addQualifierToPath(final List segments, final Strin * path varies depending on the operation being performed. When reading or writing a secret, you must inject the path * segment "data" right after the lowest-level path segment. * - * @param path - * @param operation - * @return + * @param path The Vault path to check or mutate, based on the operation. + * @param operation The operation being performed, e.g. readV2 or writeV1. + * @return The Vault path mutated based on the operation. */ public static String adjustPathForReadOrWrite(final String path, final Logical.logicalOperations operation) { final List pathSegments = getPathSegments(path); @@ -72,9 +72,9 @@ public static String adjustPathForReadOrWrite(final String path, final Logical.l * path varies depending on the operation being performed. When listing secrets available beneath a path, you must inject the * path segment "metadata" right after the lowest-level path segment. * - * @param path - * @param operation - * @return + * @param path The Vault path to check or mutate, based on the operation. + * @param operation The operation being performed, e.g. readV2 or writeV1. + * @return The Vault path mutated based on the operation. */ public static String adjustPathForList(final String path, final Logical.logicalOperations operation) { final List pathSegments = getPathSegments(path); @@ -98,8 +98,8 @@ public static String adjustPathForList(final String path, final Logical.logicalO * path varies depending on the operation being performed. When deleting secrets, you must inject the path segment "metadata" * right after the lowest-level path segment. * - * @param path - * @return + * @param path The Vault path to check or mutate, based on the operation. + * @param operation The operation being performed, e.g. readV2 or writeV1. */ public static String adjustPathForDelete(final String path, final Logical.logicalOperations operation) { final List pathSegments = getPathSegments(path); @@ -117,8 +117,7 @@ public static String adjustPathForDelete(final String path, final Logical.logica /** * When deleting secret versions, you must inject the path segment "delete" right after the lowest-level path segment. * - * @param path - * @return + * @param path The Vault path to check or mutate, based on the operation. */ public static String adjustPathForVersionDelete(final String path) { final List pathSegments = getPathSegments(path); @@ -132,8 +131,8 @@ public static String adjustPathForVersionDelete(final String path) { /** * When undeleting secret versions, you must inject the path segment "undelete" right after the lowest-level path segment. * - * @param path - * @return + * @param path The Vault path to check or mutate, based on the operation. + * @return The path mutated depending on the operation. */ public static String adjustPathForVersionUnDelete(final String path) { final List pathSegments = getPathSegments(path); @@ -147,8 +146,8 @@ public static String adjustPathForVersionUnDelete(final String path) { /** * When destroying secret versions, you must inject the path segment "destroy" right after the lowest-level path segment. * - * @param path - * @return + * @param path The Vault path to check or mutate, based on the operation. + * @return The path mutated depending on the operation. */ public static String adjustPathForVersionDestroy(final String path) { final List pathSegments = getPathSegments(path); @@ -162,9 +161,9 @@ public static String adjustPathForVersionDestroy(final String path) { /** * In version two, when writing a secret, the JSONObject must be nested with "data" as the key. * - * @param operation - * @param jsonObject - * @return + * @param operation The operation being performed, e.g. writeV1, or writeV2. + * @param jsonObject The jsonObject that is going to be written. + * @return This jsonObject mutated for the operation. */ public static JsonObject jsonObjectToWriteFromEngineVersion(final Logical.logicalOperations operation, final JsonObject jsonObject) { if (operation.equals(Logical.logicalOperations.writeV2)) { diff --git a/src/main/java/com/bettercloud/vault/api/Seal.java b/src/main/java/com/bettercloud/vault/api/Seal.java index 95ec3bc2..5aa53ba3 100644 --- a/src/main/java/com/bettercloud/vault/api/Seal.java +++ b/src/main/java/com/bettercloud/vault/api/Seal.java @@ -25,6 +25,9 @@ public class Seal { public Seal(final VaultConfig config) { this.config = config; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } public Seal withNameSpace(final String nameSpace) { @@ -42,22 +45,15 @@ public void seal() throws VaultException { while (true) { try { // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/seal") .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse if (restResponse.getStatus() != 204) { @@ -109,23 +105,16 @@ public SealResponse unseal(final String key, final Boolean reset) throws VaultEx while (true) { try { // HTTP request to Vault - final RestResponse restResponse; final String requestJson = Json.object().add("key", key).add("reset", reset).toString(); - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/unseal") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate restResponse return getSealResponse(retryCount, restResponse); @@ -160,21 +149,15 @@ public SealResponse sealStatus() throws VaultException { while (true) { try { // HTTP request to Vault - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(config.getAddress() + "/v1/sys/seal-status") + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); + .sslContext(config.getSslConfig().getSslContext()) + .get(); - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .get(); - } else { - restResponse = rest.get(); - } // Validate restResponse return getSealResponse(retryCount, restResponse); } catch (Exception e) { diff --git a/src/main/java/com/bettercloud/vault/api/pki/Pki.java b/src/main/java/com/bettercloud/vault/api/pki/Pki.java index 855034e2..588cdaeb 100644 --- a/src/main/java/com/bettercloud/vault/api/pki/Pki.java +++ b/src/main/java/com/bettercloud/vault/api/pki/Pki.java @@ -37,6 +37,9 @@ public Pki withNameSpace(final String nameSpace) { public Pki(final VaultConfig config) { this.config = config; this.mountPath = "pki"; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } /** @@ -48,6 +51,9 @@ public Pki(final VaultConfig config) { public Pki(final VaultConfig config, final String mountPath) { this.config = config; this.mountPath = mountPath; + if (this.config.getNameSpace() != null && !this.config.getNameSpace().isEmpty()) { + this.nameSpace = this.config.getNameSpace(); + } } /** @@ -110,6 +116,7 @@ public PkiResponse createOrUpdateRole(final String roleName, final RoleOptions o final RestResponse restResponse = new Rest()//NOPMD .url(String.format("%s/v1/%s/roles/%s", config.getAddress(), this.mountPath, roleName)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) @@ -168,22 +175,15 @@ public PkiResponse getRole(final String roleName) throws VaultException { while (true) { // Make an HTTP request to Vault try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(String.format("%s/v1/%s/roles/%s", config.getAddress(), this.mountPath, roleName)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .get(); - } else { - restResponse = rest.get(); - } + .sslContext(config.getSslConfig().getSslContext()) + .get(); // Validate response if (restResponse.getStatus() != 200 && restResponse.getStatus() != 404) { @@ -242,23 +242,16 @@ public PkiResponse revoke(final String serialNumber) throws VaultException { } final String requestJson = jsonObject.toString(); try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(String.format("%s/v1/%s/revoke", config.getAddress(), this.mountPath)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .body(requestJson.getBytes(StandardCharsets.UTF_8)) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate response if (restResponse.getStatus() != 200) { @@ -311,22 +304,15 @@ public PkiResponse deleteRole(final String roleName) throws VaultException { while (true) { // Make an HTTP request to Vault try { - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(String.format("%s/v1/%s/roles/%s", config.getAddress(), this.mountPath, roleName)) .header("X-Vault-Token", config.getToken()) + .optionalHeader("X-Vault-Namespace", this.nameSpace) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .delete(); - } else { - restResponse = rest.delete(); - } + .sslContext(config.getSslConfig().getSslContext()) + .delete(); // Validate response if (restResponse.getStatus() != 204) { @@ -467,30 +453,23 @@ public PkiResponse issue( jsonObject.add("format", format.toString()); } if (csr != null) { - jsonObject.add("csr", csr.toString()); + jsonObject.add("csr", csr); } final String requestJson = jsonObject.toString(); // Make an HTTP request to Vault try { String endpoint = (csr == null || csr.isEmpty()) ? "%s/v1/%s/issue/%s" : "%s/v1/%s/sign/%s"; - final RestResponse restResponse; - final Rest rest = new Rest()//NOPMD + final RestResponse restResponse = new Rest()//NOPMD .url(String.format(endpoint, config.getAddress(), this.mountPath, roleName)) .header("X-Vault-Token", config.getToken()) - .body(requestJson.getBytes("UTF-8")) + .optionalHeader("X-Vault-Namespace", this.nameSpace) + .body(requestJson.getBytes(StandardCharsets.UTF_8)) .connectTimeoutSeconds(config.getOpenTimeout()) .readTimeoutSeconds(config.getReadTimeout()) .sslVerification(config.getSslConfig().isVerify()) - .sslContext(config.getSslConfig().getSslContext()); - - if (this.nameSpace != null && !this.nameSpace.isEmpty()) { - restResponse = rest - .header("X-Vault-Namespace", this.nameSpace) - .post(); - } else { - restResponse = rest.post(); - } + .sslContext(config.getSslConfig().getSslContext()) + .post(); // Validate response if (restResponse.getStatus() != 200 && restResponse.getStatus() != 404) { diff --git a/src/main/java/com/bettercloud/vault/response/LookupResponse.java b/src/main/java/com/bettercloud/vault/response/LookupResponse.java index abef21b7..dfa6bd40 100644 --- a/src/main/java/com/bettercloud/vault/response/LookupResponse.java +++ b/src/main/java/com/bettercloud/vault/response/LookupResponse.java @@ -1,11 +1,14 @@ package com.bettercloud.vault.response; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import com.bettercloud.vault.json.*; +import com.bettercloud.vault.json.Json; +import com.bettercloud.vault.json.JsonArray; +import com.bettercloud.vault.json.JsonObject; +import com.bettercloud.vault.json.JsonValue; +import com.bettercloud.vault.json.ParseException; import com.bettercloud.vault.rest.RestResponse; /** @@ -67,7 +70,7 @@ public LookupResponse(final RestResponse restResponse, final int retries) { renewable = dataJsonObject.getBoolean("renewable", false); ttl = dataJsonObject.getLong("ttl", 0); - } catch (ParseException e) { + } catch (ParseException ignored) { } } diff --git a/src/main/java/com/bettercloud/vault/response/SealResponse.java b/src/main/java/com/bettercloud/vault/response/SealResponse.java index ddd487df..38a53a40 100644 --- a/src/main/java/com/bettercloud/vault/response/SealResponse.java +++ b/src/main/java/com/bettercloud/vault/response/SealResponse.java @@ -1,6 +1,8 @@ package com.bettercloud.vault.response; -import com.bettercloud.vault.json.*; +import com.bettercloud.vault.json.Json; +import com.bettercloud.vault.json.JsonObject; +import com.bettercloud.vault.json.ParseException; import com.bettercloud.vault.rest.RestResponse; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/com/bettercloud/vault/rest/Rest.java b/src/main/java/com/bettercloud/vault/rest/Rest.java index 65d02909..5914f7e2 100644 --- a/src/main/java/com/bettercloud/vault/rest/Rest.java +++ b/src/main/java/com/bettercloud/vault/rest/Rest.java @@ -157,25 +157,37 @@ public Rest parameter(final String name, final String value) throws RestExceptio } /** - *

Adds a header to be send with the HTTP request.

+ *

Adds a header to be sent with the HTTP request.

+ * * + *

This method may be chained together repeatedly, to pass multiple headers with a request. When the request + * is ultimately sent, the headers will be sorted by their names.

* - *

Both the header name and value will be automatically url-encoded by the Rest client.

+ * @param name The raw header name + * @param value The raw header value + * @return This object, with a header added, ready for other builder-pattern config methods or an HTTP verb method + */ + public Rest header(final String name, final String value) { + this.headers.put(name, value); + return this; + } + + /** + *

Adds an optional header to be sent with the HTTP request.

+ * * + *

The value, if null, will skip adding this header to the request.

* *

This method may be chained together repeatedly, to pass multiple headers with a request. When the request * is ultimately sent, the headers will be sorted by their names.

* - * @param name The raw header name (not url-encoded) - * @param value The raw header value (not url-encoded) + * @param name The raw header name + * @param value The raw header value * @return This object, with a header added, ready for other builder-pattern config methods or an HTTP verb method - * @throws RestException If any error occurs, or unexpected response received from Vault */ - public Rest header(final String name, final String value) throws RestException { - try { - this.headers.put(URLEncoder.encode(name, "UTF-8"), URLEncoder.encode(value, "UTF-8")); - } catch (UnsupportedEncodingException e) { - throw new RestException(e); - } - return this; + public Rest optionalHeader(final String name, final String value) { + if (value != null && !value.isEmpty()) { + this.headers.put(name, value); + return this; + } else return this; } /** diff --git a/src/test/java/com/bettercloud/vault/RetryTests.java b/src/test/java/com/bettercloud/vault/RetryTests.java index d81d0d64..8779ed6f 100644 --- a/src/test/java/com/bettercloud/vault/RetryTests.java +++ b/src/test/java/com/bettercloud/vault/RetryTests.java @@ -31,7 +31,7 @@ public void testRetries_Read() throws Exception { assertEquals("mock", response.getData().get("value")); assertEquals("12345", response.getLeaseId()); assertEquals(false, response.getRenewable()); - assertTrue(10000L == response.getLeaseDuration()); + assertEquals(10000L, (long) response.getLeaseDuration()); VaultTestUtils.shutdownMockVault(server); } @@ -45,7 +45,7 @@ public void testRetries_Write() throws Exception { final VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("mock_token").build(); final Vault vault = new Vault(vaultConfig); final LogicalResponse response = vault.withRetries(5, 100).logical() - .write("secret/hello", new HashMap() {{ + .write("secret/hello", new HashMap() {{ put("value", "world"); }}); assertEquals(5, response.getRetries()); diff --git a/src/test/java/com/bettercloud/vault/VaultConfigTests.java b/src/test/java/com/bettercloud/vault/VaultConfigTests.java index 02c2e4ba..a4cec99e 100644 --- a/src/test/java/com/bettercloud/vault/VaultConfigTests.java +++ b/src/test/java/com/bettercloud/vault/VaultConfigTests.java @@ -1,5 +1,6 @@ package com.bettercloud.vault; +import org.junit.Assert; import org.junit.Test; import java.io.File; @@ -54,7 +55,7 @@ private MockEnvironmentLoader(final String mockHomeDirectory) { * repeatedly, to populate multiple variables. This method should be called prior to passing the object * instance to a VaultConfig constructor, or calling the build() method on that class. * - * @param name Mock environment variable name + * @param name Mock environment variable name * @param value Mock environment variable value */ private void override(final String name, final String value) { @@ -166,8 +167,8 @@ public void testConfigBuilder_LoadFromEnv_SslCert() throws IOException, VaultExc final FileOutputStream output = new FileOutputStream(pemPath) ) { int nextChar; - while ( (nextChar = input.read()) != -1 ) { - output.write( (char) nextChar ); + while ((nextChar = input.read()) != -1) { + output.write((char) nextChar); } } @@ -230,11 +231,17 @@ public void testConfigBuilder_LoadTokenFromHomedir() throws IOException, VaultEx assertEquals("http://127.0.0.1:8200", config.getAddress()); assertEquals("d24e2469-298a-6c64-6a71-5b47c9ba459a", config.getToken()); assertTrue(config.getSslConfig().isVerify()); - assertTrue(30 == config.getOpenTimeout()); - assertTrue(30 == config.getReadTimeout()); + assertEquals(30, (int) config.getOpenTimeout()); + assertEquals(30, (int) config.getReadTimeout()); assertTrue(mockTokenFile.delete()); assertTrue(new File(mockHomeDirectory).delete()); } + @Test + public void testConfigBuilder_WithNamespace() throws VaultException { + VaultConfig vaultConfig = new VaultConfig().nameSpace("namespace").address("address").build(); + Assert.assertEquals(vaultConfig.getNameSpace(), "namespace"); + } + } diff --git a/src/test/java/com/bettercloud/vault/VaultTests.java b/src/test/java/com/bettercloud/vault/VaultTests.java index dd968276..e1914f76 100644 --- a/src/test/java/com/bettercloud/vault/VaultTests.java +++ b/src/test/java/com/bettercloud/vault/VaultTests.java @@ -28,6 +28,20 @@ public void testGlobalEngineVersionVaultConstructor() { Assert.assertEquals(String.valueOf(1), vault.logical().getEngineVersionForSecretPath("*").toString()); } + @Test + public void testNameSpaceProvidedVaultConstructor() { + VaultConfig vaultConfig = new VaultConfig().nameSpace("namespace"); + Vault vault = new Vault(vaultConfig, 1); + Assert.assertNotNull(vault); + } + + @Test + public void testNameSpaceNotProvidedVaultConstructor() { + VaultConfig vaultConfig = new VaultConfig().nameSpace(null); + Vault vault = new Vault(vaultConfig, 1); + Assert.assertNotNull(vault); + } + @Test(expected = IllegalArgumentException.class) public void testInvalidGlobalEngineVersionVaultConstructor() { VaultConfig vaultConfig = new VaultConfig(); diff --git a/src/test/java/com/bettercloud/vault/rest/DeleteTests.java b/src/test/java/com/bettercloud/vault/rest/DeleteTests.java index 7d6cddb6..7d105835 100644 --- a/src/test/java/com/bettercloud/vault/rest/DeleteTests.java +++ b/src/test/java/com/bettercloud/vault/rest/DeleteTests.java @@ -10,6 +10,7 @@ import java.io.UnsupportedEncodingException; import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertNull; public class DeleteTests { @@ -92,4 +93,31 @@ public void testDelete_WithHeaders() throws Exception { VaultTestUtils.shutdownMockVault(server); } + /** + *

Verify a DELETE request that sends header values.

+ * + * @throws Exception + */ + @Test + public void testDelete_WithOptionalHeaders() throws Exception { + final EchoInputMockVault echoInputMockVault = new EchoInputMockVault(204); + final Server server = VaultTestUtils.initHttpMockVault(echoInputMockVault); + server.start(); + + final RestResponse restResponse = new Rest()//NOPMD + .url("http://127.0.0.1:8999") + .optionalHeader("header1", "value1") + .optionalHeader("header2", "value2") + .optionalHeader("I am null", null) + .delete(); + + assertEquals(204, restResponse.getStatus()); + final JsonObject headers = Json.parse(echoInputMockVault.getLastRequestDetails()).asObject().get("headers").asObject(); + assertEquals("value1", headers.getString("header1", "")); + assertEquals("value2", headers.getString("header2", "")); + assertNull(headers.getString( "I am null", null)); + + VaultTestUtils.shutdownMockVault(server); + } + } diff --git a/src/test/java/com/bettercloud/vault/rest/GetTests.java b/src/test/java/com/bettercloud/vault/rest/GetTests.java index f6b4becf..32d760d5 100644 --- a/src/test/java/com/bettercloud/vault/rest/GetTests.java +++ b/src/test/java/com/bettercloud/vault/rest/GetTests.java @@ -6,8 +6,7 @@ import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Unit tests relating the REST client processing of GET requests. @@ -113,7 +112,7 @@ public void testGet_WithHeaders() throws RestException { .url("https://httpbin.org/get") .header("black", "white") .header("day", "night") - .header("two-part", "Note that headers are send in url-encoded format") + .header("two-part", "Header value") .get(); assertEquals(200, restResponse.getStatus()); assertEquals("application/json", restResponse.getMimeType()); @@ -125,7 +124,38 @@ public void testGet_WithHeaders() throws RestException { // Note that even though our header names where all-lowercase, the round trip process converts them to camel case. assertEquals("white", headers.getString("Black", null)); assertEquals("night", headers.getString("Day", null)); - assertEquals("Note+that+headers+are+send+in+url-encoded+format", headers.getString("Two-Part", null)); + assertEquals("Header value", headers.getString("Two-Part", null)); + } + + /** + *

Verify a GET request that passes HTTP headers.

+ * + *

Note that even though our header names are all lowercase, the round-trip process + * converts them to camel case (e.g. two-part to Two-Part).

+ * + * @throws RestException + */ + @Test + public void testGet_WithOptionalHeaders() throws RestException { + final RestResponse restResponse = new Rest() + .url("https://httpbin.org/get") + .optionalHeader("black", "white") + .optionalHeader("day", "night") + .optionalHeader("two-part", "Header value") + .optionalHeader("I am null", null) + .get(); + assertEquals(200, restResponse.getStatus()); + assertEquals("application/json", restResponse.getMimeType()); + + final String jsonString = new String(restResponse.getBody(), StandardCharsets.UTF_8); + final JsonObject jsonObject = Json.parse(jsonString).asObject(); + assertEquals("https://httpbin.org/get", jsonObject.getString("url", null)); + final JsonObject headers = jsonObject.get("headers").asObject(); + // Note that even though our header names where all-lowercase, the round trip process converts them to camel case. + assertEquals("white", headers.getString("Black", null)); + assertEquals("night", headers.getString("Day", null)); + assertEquals("Header value", headers.getString("Two-Part", null)); + assertNull(headers.getString("I am null", null)); } /** diff --git a/src/test/java/com/bettercloud/vault/rest/PostTests.java b/src/test/java/com/bettercloud/vault/rest/PostTests.java index b3c62fa6..1ae185bc 100644 --- a/src/test/java/com/bettercloud/vault/rest/PostTests.java +++ b/src/test/java/com/bettercloud/vault/rest/PostTests.java @@ -6,7 +6,7 @@ import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; /** * Unit tests relating the REST client processing of POST requests. @@ -104,7 +104,7 @@ public void testPost_WithHeaders() throws RestException { .url("https://httpbin.org/post") .header("black", "white") .header("day", "night") - .header("two-part", "Note that headers are send in url-encoded format") + .header("two-part", "Header value") .post(); assertEquals(200, restResponse.getStatus()); assertEquals("application/json", restResponse.getMimeType()); @@ -115,7 +115,38 @@ public void testPost_WithHeaders() throws RestException { final JsonObject headers = jsonObject.get("headers").asObject(); assertEquals("white", headers.getString("Black", null)); assertEquals("night", headers.getString("Day", null)); - assertEquals("Note+that+headers+are+send+in+url-encoded+format", headers.getString("Two-Part", null)); + assertEquals("Header value", headers.getString("Two-Part", null)); } + /** + *

Verify a POST request that passes optional HTTP headers.

+ * + *

Note that even though our header names are all lowercase, the round-trip process + * converts them to camel case (e.g. two-part to Two-Part).

+ * + * @throws RestException + */ + @Test + public void testPost_WithOptionalHeaders() throws RestException { + final RestResponse restResponse = new Rest() + .url("https://httpbin.org/post") + .optionalHeader("black", "white") + .optionalHeader("day", "night") + .optionalHeader("two-part", "Header value") + .optionalHeader("I am null", null) + .post(); + assertEquals(200, restResponse.getStatus()); + assertEquals("application/json", restResponse.getMimeType()); + + final String jsonString = new String(restResponse.getBody(), StandardCharsets.UTF_8); + final JsonObject jsonObject = Json.parse(jsonString).asObject(); + assertEquals("https://httpbin.org/post", jsonObject.getString("url", null)); + final JsonObject headers = jsonObject.get("headers").asObject(); + assertEquals("white", headers.getString("Black", null)); + assertEquals("night", headers.getString("Day", null)); + assertEquals("Header value", headers.getString("Two-Part", null)); + assertNull(headers.getString( "I am null", null)); + } + + } diff --git a/src/test/java/com/bettercloud/vault/rest/PutTests.java b/src/test/java/com/bettercloud/vault/rest/PutTests.java index e9513e75..bab5a637 100644 --- a/src/test/java/com/bettercloud/vault/rest/PutTests.java +++ b/src/test/java/com/bettercloud/vault/rest/PutTests.java @@ -7,6 +7,7 @@ import java.nio.charset.StandardCharsets; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; /** * Unit tests relating the REST client processing of PUT requests. @@ -104,7 +105,7 @@ public void testPut_WithHeaders() throws RestException { .url("https://httpbin.org/put") .header("black", "white") .header("day", "night") - .header("two-part", "Note that headers are send in url-encoded format") + .header("two-part", "Header value") .put(); assertEquals(200, restResponse.getStatus()); assertEquals("application/json", restResponse.getMimeType()); @@ -115,7 +116,37 @@ public void testPut_WithHeaders() throws RestException { final JsonObject headers = jsonObject.get("headers").asObject(); assertEquals("white", headers.getString("Black", null)); assertEquals("night", headers.getString("Day", null)); - assertEquals("Note+that+headers+are+send+in+url-encoded+format", headers.getString("Two-Part", null)); + assertEquals("Header value", headers.getString("Two-Part", null)); + } + + /** + *

Verify a PUT request that passes optional HTTP headers.

+ * + *

Note that even though our header names are all lowercase, the round-trip process + * converts them to camel case (e.g. two-part to Two-Part).

+ * + * @throws RestException + */ + @Test + public void testPut_WithOptionalHeaders() throws RestException { + final RestResponse restResponse = new Rest() + .url("https://httpbin.org/put") + .optionalHeader("black", "white") + .optionalHeader("day", "night") + .optionalHeader("two-part", "Header value") + .optionalHeader("I am null", null) + .put(); + assertEquals(200, restResponse.getStatus()); + assertEquals("application/json", restResponse.getMimeType()); + + final String jsonString = new String(restResponse.getBody(), StandardCharsets.UTF_8); + final JsonObject jsonObject = Json.parse(jsonString).asObject(); + assertEquals("https://httpbin.org/put", jsonObject.getString("url", null)); + final JsonObject headers = jsonObject.get("headers").asObject(); + assertEquals("white", headers.getString("Black", null)); + assertEquals("night", headers.getString("Day", null)); + assertEquals("Header value", headers.getString("Two-Part", null)); + assertNull(headers.getString("I am null", null)); } }