forked from ValFadeev/rundeck-vault-plugin
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
1,119 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
src/main/java/io/github/valfadeev/rundeck/plugin/vault/KeyObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package io.github.valfadeev.rundeck.plugin.vault; | ||
|
||
import com.bettercloud.vault.api.Logical; | ||
import com.dtolabs.rundeck.core.storage.ResourceMeta; | ||
import org.rundeck.storage.api.Path; | ||
import org.rundeck.storage.impl.ResourceBase; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.util.Map; | ||
|
||
public abstract class KeyObject { | ||
|
||
protected boolean rundeckObject; | ||
protected boolean multiplesKeys; | ||
protected Map<String, String> payload; | ||
protected Map<String, Object> keys; | ||
protected Path path; | ||
|
||
protected boolean error; | ||
protected String errorMessage; | ||
|
||
abstract Map<String, Object> saveResource(ResourceMeta content, String event, ByteArrayOutputStream baoStream); | ||
abstract ResourceBase loadResource(); | ||
abstract boolean delete(Logical vault,String vaultPrefix); | ||
|
||
//empty object or null object | ||
public KeyObject(Path path) { | ||
this.path=path; | ||
} | ||
|
||
public boolean isRundeckObject() { | ||
return rundeckObject; | ||
} | ||
|
||
public void setRundeckObject(final boolean rundeckObject) { | ||
this.rundeckObject = rundeckObject; | ||
} | ||
|
||
public boolean isMultiplesKeys() { | ||
return multiplesKeys; | ||
} | ||
|
||
public void setMultiplesKeys(final boolean multiplesKeys) { | ||
this.multiplesKeys = multiplesKeys; | ||
} | ||
|
||
public Map<String, String> getPayload() { | ||
return payload; | ||
} | ||
|
||
public void setPayload(final Map<String, String> payload) { | ||
this.payload = payload; | ||
} | ||
|
||
public Map<String, Object> getKeys() { | ||
return keys; | ||
} | ||
|
||
public void setKeys(final Map<String, Object> keys) { | ||
this.keys = keys; | ||
} | ||
|
||
public Path getPath() { | ||
return path; | ||
} | ||
|
||
public void setPath(final Path path) { | ||
this.path = path; | ||
} | ||
|
||
public String getErrorMessage() { | ||
return errorMessage; | ||
} | ||
|
||
public void setErrorMessage(final String errorMessage) { | ||
this.errorMessage = errorMessage; | ||
} | ||
|
||
public boolean isError() { | ||
return error; | ||
} | ||
|
||
public void setError(final boolean error) { | ||
this.error = error; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "KeyObject{" + | ||
"rundeckObject=" + rundeckObject + | ||
", multiplesKeys=" + multiplesKeys + | ||
", payload=" + payload + | ||
", keys=" + keys + | ||
", path=" + path + | ||
", error=" + error + | ||
", errorMessage='" + errorMessage + '\'' + | ||
'}'; | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
src/main/java/io/github/valfadeev/rundeck/plugin/vault/KeyObjectBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package io.github.valfadeev.rundeck.plugin.vault; | ||
|
||
import com.bettercloud.vault.VaultException; | ||
import com.bettercloud.vault.api.Logical; | ||
import com.bettercloud.vault.response.LogicalResponse; | ||
import org.rundeck.storage.api.Path; | ||
import org.rundeck.storage.api.PathUtil; | ||
|
||
public class KeyObjectBuilder { | ||
|
||
Path path; | ||
Logical vault; | ||
String vaultPrefix; | ||
|
||
static KeyObjectBuilder builder() { | ||
return new KeyObjectBuilder(); | ||
} | ||
|
||
KeyObjectBuilder path(Path path){ | ||
this.path = path; | ||
return this; | ||
} | ||
|
||
KeyObjectBuilder vault(Logical vault){ | ||
this.vault = vault; | ||
return this; | ||
} | ||
|
||
KeyObjectBuilder vaultPrefix(String vaultPrefix){ | ||
this.vaultPrefix = vaultPrefix; | ||
return this; | ||
} | ||
|
||
private String getVaultPath(String rawPath) { | ||
return String.format("secret/%s/%s", vaultPrefix, rawPath); | ||
} | ||
|
||
KeyObject build(){ | ||
LogicalResponse response; | ||
KeyObject object; | ||
try { | ||
response = vault.read(getVaultPath(path.getPath())); | ||
String data = response.getData().get(VaultStoragePlugin.VAULT_STORAGE_KEY); | ||
|
||
if(data !=null) { | ||
object = new RundeckKey(response,path); | ||
}else{ | ||
object = new VaultKey(response,path); | ||
} | ||
|
||
} catch (VaultException e) { | ||
object = new RundeckKey(path); | ||
object.setErrorMessage(e.getMessage()); | ||
object.setError(true); | ||
} | ||
|
||
//check if parent path exists (vault entry with multiples keys) | ||
//multiples keys inside a secret will be reading on Rundeck as different keys inside a folder | ||
if(object.isError()) { | ||
KeyObject parentObject=getVaultParentObject(path); | ||
|
||
if(parentObject!=null) { | ||
object = new VaultKey(path, parentObject); | ||
Path parentPath = PathUtil.parentPath(path); | ||
String key = PathUtil.removePrefix(parentPath.toString(), path.toString()); | ||
|
||
object.setError(false); | ||
object.setErrorMessage(null); | ||
object.setMultiplesKeys(true); | ||
|
||
if (parentObject.getKeys().containsKey(key)) { | ||
object.getKeys().put(key, parentObject.getKeys().get(key)); | ||
} | ||
} | ||
} | ||
|
||
return object; | ||
} | ||
|
||
public KeyObject getVaultParentObject(Path path){ | ||
KeyObject parentObject=null; | ||
LogicalResponse response; | ||
|
||
Path parentPath = PathUtil.parentPath(path); | ||
try { | ||
response = vault.read(getVaultPath(parentPath.getPath())); | ||
parentObject=new VaultKey(response, parentPath); | ||
} catch (VaultException e) { | ||
|
||
} | ||
|
||
return parentObject; | ||
} | ||
} |
121 changes: 121 additions & 0 deletions
121
src/main/java/io/github/valfadeev/rundeck/plugin/vault/RundeckKey.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package io.github.valfadeev.rundeck.plugin.vault; | ||
|
||
import com.bettercloud.vault.VaultException; | ||
import com.bettercloud.vault.api.Logical; | ||
import com.bettercloud.vault.response.LogicalResponse; | ||
import com.dtolabs.rundeck.core.storage.ResourceMeta; | ||
import com.dtolabs.rundeck.core.storage.ResourceMetaBuilder; | ||
import com.dtolabs.rundeck.core.storage.StorageUtil; | ||
import org.rundeck.storage.api.Path; | ||
import org.rundeck.storage.api.Resource; | ||
import org.rundeck.storage.api.StorageException; | ||
import org.rundeck.storage.impl.ResourceBase; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.UnsupportedEncodingException; | ||
import java.text.DateFormat; | ||
import java.text.ParseException; | ||
import java.text.SimpleDateFormat; | ||
import java.util.HashMap; | ||
import java.util.Locale; | ||
import java.util.Map; | ||
|
||
public class RundeckKey extends KeyObject { | ||
|
||
public RundeckKey(LogicalResponse response, Path path) { | ||
super(path); | ||
this.payload = response.getData(); | ||
this.path = path; | ||
this.rundeckObject=true; | ||
this.multiplesKeys=false; | ||
} | ||
|
||
public RundeckKey(final Path path) { | ||
super(path); | ||
} | ||
|
||
public Map<String, Object> saveResource(ResourceMeta content, String event, ByteArrayOutputStream baoStream){ | ||
|
||
Map<String, Object> payload = new HashMap<>(); | ||
|
||
Map<String, String> meta = content.getMeta(); | ||
|
||
for (String k : meta.keySet()) { | ||
payload.put(k, meta.get(k)); | ||
} | ||
|
||
if (event.equals("update")) { | ||
DateFormat df = new SimpleDateFormat(StorageUtil.ISO_8601_FORMAT, Locale.ENGLISH); | ||
Resource<ResourceMeta> existing = this.loadResource(); | ||
payload.put( | ||
StorageUtil.RES_META_RUNDECK_CONTENT_CREATION_TIME, | ||
df.format(existing.getContents().getCreationTime()) | ||
); | ||
} | ||
|
||
try { | ||
String data = baoStream.toString("UTF-8"); | ||
payload.put(VaultStoragePlugin.VAULT_STORAGE_KEY, data); | ||
} catch (UnsupportedEncodingException e) { | ||
throw new StorageException( | ||
String.format( | ||
"Encountered unsupported encoding error: %s", | ||
e.getMessage() | ||
), | ||
StorageException.Event.valueOf(event.toUpperCase()), | ||
this.getPath() | ||
); | ||
} | ||
|
||
return payload; | ||
} | ||
|
||
ResourceBase loadResource(){ | ||
Map<String, String> payload = this.getPayload(); | ||
String data = payload.get(VaultStoragePlugin.VAULT_STORAGE_KEY); | ||
|
||
ResourceMetaBuilder builder = new ResourceMetaBuilder(); | ||
builder.setContentLength(Long.parseLong(payload.get(StorageUtil.RES_META_RUNDECK_CONTENT_LENGTH))); | ||
builder.setContentType(payload.get(StorageUtil.RES_META_RUNDECK_CONTENT_TYPE)); | ||
|
||
DateFormat df = new SimpleDateFormat(StorageUtil.ISO_8601_FORMAT, Locale.ENGLISH); | ||
try { | ||
builder.setCreationTime(df.parse(payload.get(StorageUtil.RES_META_RUNDECK_CONTENT_CREATION_TIME))); | ||
builder.setModificationTime(df.parse(payload.get(StorageUtil.RES_META_RUNDECK_CONTENT_MODIFY_TIME))); | ||
} catch (ParseException e) { | ||
} | ||
|
||
String type = payload.get(StorageUtil.RES_META_RUNDECK_CONTENT_TYPE); | ||
if (type.equals(VaultStoragePlugin.PRIVATE_KEY_MIME_TYPE)) { | ||
builder.setMeta(VaultStoragePlugin.RUNDECK_CONTENT_MASK, "content"); | ||
builder.setMeta(VaultStoragePlugin.RUNDECK_KEY_TYPE, "private"); | ||
} | ||
else if (type.equals(VaultStoragePlugin.PUBLIC_KEY_MIME_TYPE)) { | ||
builder.setMeta(VaultStoragePlugin.RUNDECK_KEY_TYPE, "public"); | ||
} | ||
else if (type.equals(VaultStoragePlugin.PASSWORD_MIME_TYPE)) { | ||
builder.setMeta(VaultStoragePlugin.RUNDECK_CONTENT_MASK, "content"); | ||
builder.setMeta(VaultStoragePlugin.RUNDECK_DATA_TYPE, "password"); | ||
} | ||
|
||
ByteArrayInputStream baiStream = new ByteArrayInputStream(data.getBytes()); | ||
return new ResourceBase<>( | ||
this.getPath(), | ||
StorageUtil.withStream(baiStream, builder.getResourceMeta()), | ||
false | ||
); | ||
} | ||
|
||
@Override | ||
boolean delete(final Logical vault,String vaultPrefix) { | ||
|
||
try { | ||
vault.delete(VaultStoragePlugin.getVaultPath(path.getPath(),vaultPrefix)); | ||
return true; | ||
} catch (VaultException e) { | ||
return false; | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.