Skip to content

Commit 14e68b2

Browse files
Merge pull request BetterCloud#189 from bgkaiser/multiLevelPfxPath
Multi level pfx path
2 parents cae5aa2 + 46322af commit 14e68b2

File tree

4 files changed

+107
-27
lines changed

4 files changed

+107
-27
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ alike, without causing conflicts with any other dependency.
1111
NOTE: Although the binary artifact produced by the project is backwards-compatible with Java 8, you do need
1212
JDK 9 or higher to modify or build the source code of this library itself.
1313

14+
This Change
15+
-----------
16+
This change generalizes the vault Java driver to allow prefix paths to
17+
contain multiple path elements. That is, instead of restricting v2 paths
18+
to be **v1**/*something*/**data**/*anything*/*else* (e.g., for a read or write),
19+
paths can be **v1**/*my*/*long*/*prefix*/*path*/**data**/*anything*/*else*.
20+
The length of the prefix path in path elements, or the prefix path itself
21+
(from which the length in path elements can be derived) is passed in the
22+
VaultConfig build sequence. This allows Vault administrators greater
23+
flexibility in configuring the system.
24+
25+
The default is a prefix path length of one, which makes the library's
26+
behavior backwards-compatible with v5.0.0.
27+
1428
Table of Contents
1529
-----------------
1630
* [Installing the Driver](#installing-the-driver)

src/main/java/com/bettercloud/vault/VaultConfig.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class VaultConfig implements Serializable {
3636
private SslConfig sslConfig;
3737
private Integer openTimeout;
3838
private Integer readTimeout;
39+
private int prefixPathDepth = 1;
3940
private int maxRetries;
4041
private int retryIntervalMilliseconds;
4142
private Integer globalEngineVersion;
@@ -207,6 +208,57 @@ public VaultConfig readTimeout(final Integer readTimeout) {
207208
return this;
208209
}
209210

211+
/**
212+
* <p>Set the "path depth" of the prefix path. Normally this is just
213+
* 1, to correspond to one path element in the prefix path. To use
214+
* a longer prefix path, set this value
215+
*
216+
* @param prefixPathDepth integer number of path elements in the prefix path
217+
*/
218+
public VaultConfig prefixPathDepth(int pathLength) {
219+
if (pathLength < 1) {
220+
throw new IllegalArgumentException("pathLength must be > 1");
221+
}
222+
223+
this.prefixPathDepth = pathLength;
224+
return this;
225+
}
226+
227+
228+
/**
229+
* <p>Set the "path depth" of the prefix path, by explicitly specifying
230+
* the prefix path, e.g., "foo/bar/blah" would set the prefix path depth
231+
* to 3.
232+
*
233+
* @param prefixPath string prefix path, with or without initial or
234+
* final forward slashes
235+
*/
236+
public VaultConfig prefixPath(String prefixPath) {
237+
int orig = 0;
238+
int pos;
239+
int countElements = 0;
240+
int pathLen = prefixPath.length();
241+
242+
if (pathLen == 0) {
243+
throw new IllegalArgumentException("can't use an empty path");
244+
}
245+
246+
while ((orig < pathLen) &&
247+
((pos = prefixPath.indexOf('/',orig)) >= 0)) {
248+
countElements++;
249+
orig = pos+1;
250+
}
251+
252+
if (prefixPath.charAt(0) == '/') {
253+
countElements--;
254+
}
255+
if (prefixPath.charAt(pathLen-1) == '/') {
256+
countElements--;
257+
}
258+
259+
return prefixPathDepth(countElements+1);
260+
}
261+
210262
/**
211263
* <p>Sets the maximum number of times that an API operation will retry upon failure.</p>
212264
*
@@ -245,6 +297,8 @@ void setEngineVersion(final Integer engineVersion) {
245297
this.globalEngineVersion = engineVersion;
246298
}
247299

300+
301+
248302
/**
249303
* <p>This is the terminating method in the builder pattern. The method that validates all of the fields that
250304
* has been set already, uses environment variables when available to populate any unset fields, and returns
@@ -330,5 +384,8 @@ public String getNameSpace() {
330384
return nameSpace;
331385
}
332386

387+
public int getPrefixPathDepth() {
388+
return prefixPathDepth;
389+
}
333390
}
334391

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private LogicalResponse read(final String path, Boolean shouldRetry, final logic
8787
try {
8888
// Make an HTTP request to Vault
8989
final RestResponse restResponse = new Rest()//NOPMD
90-
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, operation))
90+
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, config.getPrefixPathDepth(), operation))
9191
.header("X-Vault-Token", config.getToken())
9292
.header("X-Vault-Namespace", this.nameSpace)
9393
.connectTimeoutSeconds(config.getOpenTimeout())
@@ -155,7 +155,7 @@ public LogicalResponse read(final String path, Boolean shouldRetry, final Intege
155155
try {
156156
// Make an HTTP request to Vault
157157
final RestResponse restResponse = new Rest()//NOPMD
158-
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, logicalOperations.readV2))
158+
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, config.getPrefixPathDepth(), logicalOperations.readV2))
159159
.header("X-Vault-Token", config.getToken())
160160
.header("X-Vault-Namespace", this.nameSpace)
161161
.parameter("version", version.toString())
@@ -254,7 +254,7 @@ private LogicalResponse write(final String path, final Map<String, Object> nameV
254254
}
255255
// Make an HTTP request to Vault
256256
final RestResponse restResponse = new Rest()//NOPMD
257-
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, operation))
257+
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, config.getPrefixPathDepth(), operation))
258258
.body(jsonObjectToWriteFromEngineVersion(operation, requestJson).toString().getBytes(StandardCharsets.UTF_8))
259259
.header("X-Vault-Token", config.getToken())
260260
.header("X-Vault-Namespace", this.nameSpace)
@@ -314,7 +314,7 @@ public LogicalResponse list(final String path) throws VaultException {
314314
private LogicalResponse list(final String path, final logicalOperations operation) throws VaultException {
315315
LogicalResponse response = null;
316316
try {
317-
response = read(adjustPathForList(path, operation), true, operation);
317+
response = read(adjustPathForList(path, config.getPrefixPathDepth(), operation), true, operation);
318318
} catch (final VaultException e) {
319319
if (e.getHttpStatusCode() != 404) {
320320
throw e;
@@ -346,7 +346,7 @@ private LogicalResponse delete(final String path, final Logical.logicalOperation
346346
try {
347347
// Make an HTTP request to Vault
348348
final RestResponse restResponse = new Rest()//NOPMD
349-
.url(config.getAddress() + "/v1/" + adjustPathForDelete(path, operation))
349+
.url(config.getAddress() + "/v1/" + adjustPathForDelete(path, config.getPrefixPathDepth(), operation))
350350
.header("X-Vault-Token", config.getToken())
351351
.header("X-Vault-Namespace", this.nameSpace)
352352
.connectTimeoutSeconds(config.getOpenTimeout())
@@ -406,7 +406,7 @@ public LogicalResponse delete(final String path, final int[] versions) throws Va
406406
// Make an HTTP request to Vault
407407
JsonObject versionsToDelete = new JsonObject().add("versions", versions);
408408
final RestResponse restResponse = new Rest()//NOPMD
409-
.url(config.getAddress() + "/v1/" + adjustPathForVersionDelete(path))
409+
.url(config.getAddress() + "/v1/" + adjustPathForVersionDelete(path,config.getPrefixPathDepth()))
410410
.header("X-Vault-Token", config.getToken())
411411
.header("X-Vault-Namespace", this.nameSpace)
412412
.connectTimeoutSeconds(config.getOpenTimeout())
@@ -477,7 +477,7 @@ public LogicalResponse unDelete(final String path, final int[] versions) throws
477477
// Make an HTTP request to Vault
478478
JsonObject versionsToUnDelete = new JsonObject().add("versions", versions);
479479
final RestResponse restResponse = new Rest()//NOPMD
480-
.url(config.getAddress() + "/v1/" + adjustPathForVersionUnDelete(path))
480+
.url(config.getAddress() + "/v1/" + adjustPathForVersionUnDelete(path,config.getPrefixPathDepth()))
481481
.header("X-Vault-Token", config.getToken())
482482
.header("X-Vault-Namespace", this.nameSpace)
483483
.connectTimeoutSeconds(config.getOpenTimeout())
@@ -536,7 +536,7 @@ public LogicalResponse destroy(final String path, final int[] versions) throws V
536536
// Make an HTTP request to Vault
537537
JsonObject versionsToDestroy = new JsonObject().add("versions", versions);
538538
final RestResponse restResponse = new Rest()//NOPMD
539-
.url(config.getAddress() + "/v1/" + adjustPathForVersionDestroy(path))
539+
.url(config.getAddress() + "/v1/" + adjustPathForVersionDestroy(path,config.getPrefixPathDepth()))
540540
.header("X-Vault-Token", config.getToken())
541541
.header("X-Vault-Namespace", this.nameSpace)
542542
.connectTimeoutSeconds(config.getOpenTimeout())

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

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,25 @@ private static List<String> getPathSegments(final String path) {
2828
* path to be converted for use with a Version 2 secret engine.
2929
*
3030
* @param segments The Vault path split into segments.
31+
* @param prefixPathDepth number of path elements in the prefix part of
32+
* the path (the part before the qualifier)
3133
* @param qualifier The String to add to the path, based on the operation.
3234
* @return The final path with the needed qualifier.
3335
*/
34-
public static String addQualifierToPath(final List<String> segments, final String qualifier) {
35-
final StringBuilder adjustedPath = new StringBuilder(segments.get(0)).append('/').append(qualifier).append('/');
36-
for (int index = 1; index < segments.size(); index++) {
37-
adjustedPath.append(segments.get(index));
38-
if (index + 1 < segments.size()) {
39-
adjustedPath.append('/');
40-
}
36+
public static String addQualifierToPath(final List<String> segments, final int prefixPathDepth, final String qualifier) {
37+
final StringBuilder adjustedPath = new StringBuilder();
38+
int index;
39+
40+
for (index=0;index < prefixPathDepth;index++) {
41+
adjustedPath.append(segments.get(index))
42+
.append('/');
43+
}
44+
45+
adjustedPath.append(qualifier);
46+
47+
for (;index < segments.size(); index++) {
48+
adjustedPath.append('/')
49+
.append(segments.get(index));
4150
}
4251
return adjustedPath.toString();
4352
}
@@ -51,11 +60,11 @@ public static String addQualifierToPath(final List<String> segments, final Strin
5160
* @param operation The operation being performed, e.g. readV2 or writeV1.
5261
* @return The Vault path mutated based on the operation.
5362
*/
54-
public static String adjustPathForReadOrWrite(final String path, final Logical.logicalOperations operation) {
63+
public static String adjustPathForReadOrWrite(final String path, final int prefixPathLength,final Logical.logicalOperations operation) {
5564
final List<String> pathSegments = getPathSegments(path);
5665
if (operation.equals(Logical.logicalOperations.readV2) || operation.equals(Logical.logicalOperations.writeV2)) {
5766
// Version 2
58-
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "data"));
67+
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathLength, "data"));
5968
if (path.endsWith("/")) {
6069
adjustedPath.append("/");
6170
}
@@ -75,12 +84,12 @@ public static String adjustPathForReadOrWrite(final String path, final Logical.l
7584
* @param operation The operation being performed, e.g. readV2 or writeV1.
7685
* @return The Vault path mutated based on the operation.
7786
*/
78-
public static String adjustPathForList(final String path, final Logical.logicalOperations operation) {
87+
public static String adjustPathForList(final String path, int prefixPathDepth, final Logical.logicalOperations operation) {
7988
final List<String> pathSegments = getPathSegments(path);
8089
final StringBuilder adjustedPath = new StringBuilder();
8190
if (operation.equals(Logical.logicalOperations.listV2)) {
8291
// Version 2
83-
adjustedPath.append(addQualifierToPath(pathSegments, "metadata"));
92+
adjustedPath.append(addQualifierToPath(pathSegments, prefixPathDepth, "metadata"));
8493
if (path.endsWith("/")) {
8594
adjustedPath.append("/");
8695
}
@@ -102,10 +111,10 @@ public static String adjustPathForList(final String path, final Logical.logicalO
102111
*
103112
* @return The modified path
104113
*/
105-
public static String adjustPathForDelete(final String path, final Logical.logicalOperations operation) {
114+
public static String adjustPathForDelete(final String path, final int prefixPathDepth, final Logical.logicalOperations operation) {
106115
final List<String> pathSegments = getPathSegments(path);
107116
if (operation.equals(Logical.logicalOperations.deleteV2)) {
108-
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "metadata"));
117+
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "metadata"));
109118
if (path.endsWith("/")) {
110119
adjustedPath.append("/");
111120
}
@@ -122,9 +131,9 @@ public static String adjustPathForDelete(final String path, final Logical.logica
122131
*
123132
* @return The modified path
124133
*/
125-
public static String adjustPathForVersionDelete(final String path) {
134+
public static String adjustPathForVersionDelete(final String path,final int prefixPathDepth) {
126135
final List<String> pathSegments = getPathSegments(path);
127-
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "delete"));
136+
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "delete"));
128137
if (path.endsWith("/")) {
129138
adjustedPath.append("/");
130139
}
@@ -137,9 +146,9 @@ public static String adjustPathForVersionDelete(final String path) {
137146
* @param path The Vault path to check or mutate, based on the operation.
138147
* @return The path mutated depending on the operation.
139148
*/
140-
public static String adjustPathForVersionUnDelete(final String path) {
149+
public static String adjustPathForVersionUnDelete(final String path, final int prefixPathDepth) {
141150
final List<String> pathSegments = getPathSegments(path);
142-
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "undelete"));
151+
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "undelete"));
143152
if (path.endsWith("/")) {
144153
adjustedPath.append("/");
145154
}
@@ -152,9 +161,9 @@ public static String adjustPathForVersionUnDelete(final String path) {
152161
* @param path The Vault path to check or mutate, based on the operation.
153162
* @return The path mutated depending on the operation.
154163
*/
155-
public static String adjustPathForVersionDestroy(final String path) {
164+
public static String adjustPathForVersionDestroy(final String path,final int prefixPathDepth) {
156165
final List<String> pathSegments = getPathSegments(path);
157-
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "destroy"));
166+
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "destroy"));
158167
if (path.endsWith("/")) {
159168
adjustedPath.append("/");
160169
}

0 commit comments

Comments
 (0)