diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index 6fce9ce..33d2302 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -23,10 +23,7 @@ import de.stklcode.jvault.connector.model.AuthBackend; import de.stklcode.jvault.connector.model.response.*; import de.stklcode.jvault.connector.model.response.embedded.AuthMethod; import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; @@ -315,6 +312,16 @@ public class HTTPVaultConnector implements VaultConnector { return requestPost(PATH_SECRET + "/" + key, param).equals(""); } + @Override + public boolean deleteSecret(String key) throws VaultConnectorException { + if (!isAuthorized()) + throw new AuthorizationRequiredException(); + + /* Request HTTP response and expect empty result */ + String response = requestDelete(PATH_SECRET + "/" + key); + return response.equals(""); + } + @Override public boolean revoke(String leaseID) throws VaultConnectorException { if (!isAuthorized()) @@ -369,7 +376,7 @@ public class HTTPVaultConnector implements VaultConnector { * @throws VaultConnectorException on connection error */ private String requestPut(final String path, final Map payload) throws VaultConnectorException { - /* Initialize post */ + /* Initialize put */ HttpPut put = new HttpPut(baseURL + path); /* generate JSON from payload */ StringEntity entity = null; @@ -387,6 +394,23 @@ public class HTTPVaultConnector implements VaultConnector { return request(put); } + /** + * Execute HTTP request using DELETE method. + * + * @param path URL path (relative to base) + * @return HTTP response + * @throws VaultConnectorException on connection error + */ + private String requestDelete(final String path) throws VaultConnectorException { + /* Initialize delete */ + HttpDelete delete = new HttpDelete(baseURL + path); + /* Set X-Vault-Token header */ + if (token != null) + delete.addHeader("X-Vault-Token", token); + + return request(delete); + } + /** * Execute HTTP request using GET method. * diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java index f82e2fa..4ededc7 100644 --- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java @@ -182,6 +182,15 @@ public interface VaultConnector { */ boolean writeSecret(final String key, final String value) throws VaultConnectorException; + /** + * Delete secret from Vault. + * + * @param key Secret path + * @return TRUE on succevss + * @throws VaultConnectorException on error + */ + boolean deleteSecret(final String key) throws VaultConnectorException; + /** * Revoke given lease immediately. * diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java index 16b5807..920d75c 100644 --- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java +++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java @@ -300,6 +300,47 @@ public class HTTPVaultConnectorTest { } } + /** + * Test deletion of secrets. + */ + @Test + public void deleteTest() { + authUser(); + assumeTrue(connector.isAuthorized()); + + /* Write a test secret to vault */ + try { + boolean res = connector.writeSecret(SECRET_PATH + "/toDelete", "secret content"); + assumeThat("Secret could not be written path.", res, is(true)); + } catch (VaultConnectorException e) { + fail("Secret written to inaccessible path."); + } + SecretResponse res = null; + try { + res = connector.readSecret(SECRET_PATH + "/toDelete"); + } catch (VaultConnectorException e) { + fail("Written secret could not be read."); + } + assumeThat(res, is(notNullValue())); + + /* Delete secret */ + try { + boolean deleted = connector.deleteSecret(SECRET_PATH + "/toDelete"); + assertThat("Revocation of secret faiked.", deleted, is(true)); + } catch (VaultConnectorException e) { + fail("Revocation threw unexpected exception."); + } + + /* Try to read again */ + try { + connector.readSecret(SECRET_PATH + "/toDelete"); + fail("Successfully read deleted secret."); + } catch (VaultConnectorException e) { + assertThat(e, is(instanceOf(InvalidResponseException.class))); + assertThat(((InvalidResponseException)e).getStatusCode(), is(404)); + } + } + /** * Test revocation of secrets. */ @@ -323,20 +364,13 @@ public class HTTPVaultConnectorTest { } assumeThat(res, is(notNullValue())); - /* Revoke secret by lease id */ + /* Revoke secret */ try { boolean revoked = connector.revoke(SECRET_PATH + "/toRevoke"); assertThat("Revocation of secret faiked.", revoked, is(true)); } catch (VaultConnectorException e) { fail("Revocation threw unexpected exception."); } - - try { - connector.readSecret(SECRET_PATH + "/toRevoke"); - fail("Revoked secret could still be read"); - } catch (VaultConnectorException e) { - assertThat(e, is(notNullValue())); - } } /**