Provide transit backend support #1
This commit is contained in:
@@ -13,8 +13,6 @@
|
||||
<description>Spring Vault Core Components</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<url>http://projects.spring.io/spring-vault/</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
||||
@@ -59,6 +59,19 @@ public interface VaultOperations {
|
||||
*/
|
||||
VaultTokenOperations opsForToken();
|
||||
|
||||
/**
|
||||
* @return the operations interface to interact with the Vault transit backend.
|
||||
*/
|
||||
VaultTransitOperations opsForTransit();
|
||||
|
||||
/**
|
||||
* Returns {@link VaultTransitOperations} if the transit backend is mounted on a different path than {@code transit}.
|
||||
*
|
||||
* @param path the mount path
|
||||
* @return the operations interface to interact with the Vault transit backend.
|
||||
*/
|
||||
VaultTransitOperations opsForTransit(String path);
|
||||
|
||||
/**
|
||||
* Read from a secret backend. Reading data using this method is suitable for secret backends that do not require a
|
||||
* request body.
|
||||
@@ -102,7 +115,8 @@ public interface VaultOperations {
|
||||
void delete(String path);
|
||||
|
||||
/**
|
||||
* Executes a Vault {@link ClientCallback}. Allows to interact with Vault using {@link VaultClient} without requiring a session.
|
||||
* Executes a Vault {@link ClientCallback}. Allows to interact with Vault using {@link VaultClient} without requiring
|
||||
* a session.
|
||||
*
|
||||
* @param clientCallback the request.
|
||||
* @return the {@link ClientCallback} return value.
|
||||
|
||||
@@ -119,14 +119,24 @@ public class VaultTemplate implements InitializingBean, VaultOperations {
|
||||
Assert.notNull(sessionManager, "SessionManager must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultSysOperations opsForSys() {
|
||||
return new VaultSysTemplate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultTokenOperations opsForToken() {
|
||||
return new VaultTokenTemplate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultSysOperations opsForSys() {
|
||||
return new VaultSysTemplate(this);
|
||||
public VaultTransitOperations opsForTransit() {
|
||||
return opsForTransit("transit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultTransitOperations opsForTransit(String path) {
|
||||
return new VaultTransitTemplate(this, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.core;
|
||||
|
||||
import org.springframework.vault.support.VaultTransitKeyConfiguration;
|
||||
import org.springframework.vault.support.VaultTransitKey;
|
||||
import org.springframework.vault.support.VaultTransitKeyCreationRequest;
|
||||
import org.springframework.vault.support.VaultTransitRequest;
|
||||
|
||||
/**
|
||||
* Interface that specifies operations using the {@code transit} backend.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see <a href="https://www.vaultproject.io/docs/secrets/transit/index.html">Transit Secret Backend</a>
|
||||
*/
|
||||
public interface VaultTransitOperations {
|
||||
|
||||
/**
|
||||
* Creates a new named encryption key given a {@code name}.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
*/
|
||||
void createKey(String keyName);
|
||||
|
||||
/**
|
||||
* Creates a new named encryption key given a {@code name} and {@link VaultTransitKeyCreationRequest}. The key options
|
||||
* set here cannot be changed after key creation.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param createKeyRequest must not be {@literal null}.
|
||||
*/
|
||||
void createKey(String keyName, VaultTransitKeyCreationRequest createKeyRequest);
|
||||
|
||||
/**
|
||||
* Creates a new named encryption key given a {@code name}.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param keyConfiguration must not be {@literal null}.
|
||||
*/
|
||||
void configureKey(String keyName, VaultTransitKeyConfiguration keyConfiguration);
|
||||
|
||||
/**
|
||||
* Returns information about a named encryption key.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @return the {@link VaultTransitKey}.
|
||||
*/
|
||||
VaultTransitKey getKey(String keyName);
|
||||
|
||||
/**
|
||||
* Deletes a named encryption key. It will no longer be possible to decrypt any data encrypted with the named key.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
*/
|
||||
void deleteKey(String keyName);
|
||||
|
||||
/**
|
||||
* Rotates the version of the named key. After rotation, new plaintext requests will be encrypted with the new version
|
||||
* of the key. To upgrade ciphertext to be encrypted with the latest version of the key, use
|
||||
* {@link #rewrap(String, String)}.
|
||||
*
|
||||
* @param keyName
|
||||
* @see #rewrap(String, String)
|
||||
*/
|
||||
void rotate(String keyName);
|
||||
|
||||
/**
|
||||
* Encrypts the provided plaintext using the named key.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param plaintext must not be empty or {@literal null}.
|
||||
* @return cipher text.
|
||||
*/
|
||||
String encrypt(String keyName, String plaintext);
|
||||
|
||||
/**
|
||||
* Encrypts the provided plaintext using the named key.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param plaintext must not be empty or {@literal null}.
|
||||
* @param transitRequest may be {@literal null} if no request options provided.
|
||||
* @return cipher text.
|
||||
*/
|
||||
String encrypt(String keyName, byte[] plaintext, VaultTransitRequest transitRequest);
|
||||
|
||||
/**
|
||||
* Decrypts the provided plaintext using the named key.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param ciphertext must not be empty or {@literal null}.
|
||||
* @return plain text.
|
||||
*/
|
||||
String decrypt(String keyName, String ciphertext);
|
||||
|
||||
/**
|
||||
* Decrypts the provided plaintext using the named key.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param ciphertext must not be empty or {@literal null}.
|
||||
* @param transitRequest may be {@literal null} if no request options provided.
|
||||
* @return plain text.
|
||||
*/
|
||||
byte[] decrypt(String keyName, String ciphertext, VaultTransitRequest transitRequest);
|
||||
|
||||
/**
|
||||
* Rewrap the provided ciphertext using the latest version of the named key. Because this never returns plaintext, it
|
||||
* is possible to delegate this functionality to untrusted users or scripts.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param ciphertext must not be empty or {@literal null}.
|
||||
* @return cipher text.
|
||||
* @see #rotate(String)
|
||||
*/
|
||||
String rewrap(String keyName, String ciphertext);
|
||||
|
||||
/**
|
||||
* Rewrap the provided ciphertext using the latest version of the named key. Because this never returns plaintext, it
|
||||
* is possible to delegate this functionality to untrusted users or scripts.
|
||||
*
|
||||
* @param keyName must not be empty or {@literal null}.
|
||||
* @param ciphertext must not be empty or {@literal null}.
|
||||
* @param transitRequest may be {@literal null} if no request options provided.
|
||||
* @return cipher text.
|
||||
* @see #rotate(String)
|
||||
*/
|
||||
String rewrap(String keyName, String ciphertext, VaultTransitRequest transitRequest);
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.core;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.vault.support.VaultTransitKeyConfiguration;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.vault.support.VaultTransitKey;
|
||||
import org.springframework.vault.support.VaultTransitKeyCreationRequest;
|
||||
import org.springframework.vault.support.VaultTransitRequest;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultTransitOperations}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
private final VaultOperations vaultOperations;
|
||||
|
||||
private final String path;
|
||||
|
||||
public VaultTransitTemplate(VaultOperations vaultOperations, String path) {
|
||||
|
||||
Assert.notNull(vaultOperations, "VaultOperations must not be null");
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
this.vaultOperations = vaultOperations;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createKey(final String keyName) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
|
||||
vaultOperations.write(String.format("%s/keys/%s", path, keyName), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createKey(final String keyName, final VaultTransitKeyCreationRequest createKeyRequest) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.notNull(createKeyRequest, "VaultTransitKeyCreationRequest must not be empty");
|
||||
|
||||
vaultOperations.write(String.format("%s/keys/%s", path, keyName), createKeyRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureKey(final String keyName, final VaultTransitKeyConfiguration keyConfiguration) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.notNull(keyConfiguration, "VaultKeyConfiguration must not be empty");
|
||||
|
||||
vaultOperations.write(String.format("%s/keys/%s/config", path, keyName), keyConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultTransitKey getKey(final String keyName) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
|
||||
VaultResponseSupport<VaultTransitKey> result = vaultOperations.read(String.format("%s/keys/%s", path, keyName),
|
||||
VaultTransitKey.class);
|
||||
|
||||
if (result != null) {
|
||||
return result.getData();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteKey(String keyName) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
|
||||
vaultOperations.delete(String.format("%s/keys/%s", path, keyName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotate(String keyName) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
|
||||
vaultOperations.write(String.format("%s/keys/%s/rotate", path, keyName), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String keyName, String plaintext) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.notNull(plaintext, "Plain text must not be null");
|
||||
|
||||
Map<String, String> request = new LinkedHashMap<String, String>();
|
||||
|
||||
request.put("plaintext", Base64Utils.encodeToString(plaintext.getBytes()));
|
||||
|
||||
return (String) vaultOperations.write(String.format("%s/encrypt/%s", path, keyName), request).getData()
|
||||
.get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String keyName, byte[] plaintext, VaultTransitRequest transitRequest) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.notNull(plaintext, "Plain text must not be null");
|
||||
|
||||
Map<String, String> request = new LinkedHashMap<String, String>();
|
||||
|
||||
request.put("plaintext", Base64Utils.encodeToString(plaintext));
|
||||
|
||||
if (transitRequest != null) {
|
||||
applyTransitOptions(transitRequest, request);
|
||||
}
|
||||
|
||||
return (String) vaultOperations.write(String.format("%s/encrypt/%s", path, keyName), request).getData()
|
||||
.get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decrypt(String keyName, String ciphertext) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.hasText(keyName, "Cipher text must not be empty");
|
||||
|
||||
Map<String, String> request = new LinkedHashMap<String, String>();
|
||||
|
||||
request.put("ciphertext", ciphertext);
|
||||
|
||||
String plaintext = (String) vaultOperations.write(String.format("%s/decrypt/%s", path, keyName), request).getData()
|
||||
.get("plaintext");
|
||||
|
||||
return new String(Base64Utils.decodeFromString(plaintext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(String keyName, String ciphertext, VaultTransitRequest transitRequest) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.hasText(keyName, "Cipher text must not be empty");
|
||||
|
||||
Map<String, String> request = new LinkedHashMap<String, String>();
|
||||
|
||||
request.put("ciphertext", ciphertext);
|
||||
|
||||
if (transitRequest != null) {
|
||||
applyTransitOptions(transitRequest, request);
|
||||
}
|
||||
|
||||
String plaintext = (String) vaultOperations.write(String.format("%s/decrypt/%s", path, keyName), request).getData()
|
||||
.get("plaintext");
|
||||
|
||||
return Base64Utils.decodeFromString(plaintext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String rewrap(String keyName, String ciphertext) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.hasText(ciphertext, "Cipher text must not be empty");
|
||||
|
||||
Map<String, String> request = new LinkedHashMap<String, String>();
|
||||
request.put("ciphertext", ciphertext);
|
||||
|
||||
return (String) vaultOperations.write(String.format("%s/rewrap/%s", path, keyName), request).getData()
|
||||
.get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String rewrap(String keyName, String ciphertext, VaultTransitRequest transitRequest) {
|
||||
|
||||
Assert.hasText(keyName, "KeyName must not be empty");
|
||||
Assert.hasText(ciphertext, "Cipher text must not be empty");
|
||||
|
||||
Map<String, String> request = new LinkedHashMap<String, String>();
|
||||
|
||||
request.put("ciphertext", ciphertext);
|
||||
|
||||
if (transitRequest != null) {
|
||||
applyTransitOptions(transitRequest, request);
|
||||
}
|
||||
|
||||
return (String) vaultOperations.write(String.format("%s/rewrap/%s", path, keyName), request).getData()
|
||||
.get("ciphertext");
|
||||
}
|
||||
|
||||
private void applyTransitOptions(VaultTransitRequest transitRequest, Map<String, String> request) {
|
||||
|
||||
if (transitRequest.getContext() != null) {
|
||||
request.put("context", Base64Utils.encodeToString(transitRequest.getContext()));
|
||||
}
|
||||
|
||||
if (transitRequest.getNonce() != null) {
|
||||
request.put("nonce", Base64Utils.encodeToString(transitRequest.getNonce()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ package org.springframework.vault.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object to bind Vault HTTP Mount API requests/responses.
|
||||
*
|
||||
@@ -30,9 +32,20 @@ public class VaultMount {
|
||||
|
||||
private Map<String, Object> config;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultMount}.
|
||||
*/
|
||||
public VaultMount() {}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultMount} given a {@code type}.
|
||||
*
|
||||
* @param type must not be empty or {@literal null}.
|
||||
*/
|
||||
public VaultMount(String type) {
|
||||
|
||||
Assert.hasText(type, "Type must not be empty");
|
||||
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Value object to bind Vault HTTP Transit Key API responses.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultTransitKey {
|
||||
|
||||
@JsonProperty("cipher_mode") private String cipherMode;
|
||||
|
||||
@JsonProperty("deletion_allowed") private boolean deletionAllowed;
|
||||
|
||||
private boolean derived;
|
||||
|
||||
private Map<String, Long> keys;
|
||||
|
||||
@JsonProperty("latest_version") private boolean latestVersion;
|
||||
|
||||
@JsonProperty("min_decryption_version") private int minDecryptionVersion;
|
||||
|
||||
private String name;
|
||||
|
||||
public String getCipherMode() {
|
||||
return cipherMode;
|
||||
}
|
||||
|
||||
public void setCipherMode(String cipherMode) {
|
||||
this.cipherMode = cipherMode;
|
||||
}
|
||||
|
||||
public boolean isDeletionAllowed() {
|
||||
return deletionAllowed;
|
||||
}
|
||||
|
||||
public void setDeletionAllowed(boolean deletionAllowed) {
|
||||
this.deletionAllowed = deletionAllowed;
|
||||
}
|
||||
|
||||
public boolean isDerived() {
|
||||
return derived;
|
||||
}
|
||||
|
||||
public void setDerived(boolean derived) {
|
||||
this.derived = derived;
|
||||
}
|
||||
|
||||
public Map<String, Long> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public void setKeys(Map<String, Long> keys) {
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
public boolean isLatestVersion() {
|
||||
return latestVersion;
|
||||
}
|
||||
|
||||
public void setLatestVersion(boolean latestVersion) {
|
||||
this.latestVersion = latestVersion;
|
||||
}
|
||||
|
||||
public int getMinDecryptionVersion() {
|
||||
return minDecryptionVersion;
|
||||
}
|
||||
|
||||
public void setMinDecryptionVersion(int minDecryptionVersion) {
|
||||
this.minDecryptionVersion = minDecryptionVersion;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.support;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Value object to bind Vault HTTP Transit Key Config API requests.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultTransitKeyConfiguration {
|
||||
|
||||
@JsonProperty("deletion_allowed") private Boolean deletionAllowed;
|
||||
|
||||
@JsonProperty("latest_version") private Integer latestVersion;
|
||||
|
||||
public VaultTransitKeyConfiguration() {
|
||||
}
|
||||
|
||||
public VaultTransitKeyConfiguration(Boolean deletionAllowed, Integer latestVersion) {
|
||||
this.deletionAllowed = deletionAllowed;
|
||||
this.latestVersion = latestVersion;
|
||||
}
|
||||
|
||||
public Boolean getDeletionAllowed() {
|
||||
return deletionAllowed;
|
||||
}
|
||||
|
||||
public void setDeletionAllowed(Boolean deletionAllowed) {
|
||||
this.deletionAllowed = deletionAllowed;
|
||||
}
|
||||
|
||||
public Integer getLatestVersion() {
|
||||
return latestVersion;
|
||||
}
|
||||
|
||||
public void setLatestVersion(Integer latestVersion) {
|
||||
this.latestVersion = latestVersion;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.support;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Transit backend key creation request options.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultTransitKeyCreationRequest {
|
||||
|
||||
private Boolean derived;
|
||||
|
||||
@JsonProperty("convergent_encryption") private Boolean convergentEncryption;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultTransitKeyCreationRequest}.
|
||||
*/
|
||||
public VaultTransitKeyCreationRequest() {}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultTransitKeyCreationRequest} and sets {@code derived} and {@code convergentEncryption}
|
||||
* properties.
|
||||
*
|
||||
* @param derived
|
||||
* @param convergentEncryption
|
||||
*/
|
||||
public VaultTransitKeyCreationRequest(boolean derived, boolean convergentEncryption) {
|
||||
this.derived = derived;
|
||||
this.convergentEncryption = convergentEncryption;
|
||||
}
|
||||
|
||||
public Boolean getDerived() {
|
||||
return derived;
|
||||
}
|
||||
|
||||
public void setDerived(Boolean derived) {
|
||||
this.derived = derived;
|
||||
}
|
||||
|
||||
public Boolean getConvergentEncryption() {
|
||||
return convergentEncryption;
|
||||
}
|
||||
|
||||
public void setConvergentEncryption(Boolean convergentEncryption) {
|
||||
this.convergentEncryption = convergentEncryption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.support;
|
||||
|
||||
/**
|
||||
* Transit backend encryption/decryption/rewrapping request options.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultTransitRequest {
|
||||
|
||||
private byte[] context;
|
||||
|
||||
private byte[] nonce;
|
||||
|
||||
public byte[] getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void setContext(byte[] context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public byte[] getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public void setNonce(byte[] nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.vault.authentication.ClientAuthentication;
|
||||
import org.springframework.vault.authentication.DefaultSessionManager;
|
||||
import org.springframework.vault.authentication.TokenAuthentication;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.config.AbstractVaultConfiguration;
|
||||
@@ -48,26 +46,3 @@ class VaultIntegrationTestConfiguration extends AbstractVaultConfiguration {
|
||||
return Settings.createSslConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
class test {
|
||||
|
||||
@Bean
|
||||
public VaultTemplate vaultTemplate() {
|
||||
|
||||
VaultTemplate vaultTemplate = new VaultTemplate();
|
||||
vaultTemplate.setSessionManager(sessionManager());
|
||||
vaultTemplate.setVaultClientFactory(clientFactory());
|
||||
|
||||
return vaultTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultVaultClientFactory clientFactory() {
|
||||
return new DefaultVaultClientFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultSessionManager sessionManager() {
|
||||
return new DefaultSessionManager(new TokenAuthentication("…"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.support.VaultTransitKeyConfiguration;
|
||||
import org.springframework.vault.support.VaultMount;
|
||||
import org.springframework.vault.support.VaultTransitKey;
|
||||
import org.springframework.vault.support.VaultTransitKeyCreationRequest;
|
||||
import org.springframework.vault.support.VaultTransitRequest;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultTransitTemplate} through {@link VaultTransitOperations}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = VaultIntegrationTestConfiguration.class)
|
||||
public class VaultTransitTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
|
||||
@Autowired private VaultOperations vaultOperations;
|
||||
private VaultTransitOperations transitOperations;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
transitOperations = vaultOperations.opsForTransit();
|
||||
|
||||
if (!vaultOperations.opsForSys().getMounts().containsKey("transit/")) {
|
||||
vaultOperations.opsForSys().mount("transit", new VaultMount("transit"));
|
||||
}
|
||||
|
||||
try {
|
||||
transitOperations.configureKey("mykey", new VaultTransitKeyConfiguration(true, null));
|
||||
} catch (Exception e) {}
|
||||
|
||||
try {
|
||||
transitOperations.deleteKey("mykey");
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createKeyShouldCreateKey() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey");
|
||||
|
||||
VaultTransitKey mykey = transitOperations.getKey("mykey");
|
||||
|
||||
assertThat(mykey.getCipherMode()).isEqualTo("aes-gcm");
|
||||
assertThat(mykey.getName()).isEqualTo("mykey");
|
||||
assertThat(mykey.isDeletionAllowed()).isFalse();
|
||||
assertThat(mykey.isDerived()).isFalse();
|
||||
assertThat(mykey.getMinDecryptionVersion()).isEqualTo(1);
|
||||
assertThat(mykey.isLatestVersion()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createKeyShouldCreateKeyWithOptions() throws Exception {
|
||||
|
||||
VaultTransitKeyCreationRequest request = new VaultTransitKeyCreationRequest();
|
||||
request.setConvergentEncryption(true);
|
||||
request.setDerived(true);
|
||||
|
||||
transitOperations.createKey("mykey", request);
|
||||
|
||||
VaultTransitKey mykey = transitOperations.getKey("mykey");
|
||||
|
||||
assertThat(mykey.getCipherMode()).isEqualTo("aes-gcm");
|
||||
assertThat(mykey.getName()).isEqualTo("mykey");
|
||||
assertThat(mykey.isDeletionAllowed()).isFalse();
|
||||
assertThat(mykey.isDerived()).isTrue();
|
||||
assertThat(mykey.getMinDecryptionVersion()).isEqualTo(1);
|
||||
assertThat(mykey.isLatestVersion()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getKeyShouldReturnNullIfKeyNotExists() throws Exception {
|
||||
|
||||
VaultTransitKey key = transitOperations.getKey("hello-world");
|
||||
assertThat(key).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteKeyShouldFailIfKeyNotExists() throws Exception {
|
||||
|
||||
try {
|
||||
transitOperations.deleteKey("hello-world");
|
||||
fail("Missing VaultException");
|
||||
} catch (VaultException e) {
|
||||
assertThat(e).hasMessageContaining("could not delete");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteKeyShouldDeleteKey() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey");
|
||||
transitOperations.configureKey("mykey", new VaultTransitKeyConfiguration(true, null));
|
||||
transitOperations.deleteKey("mykey");
|
||||
|
||||
assertThat(transitOperations.getKey("mykey")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encryptShouldCreateCiphertext() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey");
|
||||
|
||||
String ciphertext = transitOperations.encrypt("mykey", "hello-world");
|
||||
assertThat(ciphertext).startsWith("vault:v");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encryptShouldCreateCiphertextWithNonceAndContext() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey", new VaultTransitKeyCreationRequest(true, true));
|
||||
|
||||
VaultTransitRequest transitRequest = new VaultTransitRequest();
|
||||
transitRequest.setContext("blubb".getBytes());
|
||||
transitRequest.setNonce("123456789012".getBytes());
|
||||
|
||||
String ciphertext = transitOperations.encrypt("mykey", "hello-world".getBytes(), transitRequest);
|
||||
assertThat(ciphertext).startsWith("vault:v1:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decryptShouldCreatePlaintext() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey");
|
||||
|
||||
String ciphertext = transitOperations.encrypt("mykey", "hello-world");
|
||||
String plaintext = transitOperations.decrypt("mykey", ciphertext);
|
||||
|
||||
assertThat(plaintext).isEqualTo("hello-world");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decryptShouldCreatePlaintextWithNonceAndContext() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey", new VaultTransitKeyCreationRequest(true, true));
|
||||
|
||||
VaultTransitRequest transitRequest = new VaultTransitRequest();
|
||||
transitRequest.setContext("blubb".getBytes());
|
||||
transitRequest.setNonce("123456789012".getBytes());
|
||||
|
||||
String ciphertext = transitOperations.encrypt("mykey", "hello-world".getBytes(), transitRequest);
|
||||
|
||||
byte[] plaintext = transitOperations.decrypt("mykey", ciphertext, transitRequest);
|
||||
assertThat(new String(plaintext)).isEqualTo("hello-world");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encryptAndRewrapShouldCreateCiphertext() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey");
|
||||
|
||||
String ciphertext = transitOperations.encrypt("mykey", "hello-world");
|
||||
transitOperations.rotate("mykey");
|
||||
|
||||
String rewrapped = transitOperations.rewrap("mykey", ciphertext);
|
||||
|
||||
assertThat(rewrapped).startsWith("vault:v2:");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encryptAndRewrapShouldCreateCiphertextWithNonceAndContext() throws Exception {
|
||||
|
||||
transitOperations.createKey("mykey", new VaultTransitKeyCreationRequest(true, true));
|
||||
|
||||
VaultTransitRequest transitRequest = new VaultTransitRequest();
|
||||
transitRequest.setContext("blubb".getBytes());
|
||||
transitRequest.setNonce("123456789012".getBytes());
|
||||
|
||||
String ciphertext = transitOperations.encrypt("mykey", "hello-world".getBytes(), transitRequest);
|
||||
transitOperations.rotate("mykey");
|
||||
|
||||
String rewrapped = transitOperations.rewrap("mykey", ciphertext, transitRequest);
|
||||
assertThat(rewrapped).startsWith("vault:v2");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user