Skip to content

Commit 862ea73

Browse files
committed
Add support for response wrapping lookup #78
See issue #78
1 parent 7fded27 commit 862ea73

6 files changed

Lines changed: 211 additions & 8 deletions

File tree

src/main/java/com/bettercloud/vault/api/Auth.java

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
import com.bettercloud.vault.json.Json;
77
import com.bettercloud.vault.json.JsonObject;
88
import com.bettercloud.vault.response.AuthResponse;
9+
import com.bettercloud.vault.response.LogicalResponse;
910
import com.bettercloud.vault.response.LookupResponse;
1011
import com.bettercloud.vault.rest.Rest;
1112
import com.bettercloud.vault.rest.RestResponse;
1213
import lombok.Getter;
1314

1415
import java.io.Serializable;
16+
import java.net.URI;
1517
import java.util.List;
1618
import java.util.Map;
1719
import java.util.UUID;
@@ -1084,17 +1086,17 @@ public AuthResponse renewSelf(final long increment, final String tokenAuthMount)
10841086

10851087
/**
10861088
* <p>Returns information about the current client token.</p>
1087-
*
1089+
*
10881090
* @return The response information returned from Vault
10891091
* @throws VaultException If any error occurs, or unexpected response received from Vault
10901092
*/
10911093
public LookupResponse lookupSelf() throws VaultException {
10921094
return lookupSelf("token");
10931095
}
1094-
1096+
10951097
/**
10961098
* <p>Returns information about the current client token.</p>
1097-
*
1099+
*
10981100
* @param tokenAuthMount The mount name of the token authentication back end. If null, defaults to "token"
10991101
* @return The response information returned from Vault
11001102
* @throws VaultException If any error occurs, or unexpected response received from Vault
@@ -1142,6 +1144,68 @@ public LookupResponse lookupSelf(final String tokenAuthMount) throws VaultExcept
11421144
}
11431145
}
11441146

1147+
/**
1148+
* <p>Returns information about the current client token for a wrapped token, for which the lookup endpoint is
1149+
* different at "sys/wrapping/lookup". Example usage:</p>
1150+
*
1151+
* <blockquote>
1152+
* <pre>{@code
1153+
* final String wrappingToken = "...";
1154+
* final VaultConfig config = new VaultConfig().address(...).token(wrappingToken).build();
1155+
* final Vault vault = new Vault(config);
1156+
* final LogicalResponse response = vault.auth().lookupWarp();
1157+
* // Then you can validate "path" for example ...
1158+
* final String path = response.getData().get("path");
1159+
* }</pre>
1160+
* </blockquote>
1161+
*
1162+
* @return The response information returned from Vault
1163+
* @throws VaultException If any error occurs, or unexpected response received from Vault
1164+
*/
1165+
public LogicalResponse lookupWrap() throws VaultException {
1166+
int retryCount = 0;
1167+
while (true) {
1168+
try {
1169+
// HTTP request to Vault
1170+
final RestResponse restResponse = new Rest()//NOPMD
1171+
.url(config.getAddress() + "/v1/sys/wrapping/lookup")
1172+
.header("X-Vault-Token", config.getToken())
1173+
.connectTimeoutSeconds(config.getOpenTimeout())
1174+
.readTimeoutSeconds(config.getReadTimeout())
1175+
.sslVerification(config.getSslConfig().isVerify())
1176+
.sslContext(config.getSslConfig().getSslContext())
1177+
.get();
1178+
// Validate restResponse
1179+
if (restResponse.getStatus() != 200) {
1180+
throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus(),
1181+
restResponse.getStatus());
1182+
}
1183+
final String mimeType = restResponse.getMimeType();
1184+
if (mimeType == null || !"application/json".equals(mimeType)) {
1185+
throw new VaultException("Vault responded with MIME type: " + mimeType, restResponse.getStatus());
1186+
}
1187+
return new LogicalResponse(restResponse, retryCount);
1188+
} catch (Exception e) {
1189+
// If there are retries to perform, then pause for the configured interval and then execute the loop
1190+
// again...
1191+
if (retryCount < config.getMaxRetries()) {
1192+
retryCount++;
1193+
try {
1194+
final int retryIntervalMilliseconds = config.getRetryIntervalMilliseconds();
1195+
Thread.sleep(retryIntervalMilliseconds);
1196+
} catch (InterruptedException e1) {
1197+
e1.printStackTrace(); //NOPMD
1198+
}
1199+
} else if (e instanceof VaultException) { //NOPMD
1200+
// ... otherwise, give up.
1201+
throw (VaultException) e;
1202+
} else {
1203+
throw new VaultException(e);
1204+
}
1205+
}
1206+
}
1207+
}
1208+
11451209
/**
11461210
* <p>Revokes current client token.</p>
11471211
*

src/test/java/com/bettercloud/vault/vault/VaultTestUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ public static Optional<JsonObject> readRequestBody(HttpServletRequest request) {
7070
try {
7171
StringBuilder requestBuffer = new StringBuilder();
7272
IOUtils.readLines(request.getReader()).forEach(requestBuffer::append);
73-
return Optional.of(Json.parse(requestBuffer.toString()).asObject());
73+
String string = requestBuffer.toString();
74+
return string.isEmpty() ? Optional.empty() : Optional.of(Json.parse(string).asObject());
7475
} catch (IOException e) {
7576
return Optional.empty();
7677
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.bettercloud.vault.vault.api;
2+
3+
import com.bettercloud.vault.Vault;
4+
import com.bettercloud.vault.VaultConfig;
5+
import com.bettercloud.vault.json.JsonArray;
6+
import com.bettercloud.vault.json.JsonObject;
7+
import com.bettercloud.vault.response.LookupResponse;
8+
import com.bettercloud.vault.vault.VaultTestUtils;
9+
import com.bettercloud.vault.vault.mock.MockVault;
10+
import org.eclipse.jetty.server.Server;
11+
import org.junit.After;
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
15+
import java.util.Optional;
16+
17+
import static org.junit.Assert.assertEquals;
18+
19+
public class AuthLookupTest {
20+
21+
private static final JsonObject RESPONSE_AUTH_LOOKUPSELF = new JsonObject()
22+
.add("data", new JsonObject()
23+
.add("accessor", "accessor")
24+
.add("policies", new JsonArray()));
25+
26+
private Server server;
27+
private MockVault vaultServer;
28+
29+
@Before
30+
public void before() throws Exception {
31+
vaultServer = new MockVault(200, RESPONSE_AUTH_LOOKUPSELF.toString());
32+
server = VaultTestUtils.initHttpMockVault(vaultServer);
33+
server.start();
34+
}
35+
36+
@After
37+
public void after() throws Exception {
38+
VaultTestUtils.shutdownMockVault(server);
39+
}
40+
41+
@Test
42+
public void should_lookup_self_use_url_auth_token_lookup_self() throws Exception {
43+
VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("token").build();
44+
Vault vault = new Vault(vaultConfig);
45+
LookupResponse response = vault.auth().lookupSelf();
46+
47+
assertEquals(200, response.getRestResponse().getStatus());
48+
49+
// Request URL should contain auth/token/lookup-self
50+
assertEquals(Optional.empty(), vaultServer.getRequestBody());
51+
assertEquals("token", vaultServer.getRequestHeaders().get("X-Vault-Token"));
52+
assertEquals("http://127.0.0.1:8999/v1/auth/token/lookup-self", vaultServer.getRequestUrl());
53+
54+
// Assert response should have the accessor
55+
assertEquals("accessor", response.getAccessor());
56+
}
57+
58+
@Test
59+
public void should_lookup_self_with_param_use_url_auth_mount_lookup_self() throws Exception {
60+
VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("token").build();
61+
Vault vault = new Vault(vaultConfig);
62+
LookupResponse response = vault.auth().lookupSelf("mount");
63+
64+
assertEquals(200, response.getRestResponse().getStatus());
65+
66+
// Request URL should contain auth/mount/lookup-self
67+
assertEquals(Optional.empty(), vaultServer.getRequestBody());
68+
assertEquals("token", vaultServer.getRequestHeaders().get("X-Vault-Token"));
69+
assertEquals("http://127.0.0.1:8999/v1/auth/mount/lookup-self", vaultServer.getRequestUrl());
70+
71+
// Assert response should have the accessor
72+
assertEquals("accessor", response.getAccessor());
73+
}
74+
75+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.bettercloud.vault.vault.api;
2+
3+
import com.bettercloud.vault.Vault;
4+
import com.bettercloud.vault.VaultConfig;
5+
import com.bettercloud.vault.json.JsonObject;
6+
import com.bettercloud.vault.response.LogicalResponse;
7+
import com.bettercloud.vault.vault.VaultTestUtils;
8+
import com.bettercloud.vault.vault.mock.MockVault;
9+
import org.eclipse.jetty.server.Server;
10+
import org.junit.After;
11+
import org.junit.Before;
12+
import org.junit.Test;
13+
14+
import java.util.Optional;
15+
16+
import static org.junit.Assert.assertEquals;
17+
18+
public class AuthLookupWrapTest {
19+
20+
private static final JsonObject RESPONSE_AUTH_LOOKUPSELF = new JsonObject()
21+
.add("data", new JsonObject()
22+
.add("creation_path", "token/path"));
23+
24+
private Server server;
25+
private MockVault vaultServer;
26+
27+
@Before
28+
public void before() throws Exception {
29+
vaultServer = new MockVault(200, RESPONSE_AUTH_LOOKUPSELF.toString());
30+
server = VaultTestUtils.initHttpMockVault(vaultServer);
31+
server.start();
32+
}
33+
34+
@After
35+
public void after() throws Exception {
36+
VaultTestUtils.shutdownMockVault(server);
37+
}
38+
39+
@Test
40+
public void should_lookup_wrap_use_url_sys_wrapping_lookup() throws Exception {
41+
VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999").token("wrapped").build();
42+
Vault vault = new Vault(vaultConfig);
43+
LogicalResponse response = vault.auth().lookupWrap();
44+
45+
assertEquals(200, response.getRestResponse().getStatus());
46+
47+
// Request URL should contain sys/wrapping/lookup
48+
assertEquals(Optional.empty(), vaultServer.getRequestBody());
49+
assertEquals("wrapped", vaultServer.getRequestHeaders().get("X-Vault-Token"));
50+
assertEquals("http://127.0.0.1:8999/v1/sys/wrapping/lookup", vaultServer.getRequestUrl());
51+
52+
// Assert response should have the accessor
53+
assertEquals("token/path", response.getData().get("creation_path"));
54+
}
55+
56+
}

src/test/java/com/bettercloud/vault/vault/api/AuthUnwrapTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void should_unwrap_without_param_sends_no_token_and_return_unwrapped_toke
4646
assertEquals(200, response.getRestResponse().getStatus());
4747

4848
// Assert request body should NOT have token body (wrapped is in header)
49-
assertEquals(null, vaultServer.getRequestBody().get("token"));
49+
assertEquals(null, vaultServer.getRequestBody().get().get("token"));
5050
assertEquals("wrappedToken", vaultServer.getRequestHeaders().get("X-Vault-Token"));
5151

5252
// 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
6262
assertEquals(200, response.getRestResponse().getStatus());
6363

6464
// Assert request body SHOULD have token body
65-
assertEquals("wrappedToken", vaultServer.getRequestBody().getString("token", null));
65+
assertEquals("wrappedToken", vaultServer.getRequestBody().get().getString("token", null));
6666
assertEquals("authToken", vaultServer.getRequestHeaders().get("X-Vault-Token"));
6767

6868
// Assert response should have the unwrapped token in the client_token key

src/test/java/com/bettercloud/vault/vault/mock/MockVault.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.io.IOException;
77
import java.util.Map;
8+
import java.util.Optional;
89
import javax.servlet.ServletException;
910
import javax.servlet.http.HttpServletRequest;
1011
import javax.servlet.http.HttpServletResponse;
@@ -45,6 +46,7 @@ public class MockVault extends AbstractHandler {
4546
private String mockResponse;
4647
private JsonObject requestBody;
4748
private Map<String, String> requestHeaders;
49+
private String requestUrl;
4850

4951
MockVault() {
5052
}
@@ -63,6 +65,7 @@ public void handle(
6365
) throws IOException, ServletException {
6466
requestBody = readRequestBody(request).orElse(null);
6567
requestHeaders = readRequestHeaders(request);
68+
requestUrl = request.getRequestURL().toString();
6669
response.setContentType("application/json");
6770
baseRequest.setHandled(true);
6871
System.out.println("MockVault is sending an HTTP " + mockStatus + " code, with expected success payload...");
@@ -72,12 +75,16 @@ public void handle(
7275
}
7376
}
7477

75-
public JsonObject getRequestBody() {
76-
return requestBody;
78+
public Optional<JsonObject> getRequestBody() {
79+
return Optional.ofNullable(requestBody);
7780
}
7881

7982
public Map<String, String> getRequestHeaders() {
8083
return requestHeaders;
8184
}
8285

86+
public String getRequestUrl() {
87+
return requestUrl;
88+
}
89+
8390
}

0 commit comments

Comments
 (0)