Skip to content

Commit 064885f

Browse files
authored
Merge branch 'master' into return-response-body-on-error
2 parents d02b852 + 9951203 commit 064885f

File tree

6 files changed

+303
-26
lines changed

6 files changed

+303
-26
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ Note that changes to the major version (i.e. the first number) represent possibl
135135
may require modifications in your code to migrate. Changes to the minor version (i.e. the second number)
136136
should represent non-breaking changes. The third number represents any very minor bugfix patches.
137137

138+
* **3.0.0 (IN DEVELOPMENT)**: This is a (mildly) breaking-change release, with several updates.
139+
* Adds support for writing arbitrary objects to Vault, instead of just strings (i.e. the
140+
`com.bettercloud.vault.api.Logical.write(...)` method now accepts a `Map<String. Object>` rather than a
141+
`Map<String, String>`).
142+
* Supports creating tokens against a role, and refactors the `com.bettercloud.vault.api.Auth.createToken(...)`
143+
method to accept an options object (deprecating the previous version of the method, which took all of those
144+
options as separate parameters).
138145
* **2.0.0**: This is breaking-change release, with numerous deprecated items cleaned up.
139146
* Adds support for authentication via the AppRole auth backend.
140147
* Adds support for renewing secret leases.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ apply plugin: 'signing'
44

55
group 'com.bettercloud'
66
archivesBaseName = 'vault-java-driver'
7-
version '2.0.0'
7+
version '3.0.0-SNAPSHOT'
88
ext.isReleaseVersion = !version.endsWith('SNAPSHOT')
99

1010
sourceCompatibility = 1.7

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

Lines changed: 232 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,11 @@
33
import com.bettercloud.vault.VaultConfig;
44
import com.bettercloud.vault.VaultException;
55
import com.bettercloud.vault.json.Json;
6-
import com.bettercloud.vault.json.JsonArray;
76
import com.bettercloud.vault.json.JsonObject;
8-
import com.bettercloud.vault.json.JsonValue;
97
import com.bettercloud.vault.response.AuthResponse;
108
import com.bettercloud.vault.rest.RestResponse;
119
import com.bettercloud.vault.rest.Rest;
1210

13-
import java.io.UnsupportedEncodingException;
14-
import java.util.ArrayList;
1511
import java.util.List;
1612
import java.util.Map;
1713
import java.util.UUID;
@@ -24,6 +20,194 @@
2420
*/
2521
public class Auth {
2622

23+
/**
24+
* Builder-style class for use with {@link #createToken(TokenRequest)}
25+
*
26+
* <p>All properties are optional and can be <code>null</code>.</p>
27+
*/
28+
public static class TokenRequest {
29+
/**
30+
* (optional) The ID of the client token. Can only be specified by a root token. Otherwise, the token ID is a randomly generated UUID.
31+
*/
32+
private UUID id;
33+
34+
/**
35+
* (optional) A list of policies for the token. This must be a subset of the policies belonging to the token making the request, unless root. If not specified, defaults to all the policies of the calling token.
36+
*/
37+
private List<String> polices;
38+
39+
/**
40+
* (optional) A map of string to string valued metadata. This is passed through to the audit backends.
41+
*/
42+
private Map<String, String> meta;
43+
44+
/**
45+
* (optional) If true and set by a root caller, the token will not have the parent token of the caller. This creates a token with no parent.
46+
*/
47+
private Boolean noParent;
48+
49+
/**
50+
* (optional) If <code>true</code> the default policy will not be a part of this token's policy set.
51+
*/
52+
private Boolean noDefaultPolicy;
53+
54+
/**
55+
* (optional) The TTL period of the token, provided as "1h", where hour is the largest suffix. If not provided, the token is valid for the default lease TTL, or indefinitely if the root policy is used.
56+
*/
57+
private String ttl;
58+
59+
/**
60+
* (optional) The display name of the token. Defaults to "token".
61+
*/
62+
private String displayName;
63+
64+
/**
65+
* (optional) The maximum uses for the given token. This can be used to create a one-time-token or limited use token. Defaults to 0, which has no limit to the number of uses.
66+
*/
67+
private Long numUses;
68+
69+
/**
70+
* (optional) The role the token will be created with. Default is no role.
71+
*/
72+
private String role;
73+
74+
/**
75+
* {@link #id}
76+
*/
77+
public TokenRequest withId(final UUID id) {
78+
this.id = id;
79+
return this;
80+
}
81+
82+
/**
83+
* {@link #polices}
84+
*/
85+
public TokenRequest withPolices(final List<String> polices) {
86+
this.polices = polices;
87+
return this;
88+
}
89+
90+
/**
91+
* {@link #meta}
92+
*/
93+
public TokenRequest withMeta(final Map<String, String> meta) {
94+
this.meta = meta;
95+
return this;
96+
}
97+
98+
/**
99+
* {@link #noParent}
100+
*/
101+
public TokenRequest withNoParent(final Boolean noParent) {
102+
this.noParent = noParent;
103+
return this;
104+
}
105+
106+
/**
107+
* {@link #noDefaultPolicy}
108+
*/
109+
public TokenRequest withNoDefaultPolicy(final Boolean noDefaultPolicy) {
110+
this.noDefaultPolicy = noDefaultPolicy;
111+
return this;
112+
}
113+
114+
/**
115+
* {@link #ttl}
116+
*/
117+
public TokenRequest withTtl(final String ttl) {
118+
this.ttl = ttl;
119+
return this;
120+
}
121+
122+
/**
123+
* {@link #displayName}
124+
*/
125+
public TokenRequest withDisplayName(final String displayName) {
126+
this.displayName = displayName;
127+
return this;
128+
}
129+
130+
/**
131+
* {@link #numUses}
132+
*/
133+
public TokenRequest withNumUses(final Long numUses) {
134+
this.numUses = numUses;
135+
return this;
136+
}
137+
138+
/**
139+
* {@link #role}
140+
*/
141+
public TokenRequest withRole(final String role) {
142+
this.role = role;
143+
return this;
144+
}
145+
146+
147+
/**
148+
* {@link #id}
149+
*/
150+
public UUID getId() {
151+
return id;
152+
}
153+
154+
/**
155+
* {@link #polices}
156+
*/
157+
public List<String> getPolices() {
158+
return polices;
159+
}
160+
161+
/**
162+
* {@link #meta}
163+
*/
164+
public Map<String, String> getMeta() {
165+
return meta;
166+
}
167+
168+
/**
169+
* {@link #noParent}
170+
*/
171+
public Boolean getNoParent() {
172+
return noParent;
173+
}
174+
175+
/**
176+
* {@link #noDefaultPolicy}
177+
*/
178+
public Boolean getNoDefaultPolicy() {
179+
return noDefaultPolicy;
180+
}
181+
182+
/**
183+
* {@link #ttl}
184+
*/
185+
public String getTtl() {
186+
return ttl;
187+
}
188+
189+
/**
190+
* {@link #displayName}
191+
*/
192+
public String getDisplayName() {
193+
return displayName;
194+
}
195+
196+
/**
197+
* {@link #numUses}
198+
*/
199+
public Long getNumUses() {
200+
return numUses;
201+
}
202+
203+
/**
204+
* {@link #role}
205+
*/
206+
public String getRole() {
207+
return role;
208+
}
209+
}
210+
27211
private final VaultConfig config;
28212

29213
public Auth(final VaultConfig config) {
@@ -56,7 +240,9 @@ public Auth(final VaultConfig config) {
56240
* @param numUses (optional) The maximum uses for the given token. This can be used to create a one-time-token or limited use token. Defaults to 0, which has no limit to the number of uses.
57241
* @return The auth token
58242
* @throws VaultException If any error occurs, or unexpected response received from Vault
243+
* @deprecated Use {@link #createToken(TokenRequest)}
59244
*/
245+
@Deprecated
60246
public AuthResponse createToken(
61247
final UUID id,
62248
final List<String> policies,
@@ -67,32 +253,63 @@ public AuthResponse createToken(
67253
final String displayName,
68254
final Long numUses
69255
) throws VaultException {
256+
return createToken(
257+
new TokenRequest()
258+
.withId(id)
259+
.withPolices(policies)
260+
.withMeta(meta)
261+
.withNoParent(noParent)
262+
.withNoDefaultPolicy(noDefaultPolicy)
263+
.withTtl(ttl)
264+
.withDisplayName(displayName)
265+
.withNumUses(numUses));
266+
}
267+
268+
269+
/**
270+
* <p>Operation to create an authentication token. Relies on another token already being present in
271+
* the <code>VaultConfig</code> instance. Example usage:</p>
272+
*
273+
* <blockquote>
274+
* <pre>{@code
275+
* final VaultConfig config = new VaultConfig(address, rootToken);
276+
* final Vault vault = new Vault(config);
277+
* final AuthResponse response = vault.auth().createToken(new TokenRequest().withTtl("1h"));
278+
*
279+
* final String token = response.getAuthClientToken();
280+
* }</pre>
281+
* </blockquote> */
282+
public AuthResponse createToken(TokenRequest tokenRequest) throws VaultException {
70283
int retryCount = 0;
71284
while (true) {
72285
try {
73286
// Parse parameters to JSON
74287
final JsonObject jsonObject = Json.object();
75-
if (id != null) jsonObject.add("id", id.toString());
76-
if (policies != null && !policies.isEmpty()) {
77-
jsonObject.add("policies", Json.array(policies.toArray(new String[policies.size()])));//NOPMD
288+
289+
if (tokenRequest.id != null) jsonObject.add("id", tokenRequest.id.toString());
290+
if (tokenRequest.polices != null && !tokenRequest.polices.isEmpty()) {
291+
jsonObject.add("policies", Json.array(tokenRequest.polices.toArray(new String[tokenRequest.polices.size()])));//NOPMD
78292
}
79-
if (meta != null && !meta.isEmpty()) {
293+
if (tokenRequest.meta != null && !tokenRequest.meta.isEmpty()) {
80294
final JsonObject metaMap = Json.object();
81-
for (final Map.Entry<String, String> entry : meta.entrySet()) {
295+
for (final Map.Entry<String, String> entry : tokenRequest.meta.entrySet()) {
82296
metaMap.add(entry.getKey(), entry.getValue());
83297
}
84298
jsonObject.add("meta", metaMap);
85299
}
86-
if (noParent != null) jsonObject.add("no_parent", noParent);
87-
if (noDefaultPolicy != null) jsonObject.add("no_default_policy", noDefaultPolicy);
88-
if (ttl != null) jsonObject.add("ttl", ttl);
89-
if (displayName != null) jsonObject.add("display_name", displayName);
90-
if (numUses != null) jsonObject.add("num_uses", numUses);
300+
if (tokenRequest.noParent != null) jsonObject.add("no_parent", tokenRequest.noParent);
301+
if (tokenRequest.noDefaultPolicy != null) jsonObject.add("no_default_policy", tokenRequest.noDefaultPolicy);
302+
if (tokenRequest.ttl != null) jsonObject.add("ttl", tokenRequest.ttl);
303+
if (tokenRequest.displayName != null) jsonObject.add("display_name", tokenRequest.displayName);
304+
if (tokenRequest.numUses != null) jsonObject.add("num_uses", tokenRequest.numUses);
91305
final String requestJson = jsonObject.toString();
92306

307+
String url = config.getAddress() + "/v1/auth/token/create";
308+
if (tokenRequest.role != null) url += "/" + tokenRequest.role;
309+
93310
// HTTP request to Vault
94311
final RestResponse restResponse = new Rest()//NOPMD
95-
.url(config.getAddress() + "/v1/auth/token/create")
312+
.url(url)
96313
.header("X-Vault-Token", config.getToken())
97314
.body(requestJson.getBytes("UTF-8"))
98315
.connectTimeoutSeconds(config.getOpenTimeout())

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,27 +93,47 @@ public LogicalResponse read(final String path) throws VaultException {
9393
*
9494
* <blockquote>
9595
* <pre>{@code
96-
* final Map<String, String> nameValuePairs = new HashMap<String, String>();
96+
* final Map<String, String> nameValuePairs = new HashMap<String, Object>();
9797
* nameValuePairs.put("value", "foo");
9898
* nameValuePairs.put("other_value", "bar");
9999
*
100100
* final LogicalResponse response = vault.logical().write("secret/hello", nameValuePairs);
101101
* }</pre>
102102
* </blockquote>
103103
*
104+
* <p>The values in these name-value pairs may be booleans, numerics, strings, or nested JSON objects. However,
105+
* be aware that this method does not recursively parse any nested structures. If you wish to write arbitrary
106+
* JSON objects to Vault... then you should parse them to JSON outside of this method, and pass them here as JSON
107+
* strings.</p>
108+
*
104109
* @param path The Vault key value to which to write (e.g. <code>secret/hello</code>)
105110
* @param nameValuePairs Secret name and value pairs to store under this Vault key (can be <code>null</code> for writing to keys that do not need or expect any fields to be specified)
106111
* @return The response information received from Vault
107112
* @throws VaultException If any errors occurs with the REST request, and the maximum number of retries is exceeded.
108113
*/
109-
public LogicalResponse write(final String path, final Map<String, String> nameValuePairs) throws VaultException {
114+
public LogicalResponse write(final String path, final Map<String, Object> nameValuePairs) throws VaultException {
110115
int retryCount = 0;
111116
while (true) {
112117
try {
113118
JsonObject requestJson = Json.object();
114119
if (nameValuePairs != null) {
115-
for (final Map.Entry<String, String> pair : nameValuePairs.entrySet()) {
116-
requestJson = requestJson.add(pair.getKey(), pair.getValue());
120+
for (final Map.Entry<String, Object> pair : nameValuePairs.entrySet()) {
121+
final Object value = pair.getValue();
122+
if (value == null) {
123+
requestJson = requestJson.add(pair.getKey(), (String) null);
124+
} else if (value instanceof Boolean) {
125+
requestJson = requestJson.add(pair.getKey(), (Boolean) pair.getValue());
126+
} else if (value instanceof Integer) {
127+
requestJson = requestJson.add(pair.getKey(), (Integer) pair.getValue());
128+
} else if (value instanceof Long) {
129+
requestJson = requestJson.add(pair.getKey(), (Long) pair.getValue());
130+
} else if (value instanceof Float) {
131+
requestJson = requestJson.add(pair.getKey(), (Float) pair.getValue());
132+
} else if (value instanceof Double) {
133+
requestJson = requestJson.add(pair.getKey(), (Double) pair.getValue());
134+
} else {
135+
requestJson = requestJson.add(pair.getKey(), pair.getValue().toString());
136+
}
117137
}
118138
}
119139

0 commit comments

Comments
 (0)