diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index af3038a..184af52 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -360,7 +360,7 @@ public class HTTPVaultConnector implements VaultConnector { /* Get response */ String response = requestPost(PATH_AUTH_APPID + "map/app-id/" + appID, payload); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); return true; } @@ -375,7 +375,7 @@ public class HTTPVaultConnector implements VaultConnector { /* Get response */ String response = requestPost(PATH_AUTH_APPID + "map/user-id/" + userID, payload); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); return true; } @@ -387,7 +387,7 @@ public class HTTPVaultConnector implements VaultConnector { /* Get response */ String response = requestPost(String.format(PATH_AUTH_APPROLE_ROLE, role.getName(), ""), role); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); /* Set custom ID if provided */ @@ -419,7 +419,7 @@ public class HTTPVaultConnector implements VaultConnector { String response = requestDelete(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "")); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); return true; @@ -450,7 +450,7 @@ public class HTTPVaultConnector implements VaultConnector { payload.put("role_id", roleID); String response = requestPost(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"), payload); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); return true; } @@ -503,7 +503,7 @@ public class HTTPVaultConnector implements VaultConnector { new AppRoleSecret(secretID)); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); return true; @@ -586,7 +586,7 @@ public class HTTPVaultConnector implements VaultConnector { if (key == null || key.isEmpty()) throw new InvalidRequestException("Secret path must not be empty."); - if (!requestPost(key, data).equals("")) + if (!requestPost(key, data).isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); } @@ -599,7 +599,7 @@ public class HTTPVaultConnector implements VaultConnector { String response = requestDelete(key); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); } @@ -612,7 +612,7 @@ public class HTTPVaultConnector implements VaultConnector { String response = requestPut(PATH_REVOKE + leaseID, new HashMap<>()); /* Response should be code 204 without content */ - if (!response.equals("")) + if (!response.isEmpty()) throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE); } diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java index 4d4d944..7e424be 100644 --- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java +++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java @@ -19,6 +19,7 @@ package de.stklcode.jvault.connector; import de.stklcode.jvault.connector.exception.InvalidRequestException; import de.stklcode.jvault.connector.exception.InvalidResponseException; import de.stklcode.jvault.connector.exception.PermissionDeniedException; +import de.stklcode.jvault.connector.exception.VaultConnectorException; import org.apache.http.ProtocolVersion; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.entity.ContentType; @@ -37,6 +38,7 @@ import javax.net.ssl.SSLContext; import java.io.IOException; import java.lang.reflect.Field; import java.security.NoSuchAlgorithmException; +import java.util.Collections; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.nullValue; @@ -242,6 +244,83 @@ public class HTTPVaultConnectorOfflineTest { } } + /** + * Test requests that expect an empty response with code 204, but receive a 200 body. + */ + @Test + public void nonEmpty204ResponseTest() throws IOException { + HTTPVaultConnector connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250); + // Mock authorization. + setPrivate(connector, "authorized", true); + // Mock response. + initHttpMock(); + mockResponse(200, "{}", ContentType.APPLICATION_JSON); + + // Now test the methods expecting a 204. + try { + connector.registerAppId("appID", "policy", "displayName"); + fail("registerAppId() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.registerUserId("appID", "userID"); + fail("registerUserId() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.createAppRole("appID", Collections.singletonList("policy")); + fail("createAppRole() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.deleteAppRole("roleName"); + fail("deleteAppRole() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.setAppRoleID("roleName", "roleID"); + fail("setAppRoleID() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.destroyAppRoleSecret("roleName", "secretID"); + fail("destroyAppRoleSecret() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.destroyAppRoleSecret("roleName", "secretUD"); + fail("destroyAppRoleSecret() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.delete("key"); + fail("delete() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + + try { + connector.revoke("leaseID"); + fail("destroyAppRoleSecret() with 200 response succeeded"); + } catch (VaultConnectorException e) { + assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class)); + } + } + private Object getPrivate(Object target, String fieldName) { try { Field field = target.getClass().getDeclaredField(fieldName); @@ -256,6 +335,18 @@ public class HTTPVaultConnectorOfflineTest { } } + private void setPrivate(Object target, String fieldName, Object value) { + try { + Field field = target.getClass().getDeclaredField(fieldName); + boolean accessible =field.isAccessible(); + field.setAccessible(true); + field.set(target, value); + field.setAccessible(accessible); + } catch (NoSuchFieldException | IllegalAccessException e) { + // Should not occur, to be taken care of in test code. + } + } + private void initHttpMock() { mockStatic(HttpClientBuilder.class); when(HttpClientBuilder.create()).thenReturn(httpMockBuilder);