Implement writing of KV v2 secret data (#16)

This commit is contained in:
2019-03-22 14:27:30 +01:00
parent e4cf8a1dde
commit ab33325b8e
5 changed files with 257 additions and 14 deletions

View File

@ -334,7 +334,7 @@ public class HTTPVaultConnector implements VaultConnector {
payload.put("value", policy);
payload.put("display_name", displayName);
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(PATH_AUTH_APPID + "map/app-id/" + appID, payload, token);
return true;
@ -347,7 +347,7 @@ public class HTTPVaultConnector implements VaultConnector {
Map<String, String> payload = new HashMap<>();
payload.put("value", appID);
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(PATH_AUTH_APPID + "map/user-id/" + userID, payload, token);
return true;
@ -357,7 +357,7 @@ public class HTTPVaultConnector implements VaultConnector {
public final boolean createAppRole(final AppRole role) throws VaultConnectorException {
requireAuth();
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(String.format(PATH_AUTH_APPROLE_ROLE, role.getName(), ""), role, token);
/* Set custom ID if provided */
@ -375,7 +375,7 @@ public class HTTPVaultConnector implements VaultConnector {
public final boolean deleteAppRole(final String roleName) throws VaultConnectorException {
requireAuth();
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.deleteWithoutResponse(String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""), token);
return true;
@ -400,7 +400,7 @@ public class HTTPVaultConnector implements VaultConnector {
Map<String, String> payload = new HashMap<>();
payload.put("role_id", roleID);
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"), payload, token);
return true;
@ -446,7 +446,7 @@ public class HTTPVaultConnector implements VaultConnector {
throws VaultConnectorException {
requireAuth();
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
@ -504,6 +504,28 @@ public class HTTPVaultConnector implements VaultConnector {
return request.get(mount + PATH_METADATA + key, new HashMap<>(), token, MetadataResponse.class);
}
@Override
public final SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data, final Integer cas) throws VaultConnectorException {
requireAuth();
if (key == null || key.isEmpty()) {
throw new InvalidRequestException("Secret path must not be empty.");
}
// Add CAS value to options map if present.
Map<String, Object> options = new HashMap<>();
if (cas != null) {
options.put("cas", cas);
}
Map<String, Object> payload = new HashMap<>();
payload.put("data", data);
payload.put("options", options);
/* Issue request and parse metadata response */
return request.post(mount + PATH_DATA + key, payload, token, SecretVersionResponse.class);
}
@Override
public final List<String> list(final String path) throws VaultConnectorException {
requireAuth();
@ -532,7 +554,7 @@ public class HTTPVaultConnector implements VaultConnector {
payload = payloadMap;
}
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(key, payload, token);
}
@ -540,7 +562,7 @@ public class HTTPVaultConnector implements VaultConnector {
public final void delete(final String key) throws VaultConnectorException {
requireAuth();
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.deleteWithoutResponse(key, token);
}
@ -586,7 +608,7 @@ public class HTTPVaultConnector implements VaultConnector {
Map<String, Object> payload = new HashMap<>();
payload.put("versions", versions);
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(mount + pathPart + key, payload, token);
}
@ -594,7 +616,7 @@ public class HTTPVaultConnector implements VaultConnector {
public final void revoke(final String leaseID) throws VaultConnectorException {
requireAuth();
/* Issue request anx expect code 204 with empty response */
/* Issue request and expect code 204 with empty response */
request.putWithoutResponse(PATH_REVOKE + leaseID, new HashMap<>(), token);
}

View File

@ -435,6 +435,49 @@ public interface VaultConnector extends AutoCloseable, Serializable {
return readSecretVersion(mount, key, null);
}
/**
* Write secret to Vault.
* Prefix "secret/" is automatically added to path. Only available for KV v2 secrets.
*
* @param key Secret identifier.
* @param data Secret content. Value must be be JSON serializable.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeSecretData(final String key, final Map<String, Object> data) throws VaultConnectorException {
return writeSecretData(PATH_SECRET, key, data, null);
}
/**
* Write secret to Vault.
* Prefix "secret/" is automatically added to path. Only available for KV v2 secrets.
*
* @param mount Secret store mountpoint (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data) throws VaultConnectorException {
return writeSecretData(mount, key, data, null);
}
/**
* Write secret to Vault.
* Prefix "secret/" is automatically added to path. Only available for KV v2 secrets.
*
* @param mount Secret store mountpoint (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @param cas Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data, final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
* Prefix "secret/data" is automatically added to key. Only available for KV v2 secrets.
@ -456,7 +499,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @param mount Secret store mountpoint (without leading or trailing slash).
* @param key Secret identifier
* @param version Version to read. If {@code null} or zero, the latest version will be returned.
* @return Secret response
* @return Secret responsef
* @throws VaultConnectorException on error
* @since 0.8
*/

View File

@ -0,0 +1,56 @@
/*
* Copyright 2016-2018 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.IOException;
import java.util.Map;
/**
* Vault response for a single secret version metatada, i.e. after update (KV v2).
*
* @author Stefan Kalscheuer
* @since 0.8
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretVersionResponse extends VaultDataResponse {
private VersionMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
this.metadata = mapper.readValue(mapper.writeValueAsString(data), VersionMetadata.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* Get the actual metadata.
*
* @return Metadata.
*/
public VersionMetadata getMetadata() {
return metadata;
}
}