From 7fded270c8595ff4f98e20c5b572423369b3bf68 Mon Sep 17 00:00:00 2001 From: Alexandre DuBreuil Date: Fri, 9 Feb 2018 14:10:07 +0100 Subject: [PATCH 1/2] Add support for response wrapping #78 See issue https://github.com/BetterCloud/vault-java-driver/issues/78 --- .../java/com/bettercloud/vault/api/Auth.java | 109 +++++++++++++++++- .../vault/vault/VaultTestUtils.java | 27 +++++ .../vault/vault/api/AuthBackendAwsTests.java | 19 +-- .../vault/vault/api/AuthUnwrapTest.java | 72 ++++++++++++ .../vault/vault/mock/MockVault.java | 32 +++-- 5 files changed, 236 insertions(+), 23 deletions(-) create mode 100644 src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java diff --git a/src/main/java/com/bettercloud/vault/api/Auth.java b/src/main/java/com/bettercloud/vault/api/Auth.java index f696f096..5c631b9e 100644 --- a/src/main/java/com/bettercloud/vault/api/Auth.java +++ b/src/main/java/com/bettercloud/vault/api/Auth.java @@ -7,8 +7,8 @@ import com.bettercloud.vault.json.JsonObject; import com.bettercloud.vault.response.AuthResponse; import com.bettercloud.vault.response.LookupResponse; -import com.bettercloud.vault.rest.RestResponse; import com.bettercloud.vault.rest.Rest; +import com.bettercloud.vault.rest.RestResponse; import lombok.Getter; import java.io.Serializable; @@ -1196,4 +1196,111 @@ 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) + */ + public AuthResponse unwrap() throws VaultException { + return unwrap(null); + } + + /** + *

Returns the original response inside the given wrapped auth token. This method is useful if you need to unwrap + * a token, while being already authenticated. Do NOT authenticate in vault with your wrapping token, since it will + * both fail authentication and invalidate the wrapping token at the same time. See {@link #unwrap()} if you need to + * do that without being authenticated.

+ * + *

In the example below, {@code authToken} is NOT your wrapped token, and should have unwrapping permissions. + * The unwrapped token in {@code unwrappedToken}. 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 AuthResponse response = vault.auth().unwrap(wrappingToken);
+     * final String unwrappedToken = response.getAuthClientToken();
+     * }
+ *
+ * + * @param wrappedToken Specifies the wrapping token ID, do NOT also put this in your {@link VaultConfig#token}, + * if token is {@code null}, this method will unwrap the auth token in {@link VaultConfig#token} + * @return The response information returned from Vault + * @throws VaultException If any error occurs, or unexpected response received from Vault + * @see #unwrap() + */ + public AuthResponse unwrap(final String wrappedToken) throws VaultException { + int retryCount = 0; + while (true) { + try { + // Parse parameters to JSON + final JsonObject jsonObject = Json.object(); + if (wrappedToken != null) { + jsonObject.add("token", wrappedToken); + } + + final String requestJson = jsonObject.toString(); + final String url = config.getAddress() + "/v1/sys/wrapping/unwrap"; + + // HTTP request to Vault + final RestResponse restResponse = new Rest() + .url(url) + .header("X-Vault-Token", config.getToken()) + .body(requestJson.getBytes("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(), + 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 AuthResponse(restResponse, retryCount); + } catch (final 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); + } + } + } + } + } diff --git a/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java b/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java index 2747730d..a2315bec 100644 --- a/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java +++ b/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java @@ -1,6 +1,9 @@ package com.bettercloud.vault.vault; +import com.bettercloud.vault.json.Json; +import com.bettercloud.vault.json.JsonObject; import com.bettercloud.vault.vault.mock.MockVault; +import org.apache.commons.io.IOUtils; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; @@ -10,6 +13,15 @@ import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; + /** *

Utilities used by all of the Vault-related unit test classes under * src/test/java/com/bettercloud/vault, to setup and shutdown mock Vault server implementations.

@@ -54,5 +66,20 @@ public static void shutdownMockVault(final Server server) throws Exception { } } + public static Optional readRequestBody(HttpServletRequest request) { + try { + StringBuilder requestBuffer = new StringBuilder(); + IOUtils.readLines(request.getReader()).forEach(requestBuffer::append); + return Optional.of(Json.parse(requestBuffer.toString()).asObject()); + } catch (IOException e) { + return Optional.empty(); + } + } + + public static Map readRequestHeaders(HttpServletRequest request) { + return Collections.list(request.getHeaderNames()).stream() + .collect(toMap(identity(), request::getHeader)); + } + } diff --git a/src/test/java/com/bettercloud/vault/vault/api/AuthBackendAwsTests.java b/src/test/java/com/bettercloud/vault/vault/api/AuthBackendAwsTests.java index afe9f405..cfa5fa0b 100644 --- a/src/test/java/com/bettercloud/vault/vault/api/AuthBackendAwsTests.java +++ b/src/test/java/com/bettercloud/vault/vault/api/AuthBackendAwsTests.java @@ -3,17 +3,16 @@ import com.bettercloud.vault.Vault; import com.bettercloud.vault.VaultConfig; import com.bettercloud.vault.VaultException; -import com.bettercloud.vault.json.Json; import com.bettercloud.vault.json.JsonObject; import com.bettercloud.vault.vault.VaultTestUtils; import com.bettercloud.vault.vault.mock.AuthRequestValidatingMockVault; -import org.apache.commons.io.IOUtils; import org.eclipse.jetty.server.Server; import org.junit.Test; import javax.servlet.http.HttpServletRequest; import java.util.function.Predicate; +import static com.bettercloud.vault.vault.VaultTestUtils.readRequestBody; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -23,7 +22,7 @@ public class AuthBackendAwsTests { public void testLoginByAwsEc2Id() throws Exception { final Predicate isValidEc2IdRequest = (request) -> { try { - JsonObject requestBody = readRequestBody(request); + JsonObject requestBody = readRequestBody(request).orElse(null); return requestBody != null && request.getRequestURI().endsWith("/auth/aws/login") && requestBody.getString("identity", "").equals("identity") && requestBody.getString("signature", "").equals("signature"); @@ -59,7 +58,7 @@ public void testLoginByAwsEc2Id() throws Exception { public void testLoginByAwsEc2Pkcs7() throws Exception { final Predicate isValidEc2pkcs7Request = (request) -> { try { - JsonObject requestBody = readRequestBody(request); + JsonObject requestBody = readRequestBody(request).orElse(null); return requestBody != null && request.getRequestURI().endsWith("/auth/aws/login") && requestBody.getString("pkcs7", "").equals("pkcs7"); } catch (Exception e) { @@ -95,7 +94,7 @@ public void testLoginByAwsEc2Pkcs7() throws Exception { @Test public void testLoginByAwsIam() throws Exception { final Predicate isValidEc2IamRequest = (request) -> { - JsonObject requestBody = readRequestBody(request); + JsonObject requestBody = readRequestBody(request).orElse(null); return requestBody != null && request.getRequestURI().endsWith("/auth/aws/login") && requestBody.getString("iam_http_request_method", "").equals("POST") && requestBody.getString("iam_request_url", "").equals("url") && @@ -123,14 +122,4 @@ public void testLoginByAwsIam() throws Exception { assertEquals("c9368254-3f21-aded-8a6f-7c818e81b17a", token.trim()); } - private JsonObject readRequestBody(HttpServletRequest request) { - try { - StringBuilder requestBuffer = new StringBuilder(); - IOUtils.readLines(request.getReader()).forEach(requestBuffer::append); - return Json.parse(requestBuffer.toString()).asObject(); - } catch (Exception e) { - return null; - } - } - } diff --git a/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java b/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java new file mode 100644 index 00000000..30069eaf --- /dev/null +++ b/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java @@ -0,0 +1,72 @@ +package com.bettercloud.vault.vault.api; + +import com.bettercloud.vault.Vault; +import com.bettercloud.vault.VaultConfig; +import com.bettercloud.vault.json.JsonArray; +import com.bettercloud.vault.json.JsonObject; +import com.bettercloud.vault.response.AuthResponse; +import com.bettercloud.vault.vault.VaultTestUtils; +import com.bettercloud.vault.vault.mock.MockVault; +import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class AuthUnwrapTest { + + private static final JsonObject RESPONSE_AUTH_UNWRAP = new JsonObject() + .add("renewable", false) + .add("auth", new JsonObject() + .add("policies", new JsonArray()) + .add("client_token", "unwrappedToken")); + + private Server server; + private MockVault vaultServer; + + @Before + public void before() throws Exception { + vaultServer = new MockVault(200, RESPONSE_AUTH_UNWRAP.toString()); + server = VaultTestUtils.initHttpMockVault(vaultServer); + server.start(); + } + + @After + public void after() throws Exception { + VaultTestUtils.shutdownMockVault(server); + } + + @Test + public void should_unwrap_without_param_sends_no_token_and_return_unwrapped_token() throws Exception { + VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("wrappedToken").build(); + Vault vault = new Vault(vaultConfig); + AuthResponse response = vault.auth().unwrap(); + + assertEquals(200, response.getRestResponse().getStatus()); + + // Assert request body should NOT have token body (wrapped is in header) + assertEquals(null, vaultServer.getRequestBody().get("token")); + assertEquals("wrappedToken", vaultServer.getRequestHeaders().get("X-Vault-Token")); + + // Assert response should have the unwrapped token in the client_token key + assertEquals("unwrappedToken", response.getAuthClientToken()); + } + + @Test + public void should_unwrap_param_sends_token_and_return_unwrapped_token() throws Exception { + VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("authToken").build(); + Vault vault = new Vault(vaultConfig); + AuthResponse response = vault.auth().unwrap("wrappedToken"); + + assertEquals(200, response.getRestResponse().getStatus()); + + // Assert request body SHOULD have token body + assertEquals("wrappedToken", vaultServer.getRequestBody().getString("token", null)); + assertEquals("authToken", vaultServer.getRequestHeaders().get("X-Vault-Token")); + + // Assert response should have the unwrapped token in the client_token key + assertEquals("unwrappedToken", response.getAuthClientToken()); + } + +} diff --git a/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java b/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java index 312bbffd..511bd7a6 100644 --- a/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java +++ b/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java @@ -1,12 +1,18 @@ package com.bettercloud.vault.vault.mock; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; +import static com.bettercloud.vault.vault.VaultTestUtils.readRequestBody; +import static com.bettercloud.vault.vault.VaultTestUtils.readRequestHeaders; +import java.io.IOException; +import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import com.bettercloud.vault.json.JsonObject; /** *

This class is used to mock out a Vault server in unit tests involving retry logic. As it extends Jetty's @@ -22,7 +28,7 @@ * server.setHandler( new MockVault(200, "{\"data\":{\"value\":\"mock\"}}") ); * server.start(); * - * final VaultConfig vaultConfig = new VaultConfig("http://127.0.0.1:8999", "mock_token"); + * 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.logical().read("secret/hello"); * @@ -37,15 +43,17 @@ public class MockVault extends AbstractHandler { private int mockStatus; private String mockResponse; + private JsonObject requestBody; + private Map requestHeaders; + + MockVault() { + } public MockVault(final int mockStatus, final String mockResponse) { this.mockStatus = mockStatus; this.mockResponse = mockResponse; } - protected MockVault() { - } - @Override public void handle( final String target, @@ -53,6 +61,8 @@ public void handle( final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException { + requestBody = readRequestBody(request).orElse(null); + requestHeaders = readRequestHeaders(request); response.setContentType("application/json"); baseRequest.setHandled(true); System.out.println("MockVault is sending an HTTP " + mockStatus + " code, with expected success payload..."); @@ -62,4 +72,12 @@ public void handle( } } + public JsonObject getRequestBody() { + return requestBody; + } + + public Map getRequestHeaders() { + return requestHeaders; + } + } From 862ea73f954e2ed4cd61fc0f25558ef92d6c4d9f Mon Sep 17 00:00:00 2001 From: Alexandre DuBreuil Date: Thu, 8 Mar 2018 11:47:02 +0100 Subject: [PATCH 2/2] Add support for response wrapping lookup #78 See issue https://github.com/BetterCloud/vault-java-driver/issues/78 --- .../java/com/bettercloud/vault/api/Auth.java | 70 ++++++++++++++++- .../vault/vault/VaultTestUtils.java | 3 +- .../vault/vault/api/AuthLookupTest.java | 75 +++++++++++++++++++ .../vault/vault/api/AuthLookupWrapTest.java | 56 ++++++++++++++ .../vault/vault/api/AuthUnwrapTest.java | 4 +- .../vault/vault/mock/MockVault.java | 11 ++- 6 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/bettercloud/vault/vault/api/AuthLookupTest.java create mode 100644 src/test/java/com/bettercloud/vault/vault/api/AuthLookupWrapTest.java diff --git a/src/main/java/com/bettercloud/vault/api/Auth.java b/src/main/java/com/bettercloud/vault/api/Auth.java index 5c631b9e..515f2664 100644 --- a/src/main/java/com/bettercloud/vault/api/Auth.java +++ b/src/main/java/com/bettercloud/vault/api/Auth.java @@ -6,12 +6,14 @@ import com.bettercloud.vault.json.Json; import com.bettercloud.vault.json.JsonObject; import com.bettercloud.vault.response.AuthResponse; +import com.bettercloud.vault.response.LogicalResponse; import com.bettercloud.vault.response.LookupResponse; import com.bettercloud.vault.rest.Rest; import com.bettercloud.vault.rest.RestResponse; import lombok.Getter; import java.io.Serializable; +import java.net.URI; import java.util.List; import java.util.Map; import java.util.UUID; @@ -1084,17 +1086,17 @@ public AuthResponse renewSelf(final long increment, final String tokenAuthMount) /** *

Returns information about the current client token.

- * + * * @return The response information returned from Vault * @throws VaultException If any error occurs, or unexpected response received from Vault */ public LookupResponse lookupSelf() throws VaultException { return lookupSelf("token"); } - + /** *

Returns information about the current client token.

- * + * * @param tokenAuthMount The mount name of the token authentication back end. If null, defaults to "token" * @return The response information returned from Vault * @throws VaultException If any error occurs, or unexpected response received from Vault @@ -1142,6 +1144,68 @@ 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 + * different 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 + */ + public LogicalResponse lookupWrap() throws VaultException { + int retryCount = 0; + while (true) { + try { + // HTTP request to Vault + final RestResponse restResponse = new Rest()//NOPMD + .url(config.getAddress() + "/v1/sys/wrapping/lookup") + .header("X-Vault-Token", config.getToken()) + .connectTimeoutSeconds(config.getOpenTimeout()) + .readTimeoutSeconds(config.getReadTimeout()) + .sslVerification(config.getSslConfig().isVerify()) + .sslContext(config.getSslConfig().getSslContext()) + .get(); + // Validate restResponse + if (restResponse.getStatus() != 200) { + throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus(), + restResponse.getStatus()); + } + final String mimeType = restResponse.getMimeType(); + if (mimeType == null || !"application/json".equals(mimeType)) { + throw new VaultException("Vault responded with MIME type: " + mimeType, restResponse.getStatus()); + } + return new LogicalResponse(restResponse, retryCount); + } 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(); //NOPMD + } + } else if (e instanceof VaultException) { //NOPMD + // ... otherwise, give up. + throw (VaultException) e; + } else { + throw new VaultException(e); + } + } + } + } + /** *

Revokes current client token.

* diff --git a/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java b/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java index a2315bec..7958959b 100644 --- a/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java +++ b/src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java @@ -70,7 +70,8 @@ public static Optional readRequestBody(HttpServletRequest request) { try { StringBuilder requestBuffer = new StringBuilder(); IOUtils.readLines(request.getReader()).forEach(requestBuffer::append); - return Optional.of(Json.parse(requestBuffer.toString()).asObject()); + String string = requestBuffer.toString(); + return string.isEmpty() ? Optional.empty() : Optional.of(Json.parse(string).asObject()); } catch (IOException e) { return Optional.empty(); } diff --git a/src/test/java/com/bettercloud/vault/vault/api/AuthLookupTest.java b/src/test/java/com/bettercloud/vault/vault/api/AuthLookupTest.java new file mode 100644 index 00000000..b1aa2462 --- /dev/null +++ b/src/test/java/com/bettercloud/vault/vault/api/AuthLookupTest.java @@ -0,0 +1,75 @@ +package com.bettercloud.vault.vault.api; + +import com.bettercloud.vault.Vault; +import com.bettercloud.vault.VaultConfig; +import com.bettercloud.vault.json.JsonArray; +import com.bettercloud.vault.json.JsonObject; +import com.bettercloud.vault.response.LookupResponse; +import com.bettercloud.vault.vault.VaultTestUtils; +import com.bettercloud.vault.vault.mock.MockVault; +import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; + +public class AuthLookupTest { + + private static final JsonObject RESPONSE_AUTH_LOOKUPSELF = new JsonObject() + .add("data", new JsonObject() + .add("accessor", "accessor") + .add("policies", new JsonArray())); + + private Server server; + private MockVault vaultServer; + + @Before + public void before() throws Exception { + vaultServer = new MockVault(200, RESPONSE_AUTH_LOOKUPSELF.toString()); + server = VaultTestUtils.initHttpMockVault(vaultServer); + server.start(); + } + + @After + public void after() throws Exception { + VaultTestUtils.shutdownMockVault(server); + } + + @Test + public void should_lookup_self_use_url_auth_token_lookup_self() throws Exception { + VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("token").build(); + Vault vault = new Vault(vaultConfig); + LookupResponse response = vault.auth().lookupSelf(); + + assertEquals(200, response.getRestResponse().getStatus()); + + // Request URL should contain auth/token/lookup-self + assertEquals(Optional.empty(), vaultServer.getRequestBody()); + assertEquals("token", vaultServer.getRequestHeaders().get("X-Vault-Token")); + assertEquals("http://127.0.0.1:8999/v1/auth/token/lookup-self", vaultServer.getRequestUrl()); + + // Assert response should have the accessor + assertEquals("accessor", response.getAccessor()); + } + + @Test + public void should_lookup_self_with_param_use_url_auth_mount_lookup_self() throws Exception { + VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("token").build(); + Vault vault = new Vault(vaultConfig); + LookupResponse response = vault.auth().lookupSelf("mount"); + + assertEquals(200, response.getRestResponse().getStatus()); + + // Request URL should contain auth/mount/lookup-self + assertEquals(Optional.empty(), vaultServer.getRequestBody()); + assertEquals("token", vaultServer.getRequestHeaders().get("X-Vault-Token")); + assertEquals("http://127.0.0.1:8999/v1/auth/mount/lookup-self", vaultServer.getRequestUrl()); + + // Assert response should have the accessor + assertEquals("accessor", response.getAccessor()); + } + +} diff --git a/src/test/java/com/bettercloud/vault/vault/api/AuthLookupWrapTest.java b/src/test/java/com/bettercloud/vault/vault/api/AuthLookupWrapTest.java new file mode 100644 index 00000000..6b49fc91 --- /dev/null +++ b/src/test/java/com/bettercloud/vault/vault/api/AuthLookupWrapTest.java @@ -0,0 +1,56 @@ +package com.bettercloud.vault.vault.api; + +import com.bettercloud.vault.Vault; +import com.bettercloud.vault.VaultConfig; +import com.bettercloud.vault.json.JsonObject; +import com.bettercloud.vault.response.LogicalResponse; +import com.bettercloud.vault.vault.VaultTestUtils; +import com.bettercloud.vault.vault.mock.MockVault; +import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; + +public class AuthLookupWrapTest { + + private static final JsonObject RESPONSE_AUTH_LOOKUPSELF = new JsonObject() + .add("data", new JsonObject() + .add("creation_path", "token/path")); + + private Server server; + private MockVault vaultServer; + + @Before + public void before() throws Exception { + vaultServer = new MockVault(200, RESPONSE_AUTH_LOOKUPSELF.toString()); + server = VaultTestUtils.initHttpMockVault(vaultServer); + server.start(); + } + + @After + public void after() throws Exception { + VaultTestUtils.shutdownMockVault(server); + } + + @Test + public void should_lookup_wrap_use_url_sys_wrapping_lookup() throws Exception { + VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("wrapped").build(); + Vault vault = new Vault(vaultConfig); + LogicalResponse response = vault.auth().lookupWrap(); + + assertEquals(200, response.getRestResponse().getStatus()); + + // Request URL should contain sys/wrapping/lookup + assertEquals(Optional.empty(), vaultServer.getRequestBody()); + assertEquals("wrapped", vaultServer.getRequestHeaders().get("X-Vault-Token")); + assertEquals("http://127.0.0.1:8999/v1/sys/wrapping/lookup", vaultServer.getRequestUrl()); + + // Assert response should have the accessor + assertEquals("token/path", response.getData().get("creation_path")); + } + +} diff --git a/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java b/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java index 30069eaf..2657187e 100644 --- a/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java +++ b/src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java @@ -46,7 +46,7 @@ public void should_unwrap_without_param_sends_no_token_and_return_unwrapped_toke assertEquals(200, response.getRestResponse().getStatus()); // Assert request body should NOT have token body (wrapped is in header) - assertEquals(null, vaultServer.getRequestBody().get("token")); + assertEquals(null, vaultServer.getRequestBody().get().get("token")); assertEquals("wrappedToken", vaultServer.getRequestHeaders().get("X-Vault-Token")); // Assert response should have the unwrapped token in the client_token key @@ -62,7 +62,7 @@ public void should_unwrap_param_sends_token_and_return_unwrapped_token() throws assertEquals(200, response.getRestResponse().getStatus()); // Assert request body SHOULD have token body - assertEquals("wrappedToken", vaultServer.getRequestBody().getString("token", null)); + assertEquals("wrappedToken", vaultServer.getRequestBody().get().getString("token", null)); assertEquals("authToken", vaultServer.getRequestHeaders().get("X-Vault-Token")); // Assert response should have the unwrapped token in the client_token key diff --git a/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java b/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java index 511bd7a6..7df77a40 100644 --- a/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java +++ b/src/test/java/com/bettercloud/vault/vault/mock/MockVault.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.util.Map; +import java.util.Optional; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -45,6 +46,7 @@ public class MockVault extends AbstractHandler { private String mockResponse; private JsonObject requestBody; private Map requestHeaders; + private String requestUrl; MockVault() { } @@ -63,6 +65,7 @@ public void handle( ) throws IOException, ServletException { requestBody = readRequestBody(request).orElse(null); requestHeaders = readRequestHeaders(request); + requestUrl = request.getRequestURL().toString(); response.setContentType("application/json"); baseRequest.setHandled(true); System.out.println("MockVault is sending an HTTP " + mockStatus + " code, with expected success payload..."); @@ -72,12 +75,16 @@ public void handle( } } - public JsonObject getRequestBody() { - return requestBody; + public Optional getRequestBody() { + return Optional.ofNullable(requestBody); } public Map getRequestHeaders() { return requestHeaders; } + public String getRequestUrl() { + return requestUrl; + } + }