Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi level pfx path #189

Merged
merged 3 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ alike, without causing conflicts with any other dependency.
NOTE: Although the binary artifact produced by the project is backwards-compatible with Java 8, you do need
JDK 9 or higher to modify or build the source code of this library itself.

This Change
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍
This is a great explanation, but it should probably be moved below in this README.md
Maybe as a sub-section of Key Value Secret Engine Config

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely agree with this. The placement of this text here is pretty bizarre, and future people reading the README will have no context of which PR/change this paragraph is talking about.

I'll re-work this myself, post-merge.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I intended for you to move it to release notes once a release number had been assigned.

-----------
This change generalizes the vault Java driver to allow prefix paths to
contain multiple path elements. That is, instead of restricting v2 paths
to be **v1**/*something*/**data**/*anything*/*else* (e.g., for a read or write),
paths can be **v1**/*my*/*long*/*prefix*/*path*/**data**/*anything*/*else*.
The length of the prefix path in path elements, or the prefix path itself
(from which the length in path elements can be derived) is passed in the
VaultConfig build sequence. This allows Vault administrators greater
flexibility in configuring the system.

The default is a prefix path length of one, which makes the library's
behavior backwards-compatible with v5.0.0.

Table of Contents
-----------------
* [Installing the Driver](#installing-the-driver)
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/com/bettercloud/vault/VaultConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class VaultConfig implements Serializable {
private SslConfig sslConfig;
private Integer openTimeout;
private Integer readTimeout;
private int prefixPathDepth = 1;
private int maxRetries;
private int retryIntervalMilliseconds;
private Integer globalEngineVersion;
Expand Down Expand Up @@ -207,6 +208,57 @@ public VaultConfig readTimeout(final Integer readTimeout) {
return this;
}

/**
* <p>Set the "path depth" of the prefix path. Normally this is just
* 1, to correspond to one path element in the prefix path. To use
* a longer prefix path, set this value
*
* @param prefixPathDepth integer number of path elements in the prefix path
*/
public VaultConfig prefixPathDepth(int pathLength) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename this method setPrefixPathDepth ?

if (pathLength < 1) {
throw new IllegalArgumentException("pathLength must be > 1");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

this.prefixPathDepth = pathLength;
return this;
}


/**
* <p>Set the "path depth" of the prefix path, by explicitly specifying
* the prefix path, e.g., "foo/bar/blah" would set the prefix path depth
* to 3.
*
* @param prefixPath string prefix path, with or without initial or
* final forward slashes
*/
public VaultConfig prefixPath(String prefixPath) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest setPrefixPathDepthFromString because this method does not actually set a prefixPath attribute

int orig = 0;
int pos;
int countElements = 0;
int pathLen = prefixPath.length();

if (pathLen == 0) {
throw new IllegalArgumentException("can't use an empty path");
}

while ((orig < pathLen) &&
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

((pos = prefixPath.indexOf('/',orig)) >= 0)) {
countElements++;
orig = pos+1;
}

if (prefixPath.charAt(0) == '/') {
countElements--;
}
if (prefixPath.charAt(pathLen-1) == '/') {
countElements--;
}

return prefixPathDepth(countElements+1);
}

/**
* <p>Sets the maximum number of times that an API operation will retry upon failure.</p>
*
Expand Down Expand Up @@ -245,6 +297,8 @@ void setEngineVersion(final Integer engineVersion) {
this.globalEngineVersion = engineVersion;
}



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

public int getPrefixPathDepth() {
return prefixPathDepth;
}
}

16 changes: 8 additions & 8 deletions src/main/java/com/bettercloud/vault/api/Logical.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private LogicalResponse read(final String path, Boolean shouldRetry, final logic
try {
// Make an HTTP request to Vault
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, operation))
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, config.getPrefixPathDepth(), operation))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
.connectTimeoutSeconds(config.getOpenTimeout())
Expand Down Expand Up @@ -155,7 +155,7 @@ public LogicalResponse read(final String path, Boolean shouldRetry, final Intege
try {
// Make an HTTP request to Vault
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, logicalOperations.readV2))
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, config.getPrefixPathDepth(), logicalOperations.readV2))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
.parameter("version", version.toString())
Expand Down Expand Up @@ -254,7 +254,7 @@ private LogicalResponse write(final String path, final Map<String, Object> nameV
}
// Make an HTTP request to Vault
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, operation))
.url(config.getAddress() + "/v1/" + adjustPathForReadOrWrite(path, config.getPrefixPathDepth(), operation))
.body(jsonObjectToWriteFromEngineVersion(operation, requestJson).toString().getBytes(StandardCharsets.UTF_8))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
Expand Down Expand Up @@ -314,7 +314,7 @@ public LogicalResponse list(final String path) throws VaultException {
private LogicalResponse list(final String path, final logicalOperations operation) throws VaultException {
LogicalResponse response = null;
try {
response = read(adjustPathForList(path, operation), true, operation);
response = read(adjustPathForList(path, config.getPrefixPathDepth(), operation), true, operation);
} catch (final VaultException e) {
if (e.getHttpStatusCode() != 404) {
throw e;
Expand Down Expand Up @@ -346,7 +346,7 @@ private LogicalResponse delete(final String path, final Logical.logicalOperation
try {
// Make an HTTP request to Vault
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForDelete(path, operation))
.url(config.getAddress() + "/v1/" + adjustPathForDelete(path, config.getPrefixPathDepth(), operation))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
.connectTimeoutSeconds(config.getOpenTimeout())
Expand Down Expand Up @@ -406,7 +406,7 @@ public LogicalResponse delete(final String path, final int[] versions) throws Va
// Make an HTTP request to Vault
JsonObject versionsToDelete = new JsonObject().add("versions", versions);
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForVersionDelete(path))
.url(config.getAddress() + "/v1/" + adjustPathForVersionDelete(path,config.getPrefixPathDepth()))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
.connectTimeoutSeconds(config.getOpenTimeout())
Expand Down Expand Up @@ -477,7 +477,7 @@ public LogicalResponse unDelete(final String path, final int[] versions) throws
// Make an HTTP request to Vault
JsonObject versionsToUnDelete = new JsonObject().add("versions", versions);
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForVersionUnDelete(path))
.url(config.getAddress() + "/v1/" + adjustPathForVersionUnDelete(path,config.getPrefixPathDepth()))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
.connectTimeoutSeconds(config.getOpenTimeout())
Expand Down Expand Up @@ -536,7 +536,7 @@ public LogicalResponse destroy(final String path, final int[] versions) throws V
// Make an HTTP request to Vault
JsonObject versionsToDestroy = new JsonObject().add("versions", versions);
final RestResponse restResponse = new Rest()//NOPMD
.url(config.getAddress() + "/v1/" + adjustPathForVersionDestroy(path))
.url(config.getAddress() + "/v1/" + adjustPathForVersionDestroy(path,config.getPrefixPathDepth()))
.header("X-Vault-Token", config.getToken())
.header("X-Vault-Namespace", this.nameSpace)
.connectTimeoutSeconds(config.getOpenTimeout())
Expand Down
47 changes: 28 additions & 19 deletions src/main/java/com/bettercloud/vault/api/LogicalUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,25 @@ private static List<String> getPathSegments(final String path) {
* path to be converted for use with a Version 2 secret engine.
*
* @param segments The Vault path split into segments.
* @param prefixPathDepth number of path elements in the prefix part of
* the path (the part before the qualifier)
* @param qualifier The String to add to the path, based on the operation.
* @return The final path with the needed qualifier.
*/
public static String addQualifierToPath(final List<String> segments, final String qualifier) {
final StringBuilder adjustedPath = new StringBuilder(segments.get(0)).append('/').append(qualifier).append('/');
for (int index = 1; index < segments.size(); index++) {
adjustedPath.append(segments.get(index));
if (index + 1 < segments.size()) {
adjustedPath.append('/');
}
public static String addQualifierToPath(final List<String> segments, final int prefixPathDepth, final String qualifier) {
final StringBuilder adjustedPath = new StringBuilder();
int index;

for (index=0;index < prefixPathDepth;index++) {
adjustedPath.append(segments.get(index))
.append('/');
}

adjustedPath.append(qualifier);

for (;index < segments.size(); index++) {
adjustedPath.append('/')
.append(segments.get(index));
}
return adjustedPath.toString();
}
Expand All @@ -51,11 +60,11 @@ public static String addQualifierToPath(final List<String> segments, final Strin
* @param operation The operation being performed, e.g. readV2 or writeV1.
* @return The Vault path mutated based on the operation.
*/
public static String adjustPathForReadOrWrite(final String path, final Logical.logicalOperations operation) {
public static String adjustPathForReadOrWrite(final String path, final int prefixPathLength,final Logical.logicalOperations operation) {
final List<String> pathSegments = getPathSegments(path);
if (operation.equals(Logical.logicalOperations.readV2) || operation.equals(Logical.logicalOperations.writeV2)) {
// Version 2
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "data"));
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathLength, "data"));
if (path.endsWith("/")) {
adjustedPath.append("/");
}
Expand All @@ -75,12 +84,12 @@ public static String adjustPathForReadOrWrite(final String path, final Logical.l
* @param operation The operation being performed, e.g. readV2 or writeV1.
* @return The Vault path mutated based on the operation.
*/
public static String adjustPathForList(final String path, final Logical.logicalOperations operation) {
public static String adjustPathForList(final String path, int prefixPathDepth, final Logical.logicalOperations operation) {
final List<String> pathSegments = getPathSegments(path);
final StringBuilder adjustedPath = new StringBuilder();
if (operation.equals(Logical.logicalOperations.listV2)) {
// Version 2
adjustedPath.append(addQualifierToPath(pathSegments, "metadata"));
adjustedPath.append(addQualifierToPath(pathSegments, prefixPathDepth, "metadata"));
if (path.endsWith("/")) {
adjustedPath.append("/");
}
Expand All @@ -102,10 +111,10 @@ public static String adjustPathForList(final String path, final Logical.logicalO
*
* @return The modified path
*/
public static String adjustPathForDelete(final String path, final Logical.logicalOperations operation) {
public static String adjustPathForDelete(final String path, final int prefixPathDepth, final Logical.logicalOperations operation) {
final List<String> pathSegments = getPathSegments(path);
if (operation.equals(Logical.logicalOperations.deleteV2)) {
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "metadata"));
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "metadata"));
if (path.endsWith("/")) {
adjustedPath.append("/");
}
Expand All @@ -122,9 +131,9 @@ public static String adjustPathForDelete(final String path, final Logical.logica
*
* @return The modified path
*/
public static String adjustPathForVersionDelete(final String path) {
public static String adjustPathForVersionDelete(final String path,final int prefixPathDepth) {
final List<String> pathSegments = getPathSegments(path);
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "delete"));
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "delete"));
if (path.endsWith("/")) {
adjustedPath.append("/");
}
Expand All @@ -137,9 +146,9 @@ public static String adjustPathForVersionDelete(final String path) {
* @param path The Vault path to check or mutate, based on the operation.
* @return The path mutated depending on the operation.
*/
public static String adjustPathForVersionUnDelete(final String path) {
public static String adjustPathForVersionUnDelete(final String path, final int prefixPathDepth) {
final List<String> pathSegments = getPathSegments(path);
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "undelete"));
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "undelete"));
if (path.endsWith("/")) {
adjustedPath.append("/");
}
Expand All @@ -152,9 +161,9 @@ public static String adjustPathForVersionUnDelete(final String path) {
* @param path The Vault path to check or mutate, based on the operation.
* @return The path mutated depending on the operation.
*/
public static String adjustPathForVersionDestroy(final String path) {
public static String adjustPathForVersionDestroy(final String path,final int prefixPathDepth) {
final List<String> pathSegments = getPathSegments(path);
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, "destroy"));
final StringBuilder adjustedPath = new StringBuilder(addQualifierToPath(pathSegments, prefixPathDepth, "destroy"));
if (path.endsWith("/")) {
adjustedPath.append("/");
}
Expand Down